Bladeren bron

Version 4.84

Threema 3 jaren geleden
bovenliggende
commit
86df527cde
100 gewijzigde bestanden met toevoegingen van 3908 en 2727 verwijderingen
  1. 5 3
      app/build.gradle
  2. 1 1
      app/src/androidTest/java/ch/threema/app/backuprestore/csv/BackupServiceTest.java
  3. 12 11
      app/src/androidTest/java/ch/threema/app/voip/VoipStatusMessageTest.java
  4. 5 8
      app/src/main/AndroidManifest.xml
  5. 31 27
      app/src/main/java/ch/threema/app/ThreemaApplication.java
  6. 1 1
      app/src/main/java/ch/threema/app/activities/ContactDetailActivity.java
  7. 4 4
      app/src/main/java/ch/threema/app/activities/EnterSerialActivity.java
  8. 5 0
      app/src/main/java/ch/threema/app/activities/GroupAddActivity.java
  9. 2 2
      app/src/main/java/ch/threema/app/activities/HomeActivity.java
  10. 1 1
      app/src/main/java/ch/threema/app/activities/PinLockActivity.java
  11. 1 1
      app/src/main/java/ch/threema/app/activities/RecipientListBaseActivity.java
  12. 25 22
      app/src/main/java/ch/threema/app/activities/SendMediaActivity.java
  13. 108 80
      app/src/main/java/ch/threema/app/activities/wizard/WizardBaseActivity.java
  14. 4 0
      app/src/main/java/ch/threema/app/adapters/ComposeMessageAdapter.java
  15. 4 3
      app/src/main/java/ch/threema/app/adapters/ContactListAdapter.java
  16. 4 3
      app/src/main/java/ch/threema/app/adapters/decorators/AdapterDecorator.java
  17. 13 20
      app/src/main/java/ch/threema/app/adapters/decorators/AudioChatAdapterDecorator.java
  18. 3 2
      app/src/main/java/ch/threema/app/adapters/decorators/FileChatAdapterDecorator.java
  19. 1 0
      app/src/main/java/ch/threema/app/archive/ArchiveActivity.java
  20. 0 8
      app/src/main/java/ch/threema/app/backuprestore/csv/BackupRestoreDataServiceImpl.java
  21. 5 4
      app/src/main/java/ch/threema/app/backuprestore/csv/RestoreService.java
  22. 132 173
      app/src/main/java/ch/threema/app/camera/VideoEditView.java
  23. 3 2
      app/src/main/java/ch/threema/app/dialogs/WizardDialog.java
  24. 25 16
      app/src/main/java/ch/threema/app/fragments/ComposeMessageFragment.java
  25. 6 0
      app/src/main/java/ch/threema/app/fragments/ContactsSectionFragment.java
  26. 38 30
      app/src/main/java/ch/threema/app/fragments/MessageSectionFragment.java
  27. 5 5
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment1.java
  28. 2 2
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment2.java
  29. 2 2
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment3.java
  30. 161 60
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment4.java
  31. 0 224
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment5.java
  32. 3 3
      app/src/main/java/ch/threema/app/managers/ServiceManager.java
  33. 11 0
      app/src/main/java/ch/threema/app/messagereceiver/ContactMessageReceiver.java
  34. 8 0
      app/src/main/java/ch/threema/app/preference/SettingsCallsFragment.kt
  35. 12 10
      app/src/main/java/ch/threema/app/preference/SettingsDeveloperFragment.java
  36. 20 1
      app/src/main/java/ch/threema/app/services/AppRestrictionService.java
  37. 4 8
      app/src/main/java/ch/threema/app/services/ConversationServiceImpl.java
  38. 12 11
      app/src/main/java/ch/threema/app/services/FileServiceImpl.java
  39. 39 37
      app/src/main/java/ch/threema/app/services/MessageServiceImpl.java
  40. 10 0
      app/src/main/java/ch/threema/app/services/ServerAddressProviderServiceImpl.java
  41. 6 6
      app/src/main/java/ch/threema/app/services/messageplayer/AudioMessagePlayer.java
  42. 19 0
      app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeConfigureActivity.java
  43. 7 1
      app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeService.java
  44. 22 19
      app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeServiceImpl.java
  45. 303 0
      app/src/main/java/ch/threema/app/ui/AudioProgressBarView.kt
  46. 178 0
      app/src/main/java/ch/threema/app/ui/AudioWaveformGeneratorTask.kt
  47. 10 6
      app/src/main/java/ch/threema/app/ui/AvatarEditView.java
  48. 7 0
      app/src/main/java/ch/threema/app/ui/MediaItem.java
  49. 20 5
      app/src/main/java/ch/threema/app/ui/ThreemaEditText.java
  50. 2 2
      app/src/main/java/ch/threema/app/ui/listitemholder/ComposeMessageHolder.java
  51. 37 16
      app/src/main/java/ch/threema/app/utils/ConfigUtils.java
  52. 93 0
      app/src/main/java/ch/threema/app/utils/GzipOutputStream.java
  53. 13 3
      app/src/main/java/ch/threema/app/utils/LocaleUtil.java
  54. 11 6
      app/src/main/java/ch/threema/app/utils/QuoteUtil.java
  55. 12 4
      app/src/main/java/ch/threema/app/utils/StringConversionUtil.java
  56. 39 0
      app/src/main/java/ch/threema/app/utils/TestUtil.java
  57. 146 0
      app/src/main/java/ch/threema/app/video/VideoTimelineThumbnailTask.kt
  58. 24 1
      app/src/main/java/ch/threema/app/video/transcoder/MediaComponent.java
  59. 10 44
      app/src/main/java/ch/threema/app/video/transcoder/VideoTranscoder.java
  60. 98 0
      app/src/main/java/ch/threema/app/video/transcoder/VideoTranscoderUtil.java
  61. 8 6
      app/src/main/java/ch/threema/app/voicemessage/VoiceRecorderActivity.java
  62. 9 1
      app/src/main/java/ch/threema/app/voip/activities/CallActivity.java
  63. 12 4
      app/src/main/java/ch/threema/app/voip/listeners/VoipCallEventListener.java
  64. 2 1
      app/src/main/java/ch/threema/app/voip/services/VoipCallService.java
  65. 86 7
      app/src/main/java/ch/threema/app/voip/services/VoipStateService.java
  66. 14 2
      app/src/main/java/ch/threema/app/webclient/activities/SessionsActivity.java
  67. 9 9
      app/src/main/java/ch/threema/app/webclient/services/instance/message/updater/VoipStatusUpdateHandler.java
  68. 43 0
      app/src/main/java/ch/threema/storage/factories/MessageModelFactory.java
  69. 3 3
      app/src/main/java/ch/threema/storage/models/MessageType.java
  70. 1 0
      app/src/main/java/ch/threema/storage/models/data/media/AudioDataModel.java
  71. 1 0
      app/src/main/java/ch/threema/storage/models/data/media/ImageDataModel.java
  72. 3 1
      app/src/main/java/ch/threema/storage/models/data/media/VideoDataModel.java
  73. 2 2
      app/src/main/java/ch/threema/storage/models/data/status/StatusDataModel.java
  74. 41 8
      app/src/main/java/ch/threema/storage/models/data/status/VoipStatusDataModel.java
  75. 27 0
      app/src/main/res/drawable-v24/ic_launcher_monochrome.xml
  76. 3 2
      app/src/main/res/drawable/ic_chevron_down_slightly_bigger.xml
  77. 40 0
      app/src/main/res/drawable/seekbar_thumb_audio.xml
  78. 38 0
      app/src/main/res/drawable/seekbar_thumb_audio_pressed.xml
  79. 1 1
      app/src/main/res/layout/activity_edit_send_contact.xml
  80. 1 1
      app/src/main/res/layout/activity_media_attach.xml
  81. 14 6
      app/src/main/res/layout/conversation_list_item_audio.xml
  82. 312 24
      app/src/main/res/layout/fragment_wizard4.xml
  83. 0 327
      app/src/main/res/layout/fragment_wizard5.xml
  84. 2 1
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  85. 16 2
      app/src/main/res/values-be-rBY/strings.xml
  86. 1 1
      app/src/main/res/values-be-rBY/voicemessage_strings.xml
  87. 1 1
      app/src/main/res/values-be-rBY/voip_strings.xml
  88. 1 1
      app/src/main/res/values-be-rBY/webclient_strings.xml
  89. 5 6
      app/src/main/res/values-ca/strings.xml
  90. 12 3
      app/src/main/res/values-cs/strings.xml
  91. 9 2
      app/src/main/res/values-de/strings.xml
  92. 8 1
      app/src/main/res/values-es/strings.xml
  93. 11 3
      app/src/main/res/values-fr/strings.xml
  94. 1355 1390
      app/src/main/res/values-hu/strings.xml
  95. 1 1
      app/src/main/res/values-hu/voicemessage_strings.xml
  96. 7 3
      app/src/main/res/values-hu/voip_strings.xml
  97. 5 5
      app/src/main/res/values-hu/webclient_strings.xml
  98. 9 2
      app/src/main/res/values-it/strings.xml
  99. 2 1
      app/src/main/res/values-ja/strings.xml
  100. 8 1
      app/src/main/res/values-nl-rNL/strings.xml

+ 5 - 3
app/build.gradle

@@ -13,7 +13,7 @@ if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")
 }
 
 // version codes
-def app_version = "4.831"
+def app_version = "4.84"
 def beta_suffix = "" // with leading dash
 
 /**
@@ -92,7 +92,7 @@ android {
         vectorDrawables.useSupportLibrary = true
         applicationId "ch.threema.app"
         testApplicationId 'ch.threema.app.test'
-        versionCode 756
+        versionCode 761
         versionName "${app_version}${beta_suffix}"
         resValue "string", "app_name", "Threema"
         // package name used for sync adapter - needs to match mime types below
@@ -656,7 +656,7 @@ dependencies {
 
     implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
     implementation 'net.sf.opencsv:opencsv:2.3'
-    implementation 'net.lingala.zip4j:zip4j:2.11.1'
+    implementation 'net.lingala.zip4j:zip4j:2.11.2'
     implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
     // commons-io >2.6 requires android 8
     implementation 'commons-io:commons-io:2.6'
@@ -821,6 +821,8 @@ dependencies {
     sandboxImplementation maplibreDependency
     sandbox_workImplementation maplibreDependency
     redImplementation maplibreDependency
+    hmsImplementation maplibreDependency
+    hms_workImplementation maplibreDependency
 
     // Huawei related libraries (only for hms* build variants)
     def huaweiDependencies = [

+ 1 - 1
app/src/androidTest/java/ch/threema/app/backuprestore/csv/BackupServiceTest.java

@@ -263,7 +263,7 @@ public class BackupServiceTest {
 	    // Messages contact 1
 	    this.messageService.sendText("Bonjour!", this.contactService.createReceiver(contact1));
 	    this.messageService.sendText("Phở?", this.contactService.createReceiver(contact1));
-	    this.messageService.createVoipStatus(VoipStatusDataModel.createAborted(), this.contactService.createReceiver(contact1), true, false);
+	    this.messageService.createVoipStatus(VoipStatusDataModel.createAborted(0), this.contactService.createReceiver(contact1), true, false);
 	    // Messages contact 2
 	    this.messageService.sendText("\uD83D\uDC4B", this.contactService.createReceiver(contact2));
 

+ 12 - 11
app/src/androidTest/java/ch/threema/app/voip/VoipStatusMessageTest.java

@@ -38,6 +38,7 @@ import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.MessageModel;
 import ch.threema.storage.models.data.status.VoipStatusDataModel;
 
+import static ch.threema.storage.models.data.status.VoipStatusDataModel.NO_CALL_ID;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -102,7 +103,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createMissed(),
+			VoipStatusDataModel.createMissed(NO_CALL_ID, null),
 			ICON_INCOMING,
 			COLOR_RED,
 			"Missed call",
@@ -115,7 +116,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.UNKNOWN),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.UNKNOWN),
 			ICON_INCOMING,
 			COLOR_RED,
 			"Missed call",
@@ -128,7 +129,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.BUSY),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.BUSY),
 			ICON_INCOMING,
 			COLOR_RED,
 			"Missed call (Busy)",
@@ -141,7 +142,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.TIMEOUT),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.TIMEOUT),
 			ICON_INCOMING,
 			COLOR_RED,
 			"Missed call",
@@ -154,7 +155,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.REJECTED),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.REJECTED),
 			ICON_INCOMING,
 			COLOR_ORANGE,
 			"Call declined",
@@ -167,7 +168,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			false,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.DISABLED),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.DISABLED),
 			ICON_INCOMING,
 			COLOR_ORANGE,
 			"Call declined",
@@ -180,7 +181,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			true,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.UNKNOWN),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.UNKNOWN),
 			ICON_OUTGOING,
 			COLOR_RED,
 			"Call declined",
@@ -193,7 +194,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			true,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.BUSY),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.BUSY),
 			ICON_OUTGOING,
 			COLOR_RED,
 			"Call recipient is busy",
@@ -206,7 +207,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			true,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.TIMEOUT),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.TIMEOUT),
 			ICON_OUTGOING,
 			COLOR_RED,
 			"Call recipient is unavailable",
@@ -219,7 +220,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			true,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.REJECTED),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.REJECTED),
 			ICON_OUTGOING,
 			COLOR_RED,
 			"Call declined",
@@ -232,7 +233,7 @@ public class VoipStatusMessageTest {
 		new TestCase(
 			this.getContext(),
 			true,
-			VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.DISABLED),
+			VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.DISABLED),
 			ICON_OUTGOING,
 			COLOR_RED,
 			"Threema calls disabled by recipient",

+ 5 - 8
app/src/main/AndroidManifest.xml

@@ -68,18 +68,15 @@
 	<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
 	<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
 
-	<!-- licence stuff -->
-	<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
-
-	<!-- launcher shortcuts -->
+	<!-- Launcher shortcuts -->
 	<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
-	<!-- for huawei launcher badges -->
+	<!-- Huawei launcher badges -->
 	<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/>
 	<uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS"/>
 	<uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS"/>
 
-	<!-- sony launcher badges -->
+	<!-- Sony launcher badges -->
 	<uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE"/>
 
 	<!-- only for fastlane test -->
@@ -233,7 +230,7 @@
 			android:theme="@style/Theme.Threema.WithToolbar"
 			android:configChanges="uiMode"
 			android:exported="true">
-			<intent-filter android:label="@string/app_name">
+			<intent-filter android:label="@string/share_with_app">
 				<action android:name="android.intent.action.SEND"/>
 				<category android:name="android.intent.category.DEFAULT"/>
 				<data android:mimeType="text/plain"/>
@@ -243,7 +240,7 @@
 				<data android:mimeType="application/*"/>
 				<data android:mimeType="*/*"/>
 			</intent-filter>
-			<intent-filter android:label="@string/app_name">
+			<intent-filter android:label="@string/share_with_app">
 				<action android:name="android.intent.action.SEND_MULTIPLE"/>
 				<category android:name="android.intent.category.DEFAULT"/>
 				<data android:mimeType="*/*"/>

+ 31 - 27
app/src/main/java/ch/threema/app/ThreemaApplication.java

@@ -47,6 +47,23 @@ import android.provider.ContactsContract;
 import android.text.format.DateUtils;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.ProcessLifecycleOwner;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.multidex.MultiDexApplication;
+import androidx.preference.PreferenceManager;
+import androidx.work.Constraints;
+import androidx.work.ExistingPeriodicWorkPolicy;
+import androidx.work.NetworkType;
+import androidx.work.PeriodicWorkRequest;
+import androidx.work.WorkManager;
+
 import com.datatheorem.android.trustkit.TrustKit;
 import com.datatheorem.android.trustkit.reporting.BackgroundReporter;
 import com.mapbox.mapboxsdk.Mapbox;
@@ -71,22 +88,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-import androidx.appcompat.app.AppCompatDelegate;
-import androidx.core.content.ContextCompat;
-import androidx.lifecycle.DefaultLifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.ProcessLifecycleOwner;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-import androidx.multidex.MultiDexApplication;
-import androidx.preference.PreferenceManager;
-import androidx.work.Constraints;
-import androidx.work.ExistingPeriodicWorkPolicy;
-import androidx.work.NetworkType;
-import androidx.work.PeriodicWorkRequest;
-import androidx.work.WorkManager;
 import ch.threema.app.backuprestore.csv.BackupService;
 import ch.threema.app.exceptions.DatabaseMigrationFailedException;
 import ch.threema.app.exceptions.FileSystemNotPresentException;
@@ -287,8 +288,9 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 	private static HashMap<String, String> messageDrafts = new HashMap<>();
 	private static HashMap<String, String> quoteDrafts = new HashMap<>();
 
-	public static ExecutorService sendMessageExecutorService = Executors.newFixedThreadPool(4);
-	public static ExecutorService sendMessageSingleThreadExecutorService = Executors.newSingleThreadExecutor();
+	public static final ExecutorService sendMessageExecutorService = Executors.newFixedThreadPool(4);
+	public static final ExecutorService sendMessageSingleThreadExecutorService = Executors.newSingleThreadExecutor();
+	public static final ExecutorService voiceMessageThumbnailExecutorService = Executors.newFixedThreadPool(4);
 
 	private static boolean checkAppReplacingState(Context context) {
 		// workaround https://code.google.com/p/android/issues/detail?id=56296
@@ -369,7 +371,9 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 		}
 
 		// Initialize TrustKit for CA pinning
-		TrustKit.initializeWithNetworkSecurityConfiguration(this);
+		if (!ConfigUtils.isOnPremBuild()) {
+			TrustKit.initializeWithNetworkSecurityConfiguration(this);
+		}
 
 		// Set unhandled exception logger
 		LoggingUEH loggingUEH = new LoggingUEH(getAppContext());
@@ -1979,41 +1983,41 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 			}
 
 			@Override
-			public void onFinished(@NonNull String peerIdentity, boolean outgoing, int duration) {
+			public void onFinished(long callId, @NonNull String peerIdentity, boolean outgoing, int duration) {
 				final String direction = outgoing ? "to" : "from";
 				this.logger.info("Call {} {} finished", direction, peerIdentity);
 				this.saveStatus(peerIdentity,
 						outgoing,
-						VoipStatusDataModel.createFinished(duration),
+						VoipStatusDataModel.createFinished(callId, duration),
 						true);
 			}
 
 			@Override
-			public void onRejected(String peerIdentity, boolean outgoing, byte reason) {
+			public void onRejected(long callId, String peerIdentity, boolean outgoing, byte reason) {
 				final String direction = outgoing ? "to" : "from";
 				this.logger.info("Call {} {} rejected (reason {})", direction, peerIdentity, reason);
 				this.saveStatus(peerIdentity,
 						// on rejected incoming, the outgoing was rejected!
 						!outgoing,
-						VoipStatusDataModel.createRejected(reason),
+						VoipStatusDataModel.createRejected(callId, reason),
 						true);
 			}
 
 			@Override
-			public void onMissed(String peerIdentity, boolean accepted) {
+			public void onMissed(long callId, String peerIdentity, boolean accepted, @Nullable Date date) {
 				this.logger.info("Call from {} missed", peerIdentity);
 				this.saveStatus(peerIdentity,
 						false,
-						VoipStatusDataModel.createMissed(),
+						VoipStatusDataModel.createMissed(callId, date),
 						accepted);
 			}
 
 			@Override
-			public void onAborted(String peerIdentity) {
+			public void onAborted(long callId, String peerIdentity) {
 				this.logger.info("Call to {} aborted", peerIdentity);
 				this.saveStatus(peerIdentity,
 						true,
-						VoipStatusDataModel.createAborted(),
+						VoipStatusDataModel.createAborted(callId),
 						true);
 			}
 

+ 1 - 1
app/src/main/java/ch/threema/app/activities/ContactDetailActivity.java

@@ -806,7 +806,7 @@ public class ContactDetailActivity extends ThreemaToolbarActivity
 						default:
 							txt = R.string.id_mismatch;
 					}
-					SimpleStringAlertDialog.newInstance(R.string.scan_id, getString(txt)).show(getSupportFragmentManager(), "scanId");
+					SimpleStringAlertDialog.newInstance(R.string.id_scanned, getString(txt)).show(getSupportFragmentManager(), "scanId");
 				}
 				break;
 			case REQUEST_CODE_CONTACT_EDITOR:

+ 4 - 4
app/src/main/java/ch/threema/app/activities/EnterSerialActivity.java

@@ -41,17 +41,17 @@ import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import org.slf4j.Logger;
-
 import androidx.annotation.NonNull;
 import androidx.core.text.HtmlCompat;
+
+import org.slf4j.Logger;
+
 import ch.threema.app.BuildConfig;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.dialogs.GenericProgressDialog;
 import ch.threema.app.exceptions.FileSystemNotPresentException;
 import ch.threema.app.managers.ServiceManager;
-import ch.threema.app.push.PushService;
 import ch.threema.app.services.AppRestrictionService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.license.LicenseService;
@@ -341,7 +341,7 @@ public class EnterSerialActivity extends ThreemaActivity {
 	protected void onSaveInstanceState(Bundle outState) {
 		super.onSaveInstanceState(outState);
 
-		if (!TestUtil.empty(licenseKeyOrUsernameText.getText())) {
+		if (licenseKeyOrUsernameText != null && !TestUtil.empty(licenseKeyOrUsernameText.getText())) {
 			outState.putString(BUNDLE_LICENSE_KEY, licenseKeyOrUsernameText.getText().toString());
 		}
 

+ 5 - 0
app/src/main/java/ch/threema/app/activities/GroupAddActivity.java

@@ -27,6 +27,7 @@ import android.widget.Toast;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import androidx.annotation.NonNull;
@@ -126,7 +127,11 @@ public class GroupAddActivity extends MemberChooseActivity implements GenericAle
 			} else {
 				createOrUpdateGroup(selectedContacts);
 			}
+		} else if (groupModel != null) {
+			// Adding group members to existing group (none selected)
+			createOrUpdateGroup(Collections.emptyList());
 		} else {
+			// Adding group members to new group (none selected)
 			GenericAlertDialog.newInstance(R.string.title_addgroup, R.string.group_create_no_members, R.string.yes, R.string.no).show(getSupportFragmentManager(), DIALOG_TAG_NO_MEMBERS);
 		}
 	}

+ 2 - 2
app/src/main/java/ch/threema/app/activities/HomeActivity.java

@@ -579,7 +579,7 @@ public class HomeActivity extends ThreemaAppCompatActivity implements
 											// -> create a new backup with existing password
 											enableSafe(threemaSafeService, newConfig, threemaSafeService.getThreemaSafeMasterKey());
 										} else {
-											threemaSafeService.launchForcedPasswordDialog(this);
+											threemaSafeService.launchForcedPasswordDialog(this, true);
 											finish();
 											return;
 										}
@@ -592,7 +592,7 @@ public class HomeActivity extends ThreemaAppCompatActivity implements
 											enableSafe(threemaSafeService, newConfig, null);
 										} else {
 											// ask user for a new password
-											threemaSafeService.launchForcedPasswordDialog(this);
+											threemaSafeService.launchForcedPasswordDialog(this, true);
 											finish();
 											return;
 										}

+ 1 - 1
app/src/main/java/ch/threema/app/activities/PinLockActivity.java

@@ -203,7 +203,7 @@ public class PinLockActivity extends ThreemaActivity {
 			if (isCheckOnly) {
 				passwordEntry.setEnabled(false);
 
-				handler.postDelayed(() -> RuntimeUtil.runOnUiThread(this::finish), 1000);
+				handler.postDelayed(() -> RuntimeUtil.runOnUiThread(this::quit), 1000);
 			}
 			if (++numWrongConfirmAttempts >= FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
 				long deadline = setLockoutAttemptDeadline(DEFAULT_LOCKOUT_TIMEOUT); // TODO default value

+ 1 - 1
app/src/main/java/ch/threema/app/activities/RecipientListBaseActivity.java

@@ -855,7 +855,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 
 	private void sendSharedMedia(final MessageReceiver[] messageReceivers, final Intent intent) {
 		if (messageReceivers.length == 1 && mediaItems.size() == 1 && TYPE_TEXT == mediaItems.get(0).getType()) {
-			intent.putExtra(ThreemaApplication.INTENT_DATA_TEXT, mediaItems.get(0).getCaption());
+			intent.putExtra(ThreemaApplication.INTENT_DATA_TEXT, mediaItems.get(0).getTrimmedCaption());
 			startComposeActivity(intent);
 		} else if (messageReceivers.length > 1 || mediaItems.size() > 0) {
 			messageService.sendMediaSingleThread(mediaItems, Arrays.asList(messageReceivers));

+ 25 - 22
app/src/main/java/ch/threema/app/activities/SendMediaActivity.java

@@ -21,6 +21,12 @@
 
 package ch.threema.app.activities;
 
+import static ch.threema.app.ui.MediaItem.TYPE_GIF;
+import static ch.threema.app.ui.MediaItem.TYPE_IMAGE;
+import static ch.threema.app.ui.MediaItem.TYPE_IMAGE_CAM;
+import static ch.threema.app.utils.BitmapUtil.FLIP_HORIZONTAL;
+import static ch.threema.app.utils.BitmapUtil.FLIP_VERTICAL;
+
 import android.Manifest;
 import android.animation.Animator;
 import android.annotation.SuppressLint;
@@ -57,16 +63,6 @@ import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.google.android.material.snackbar.BaseTransientBottomBar;
-import com.google.android.material.snackbar.Snackbar;
-
-import org.slf4j.Logger;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.UiThread;
 import androidx.appcompat.app.ActionBar;
@@ -78,6 +74,17 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
 import androidx.recyclerview.widget.ItemTouchHelper;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.snackbar.BaseTransientBottomBar;
+import com.google.android.material.snackbar.Snackbar;
+
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.adapters.SendMediaAdapter;
@@ -114,12 +121,6 @@ import ch.threema.base.ThreemaException;
 import ch.threema.base.utils.LoggingUtil;
 import pl.droidsonroids.gif.GifImageView;
 
-import static ch.threema.app.ui.MediaItem.TYPE_GIF;
-import static ch.threema.app.ui.MediaItem.TYPE_IMAGE;
-import static ch.threema.app.ui.MediaItem.TYPE_IMAGE_CAM;
-import static ch.threema.app.utils.BitmapUtil.FLIP_HORIZONTAL;
-import static ch.threema.app.utils.BitmapUtil.FLIP_VERTICAL;
-
 public class SendMediaActivity extends ThreemaToolbarActivity implements
 	GenericAlertDialog.DialogClickListener,
 	ThreemaToolbarActivity.OnSoftKeyboardChangedListener {
@@ -1229,12 +1230,14 @@ public class SendMediaActivity extends ThreemaToolbarActivity implements
 					protected void onPostExecute(Bitmap bitmap) {
 						super.onPostExecute(bitmap);
 						bigProgressBar.setVisibility(View.GONE);
-						bigImageView.setRotation(0f);
-						bigImageView.setScaleX(1f);
-						bigImageView.setScaleY(1f);
-						bigImageView.setRotationY(0f);
-						bigImageView.setVisibility(View.VISIBLE);
-						bigGifImageView.setVisibility(View.GONE);
+						if (position == bigImagePos) {
+							bigImageView.setRotation(0f);
+							bigImageView.setScaleX(1f);
+							bigImageView.setScaleY(1f);
+							bigImageView.setRotationY(0f);
+							bigImageView.setVisibility(View.VISIBLE);
+							bigGifImageView.setVisibility(View.GONE);
+						}
 					}
 				}.execute(bitmapParams);
 			}

+ 108 - 80
app/src/main/java/ch/threema/app/activities/wizard/WizardBaseActivity.java

@@ -21,6 +21,8 @@
 
 package ch.threema.app.activities.wizard;
 
+import static ch.threema.app.ThreemaApplication.PHONE_LINKED_PLACEHOLDER;
+
 import android.accounts.Account;
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -37,6 +39,14 @@ import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+
 import com.google.i18n.phonenumbers.NumberParseException;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
 import com.google.i18n.phonenumbers.Phonenumber;
@@ -45,13 +55,6 @@ import org.slf4j.Logger;
 
 import java.util.List;
 
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentStatePagerAdapter;
-import androidx.viewpager.widget.ViewPager;
-import androidx.work.OneTimeWorkRequest;
-import androidx.work.WorkManager;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.activities.ThreemaAppCompatActivity;
@@ -65,7 +68,6 @@ import ch.threema.app.fragments.wizard.WizardFragment1;
 import ch.threema.app.fragments.wizard.WizardFragment2;
 import ch.threema.app.fragments.wizard.WizardFragment3;
 import ch.threema.app.fragments.wizard.WizardFragment4;
-import ch.threema.app.fragments.wizard.WizardFragment5;
 import ch.threema.app.jobs.WorkSyncService;
 import ch.threema.app.managers.ServiceManager;
 import ch.threema.app.routines.SynchronizeContactsRoutine;
@@ -82,6 +84,7 @@ import ch.threema.app.ui.StepPagerStrip;
 import ch.threema.app.utils.AppRestrictionUtil;
 import ch.threema.app.utils.ConfigUtils;
 import ch.threema.app.utils.RuntimeUtil;
+import ch.threema.app.utils.SynchronizeContactsUtil;
 import ch.threema.app.utils.TestUtil;
 import ch.threema.app.utils.TextUtil;
 import ch.threema.app.workers.IdentityStatesWorker;
@@ -91,15 +94,12 @@ import ch.threema.domain.protocol.api.LinkMobileNoException;
 import ch.threema.localcrypto.MasterKeyLockedException;
 import ch.threema.storage.models.ContactModel;
 
-import static ch.threema.app.ThreemaApplication.PHONE_LINKED_PLACEHOLDER;
-
 public class WizardBaseActivity extends ThreemaAppCompatActivity implements ViewPager.OnPageChangeListener,
 		View.OnClickListener,
 		WizardFragment1.OnSettingsChangedListener,
 		WizardFragment2.OnSettingsChangedListener,
 		WizardFragment3.OnSettingsChangedListener,
-		WizardFragment4.OnSettingsChangedListener,
-		WizardFragment5.SettingsInterface,
+		WizardFragment4.SettingsInterface,
 		WizardDialog.WizardDialogCallback {
 
 	private static final Logger logger = LoggingUtil.getThreemaLogger("WizardBaseActivity");
@@ -109,13 +109,14 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	private static final String DIALOG_TAG_USE_ANONYMOUSLY = "ano";
 	private static final String DIALOG_TAG_THREEMA_SAFE = "sd";
 	private static final String DIALOG_TAG_PASSWORD_BAD = "pwb";
+	private static final String DIALOG_TAG_SYNC_CONTACTS_ENABLE = "scen";
 
 	private static final int PERMISSION_REQUEST_READ_CONTACTS = 2;
-	private static final int NUM_PAGES = 6;
+	private static final int NUM_PAGES = 5;
 	private static final long FINISH_DELAY = 3 * 1000;
 	private static final long DIALOG_DELAY = 200;
 
-	public static final boolean DEFAULT_SYNC_CONTACTS = true;
+	public static final boolean DEFAULT_SYNC_CONTACTS = false;
 
 	private static int lastPage = 0;
 	private ParallaxViewPager viewPager;
@@ -125,7 +126,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	private StepPagerStrip stepPagerStrip;
 	private String nickname, email, number, prefix, presetMobile, presetEmail, safePassword;
 	private ThreemaSafeServerInfo safeServerInfo = new ThreemaSafeServerInfo();
-	private boolean isSyncContacts, syncContactsRestricted = false, skipWizard = false, readOnlyProfile = false;
+	private boolean isSyncContacts = DEFAULT_SYNC_CONTACTS, userCannotChangeContactSync = false, skipWizard = false, readOnlyProfile = false;
 	private ThreemaSafeMDMConfig safeConfig;
 	private ServiceManager serviceManager;
 	private UserService userService;
@@ -133,7 +134,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	private PreferenceService preferenceService;
 	private ThreemaSafeService threemaSafeService;
 	private boolean errorRaised = false;
-	private WizardFragment5 fragment5;
+	private WizardFragment4 fragment4;
 
 	private final Handler finishHandler = new Handler();
 	private final Handler dialogHandler = new Handler();
@@ -144,7 +145,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 		 	RuntimeUtil.runOnUiThread(new Runnable() {
 				@Override
 				public void run() {
-					fragment5.setContactsSyncInProgress(false, null);
+					fragment4.setContactsSyncInProgress(false, null);
 					prepareThreemaSafe();
 				}
 			});
@@ -164,13 +165,6 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 					}
 				}
 
-				if (current == WizardFragment3.PAGE_ID && previous == WizardFragment2.PAGE_ID && TestUtil.empty(nickname)) {
-					if (!isReadOnlyProfile()) {
-						WizardDialog wizardDialog = WizardDialog.newInstance(R.string.new_wizard_use_id_as_nickname, R.string.yes, R.string.no, WizardDialog.Highlight.POSITIVE);
-						wizardDialog.show(getSupportFragmentManager(), DIALOG_TAG_USE_ID_AS_NICKNAME);
-					}
-				}
-
 				if (current == WizardFragment4.PAGE_ID && previous == WizardFragment3.PAGE_ID) {
 					if (!isReadOnlyProfile()) {
 						if ((!TestUtil.empty(number) && TestUtil.empty(presetMobile) && !localeService.validatePhoneNumber(getPhone())) ||
@@ -184,7 +178,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 					}
 				}
 
-				if (current == WizardFragment5.PAGE_ID && previous == WizardFragment4.PAGE_ID) {
+				if (current == WizardFragment4.PAGE_ID && previous == WizardFragment3.PAGE_ID) {
 					if (!isReadOnlyProfile()) {
 						boolean needConfirm;
 						if (ConfigUtils.isWorkBuild()) {
@@ -295,9 +289,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			booleanPreset = AppRestrictionUtil.getBooleanRestriction(getString(R.string.restriction__contact_sync));
 			if (booleanPreset != null) {
 				isSyncContacts = booleanPreset;
-				syncContactsRestricted = true;
-			} else {
-				isSyncContacts = DEFAULT_SYNC_CONTACTS;
+				userCannotChangeContactSync = true;
 			}
 			booleanPreset = AppRestrictionUtil.getBooleanRestriction(getString(R.string.restriction__readonly_profile));
 			if (booleanPreset != null) {
@@ -307,7 +299,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			if (booleanPreset != null) {
 				if (booleanPreset) {
 					skipWizard = true;
-					viewPager.setCurrentItem(WizardFragment5.PAGE_ID);
+					viewPager.setCurrentItem(WizardFragment4.PAGE_ID);
 				}
 			}
 		} else {
@@ -318,6 +310,13 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			if (!TestUtil.empty(presetEmail)) {
 				email = presetEmail;
 			}
+
+		}
+
+		// if the app is running in a restricted user profile, it s not possible to add accounts
+		if (SynchronizeContactsUtil.isRestrictedProfile(this)) {
+			userCannotChangeContactSync = true;
+			isSyncContacts = false;
 		}
 	}
 
@@ -331,7 +330,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 				Phonenumber.PhoneNumber numberProto = null;
 
 				numberProto = phoneNumberUtil.parse(phoneNumber, "");
-				prefix = "+" + String.valueOf(numberProto.getCountryCode());
+				prefix = "+" + numberProto.getCountryCode();
 				number = String.valueOf(numberProto.getNationalNumber());
 			} catch (NumberParseException e) {
 				logger.error("Exception", e);
@@ -409,7 +408,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			}
 		}
 
-		if (position > lastPage && position >= WizardFragment2.PAGE_ID && position <= WizardFragment5.PAGE_ID) {
+		if (position > lastPage && position >= WizardFragment2.PAGE_ID && position <= WizardFragment4.PAGE_ID) {
 			// we delay dialogs for a few milliseconds to prevent stuttering of the page change animation
 			dialogHandler.removeCallbacks(showDialogDelayedTask(position, lastPage));
 			dialogHandler.postDelayed(showDialogDelayedTask(position, lastPage), DIALOG_DELAY);
@@ -429,9 +428,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	 * @see ViewPager#SCROLL_STATE_SETTLING
 	 */
 	@Override
-	public void onPageScrollStateChanged(int state) {
-
-	}
+	public void onPageScrollStateChanged(int state) { }
 
 	/**
 	 * Called when a view has been clicked.
@@ -448,9 +445,9 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	}
 
 	@Override
-	public void onWizardFinished(WizardFragment5 fragment, Button finishButton) {
+	public void onWizardFinished(WizardFragment4 fragment, Button finishButton) {
 		errorRaised = false;
-		fragment5 = fragment;
+		fragment4 = fragment;
 
 		viewPager.lock(true);
 		this.finishButton = finishButton;
@@ -462,7 +459,33 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 
 		userService.setPublicNickname(this.nickname);
 
-		linkPhone(); // also calls linkEmail() and syncContactsAndFinish();
+		askUserForContactSync();
+	}
+
+	private void askUserForContactSync() {
+		/* trigger a connection now - as application lifecycle was set to resumed state when there was no identity yet */
+		serviceManager.getLifetimeService().ensureConnection();
+
+		if (this.userCannotChangeContactSync) {
+			if (this.isSyncContacts) {
+				requestContactSyncPermission();
+			} else {
+				linkPhone();
+			}
+		} else {
+			WizardDialog wizardDialog = WizardDialog.newInstance(R.string.new_wizard_info_sync_contacts_dialog, R.string.yes, R.string.no, null);
+			wizardDialog.show(getSupportFragmentManager(), DIALOG_TAG_SYNC_CONTACTS_ENABLE);
+		}
+	}
+
+	private void requestContactSyncPermission() {
+		if (ConfigUtils.requestContactPermissions(this, null, PERMISSION_REQUEST_READ_CONTACTS)) {
+			// permission is already granted
+			this.isSyncContacts = true;
+			preferenceService.setSyncContacts(this.isSyncContacts);
+			linkPhone();
+		}
+		// continue to onRequestPermissionsResult
 	}
 
 	@Override
@@ -495,13 +518,6 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 		this.safeServerInfo = safeServerInfo;
 	}
 
-	@Override
-	public void onSyncContactsSet(boolean enabled) {
-		if (!this.syncContactsRestricted) {
-			this.isSyncContacts = enabled;
-		}
-	}
-
 	@Override
 	public String getNickname() {
 		return this.nickname;
@@ -596,9 +612,11 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 				prevPage();
 				break;
 			case DIALOG_TAG_PASSWORD_BAD:
-				break;
 			case DIALOG_TAG_THREEMA_SAFE:
 				break;
+			case DIALOG_TAG_SYNC_CONTACTS_ENABLE:
+				requestContactSyncPermission();
+				break;
 		}
 	}
 
@@ -617,6 +635,11 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			case DIALOG_TAG_PASSWORD_BAD:
 				setPage(WizardFragment1.PAGE_ID);
 				break;
+			case DIALOG_TAG_SYNC_CONTACTS_ENABLE:
+				isSyncContacts = false;
+				this.serviceManager.getPreferenceService().setSyncContacts(false);
+				syncContactsAndFinish();
+				break;
 		}
 	}
 
@@ -645,8 +668,6 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 					return new WizardFragment3();
 				case WizardFragment4.PAGE_ID:
 					return new WizardFragment4();
-				case WizardFragment5.PAGE_ID:
-					return new WizardFragment5();
 				default:
 					break;
 			}
@@ -678,7 +699,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	}
 
 	@SuppressLint("StaticFieldLeak")
-	private void linkEmail(final WizardFragment5 fragment) {
+	private void linkEmail(final WizardFragment4 fragment) {
 		final String newEmail = getEmail();
 		if (TestUtil.empty(newEmail)) {
 			initSyncAndFinish();
@@ -728,7 +749,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	private void linkPhone() {
 		final String phone = getPhone();
 		if (TestUtil.empty(phone)) {
-			linkEmail(fragment5);
+			linkEmail(fragment4);
 			return;
 		}
 
@@ -739,7 +760,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			new AsyncTask<Void, Void, String>() {
 				@Override
 				protected void onPreExecute() {
-					fragment5.setMobileLinkingInProgress(true);
+					fragment4.setMobileLinkingInProgress(true);
 				}
 
 				@Override
@@ -759,16 +780,16 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 				@Override
 				protected void onPostExecute(String result) {
 					if (result != null) {
-						fragment5.setMobileLinkingAlert(result);
+						fragment4.setMobileLinkingAlert(result);
 						errorRaised = true;
 					} else {
-						fragment5.setMobileLinkingInProgress(false);
+						fragment4.setMobileLinkingInProgress(false);
 					}
-					linkEmail(fragment5);
+					linkEmail(fragment4);
 				}
 			}.execute();
 		} else {
-			linkEmail(fragment5);
+			linkEmail(fragment4);
 		}
 	}
 
@@ -830,7 +851,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 		}
 	}
 
-	@SuppressLint("StaticFieldLeak")
+	@SuppressLint({"StaticFieldLeak", "MissingPermission"})
 	private void reallySyncContactsAndFinish() {
 		ensureMasterKeyWrite();
 
@@ -838,9 +859,10 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			new AsyncTask<Void, Void, Void>() {
 				@Override
 				protected void onPreExecute() {
-					fragment5.setContactsSyncInProgress(true, getString(R.string.wizard1_sync_contacts));
+					fragment4.setContactsSyncInProgress(true, getString(R.string.wizard1_sync_contacts));
 				}
 
+				@SuppressLint("MissingPermission")
 				@Override
 				protected Void doInBackground(Void... params) {
 					try {
@@ -854,12 +876,12 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 						routine.setOnStatusUpdate(new SynchronizeContactsRoutine.OnStatusUpdate() {
 							@Override
 							public void newStatus(final long percent, final String message) {
-							 	RuntimeUtil.runOnUiThread(() -> fragment5.setContactsSyncInProgress(true, message));
+							 	RuntimeUtil.runOnUiThread(() -> fragment4.setContactsSyncInProgress(true, message));
 							}
 
 							@Override
 							public void error(final Exception x) {
-							 	RuntimeUtil.runOnUiThread(() -> fragment5.setContactsSyncInProgress(false, x.getMessage()));
+							 	RuntimeUtil.runOnUiThread(() -> fragment4.setContactsSyncInProgress(false, x.getMessage()));
 							}
 						});
 
@@ -899,7 +921,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 			new AsyncTask<Void, Void, byte[]>() {
 				@Override
 				protected void onPreExecute() {
-					fragment5.setThreemaSafeInProgress(true, getString(R.string.preparing_threema_safe));
+					fragment4.setThreemaSafeInProgress(true, getString(R.string.preparing_threema_safe));
 				}
 
 				@Override
@@ -909,7 +931,7 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 
 				@Override
 				protected void onPostExecute(byte[] masterkey) {
-					fragment5.setThreemaSafeInProgress(false, getString(R.string.menu_done));
+					fragment4.setThreemaSafeInProgress(false, getString(R.string.menu_done));
 
 					if (masterkey != null) {
 						threemaSafeService.storeMasterKey(masterkey);
@@ -935,17 +957,18 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 
 	private void initSyncAndFinish() {
 		if (!errorRaised || ConfigUtils.isWorkRestricted()) {
-			//set setting flag!
-			preferenceService.setSyncContacts(this.isSyncContacts);
-			//directly goto sync contacts
 			syncContactsAndFinish();
 		} else {
-			// unlock UI to try again
-			viewPager.lock(false);
-			prevButton.setVisibility(View.VISIBLE);
-			if (finishButton != null) {
-				finishButton.setEnabled(true);
-			}
+			resetUi();
+		}
+	}
+
+	private void resetUi() {
+		// unlock UI to try again
+		viewPager.lock(false);
+		prevButton.setVisibility(View.VISIBLE);
+		if (finishButton != null) {
+			finishButton.setEnabled(true);
 		}
 	}
 
@@ -967,10 +990,10 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 		serviceManager.getLifetimeService().ensureConnection();
 
 		if (this.isSyncContacts) {
-			if (ConfigUtils.requestContactPermissions(this, null, PERMISSION_REQUEST_READ_CONTACTS)) {
-				reallySyncContactsAndFinish();
-			}
+			preferenceService.setSyncContacts(true);
+			reallySyncContactsAndFinish();
 		} else {
+			preferenceService.setSyncContacts(false);
 			startWorkSync();
 			startIdentityStatesSync();
 			prepareThreemaSafe();
@@ -980,15 +1003,20 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 	@Override
 	public void onRequestPermissionsResult(int requestCode,
 										   @NonNull String permissions[], @NonNull int[] grantResults) {
-		switch (requestCode) {
-			case PERMISSION_REQUEST_READ_CONTACTS:
-				if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
-					Boolean contactSyncRestriction = AppRestrictionUtil.getBooleanRestriction(getString(R.string.restriction__contact_sync));
-					if (contactSyncRestriction == null || !contactSyncRestriction) {
-						this.serviceManager.getPreferenceService().setSyncContacts(false);
-					}
+		super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+		if (requestCode == PERMISSION_REQUEST_READ_CONTACTS) {
+			if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+				this.isSyncContacts = true;
+				linkPhone();
+			} else {
+				if (userCannotChangeContactSync) {
+					ConfigUtils.showPermissionRationale(this, (View) viewPager.getParent(), R.string.permission_contacts_sync_required);
+					resetUi();
+				} else {
+					this.isSyncContacts = false;
+					linkPhone();
 				}
-				reallySyncContactsAndFinish();
+			}
 		}
 	}
 }

+ 4 - 0
app/src/main/java/ch/threema/app/adapters/ComposeMessageAdapter.java

@@ -42,6 +42,8 @@ import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.fragment.app.Fragment;
 
+import org.slf4j.Logger;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
@@ -82,6 +84,7 @@ import ch.threema.app.utils.MimeUtil;
 import ch.threema.app.utils.NameUtil;
 import ch.threema.app.utils.QuoteUtil;
 import ch.threema.app.utils.TestUtil;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.csp.messages.file.FileData;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.ContactModel;
@@ -90,6 +93,7 @@ import ch.threema.storage.models.FirstUnreadMessageModel;
 import ch.threema.storage.models.MessageType;
 
 public class ComposeMessageAdapter extends ArrayAdapter<AbstractMessageModel> {
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ComposeMessageAdapter");
 
 	private final List<AbstractMessageModel> values;
 	private final ChatAdapterDecorator.Helper decoratorHelper;

+ 4 - 3
app/src/main/java/ch/threema/app/adapters/ContactListAdapter.java

@@ -65,6 +65,7 @@ import ch.threema.app.utils.AdapterUtil;
 import ch.threema.app.utils.ContactUtil;
 import ch.threema.app.utils.LocaleUtil;
 import ch.threema.app.utils.NameUtil;
+import ch.threema.app.utils.TestUtil;
 import ch.threema.app.utils.ViewUtil;
 import ch.threema.storage.models.ContactModel;
 
@@ -496,12 +497,12 @@ public class ContactListAdapter extends FilterableListAdapter implements Section
 			} else {
 				// perform filtering
 				List<ContactModel> nContactList = new ArrayList<ContactModel>();
-				filterString = LocaleUtil.normalize(constraint.toString());
+				filterString = constraint.toString();
 
 				for (ContactModel contactModel : ovalues) {
 					if (contactModel != null) {
-						if ((LocaleUtil.normalize(NameUtil.getDisplayNameOrNickname(contactModel, false)).contains(filterString)) ||
-							(contactModel.getIdentity().toUpperCase().contains(filterString))) {
+						if ((TestUtil.matchesConversationSearch(filterString, NameUtil.getDisplayNameOrNickname(contactModel, false))) ||
+							(contactModel.getIdentity().toUpperCase().contains(filterString.toUpperCase()))) {
 							nContactList.add(contactModel);
 						}
 					}

+ 4 - 3
app/src/main/java/ch/threema/app/adapters/decorators/AdapterDecorator.java

@@ -27,6 +27,7 @@ import android.widget.AbsListView;
 import android.widget.ListView;
 
 import androidx.annotation.AnyThread;
+
 import ch.threema.app.ui.listitemholder.AbstractListItemHolder;
 import ch.threema.app.utils.RuntimeUtil;
 
@@ -63,9 +64,9 @@ abstract class AdapterDecorator {
 	@AnyThread
 	protected void invalidate(final AbstractListItemHolder holder, final int position) {
 		RuntimeUtil.runOnUiThread(() -> {
-		if(holder != null && holder.position == position) {
-			configure(holder, position);
-		}
+			if (holder != null && holder.position == position) {
+				configure(holder, position);
+			}
 		});
 	}
 	abstract protected void configure(AbstractListItemHolder holder, int position);

+ 13 - 20
app/src/main/java/ch/threema/app/adapters/decorators/AudioChatAdapterDecorator.java

@@ -30,16 +30,18 @@ import android.view.View;
 import android.widget.SeekBar;
 import android.widget.Toast;
 
+import androidx.annotation.UiThread;
+
 import org.slf4j.Logger;
 
 import java.io.File;
 
-import androidx.annotation.UiThread;
 import ch.threema.app.BuildConfig;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.services.messageplayer.MessagePlayer;
+import ch.threema.app.ui.AudioProgressBarView;
 import ch.threema.app.ui.ControllerView;
 import ch.threema.app.ui.listitemholder.ComposeMessageHolder;
 import ch.threema.app.utils.AnimationUtil;
@@ -82,29 +84,13 @@ public class AudioChatAdapterDecorator extends ChatAdapterDecorator {
 		keepScreenOnUpdate();
 	}
 
-	private void keepScreenOnUpdate() {
-/*		RuntimeUtil.runOnUiThread(() -> {
-			try {
-				helper.getFragment().getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-			} catch (Exception e) {
-				//
-			}
-		});
-*/	}
+	private void keepScreenOnUpdate() {}
 
 	private void keepScreenOff() {
 		if (audioPlayerWakelock != null && audioPlayerWakelock.isHeld()) {
 			audioPlayerWakelock.release();
 		}
-
-/*		RuntimeUtil.runOnUiThread(() -> {
-			try {
-				helper.getFragment().getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-			} catch (Exception e) {
-				//
-			}
-		});
-*/	}
+	}
 
 	@Override
 	protected void configureChatMessage(final ComposeMessageHolder holder, final int position) {
@@ -139,6 +125,7 @@ public class AudioChatAdapterDecorator extends ChatAdapterDecorator {
 		});
 
 		setSpeedButtonText(holder, getPreferenceService().getAudioPlaybackSpeed());
+		holder.seekBar.setMessageModel(getMessageModel(), helper.getThumbnailCache());
 		holder.readOnButton.setVisibility(View.GONE);
 		holder.messageTypeButton.setVisibility(View.VISIBLE);
 		holder.controller.setOnClickListener(v -> {
@@ -181,6 +168,9 @@ public class AudioChatAdapterDecorator extends ChatAdapterDecorator {
 				switch (audioMessagePlayer.getState()) {
 					case MessagePlayer.State_NONE:
 						if (isDownloaded) {
+							if (holder.seekBar != null) {
+								holder.seekBar.setMessageModel(getMessageModel(), helper.getThumbnailCache());
+							}
 							holder.controller.setPlay();
 						} else {
 							if (helper.getDownloadService().isDownloading(getMessageModel().getId())) {
@@ -197,6 +187,9 @@ public class AudioChatAdapterDecorator extends ChatAdapterDecorator {
 						break;
 					case MessagePlayer.State_DOWNLOADED:
 					case MessagePlayer.State_DECRYPTED:
+						if (holder.seekBar != null) {
+							holder.seekBar.setMessageModel(getMessageModel(), helper.getThumbnailCache());
+						}
 						holder.controller.setPlay();
 						break;
 					case MessagePlayer.State_PLAYING:
@@ -217,7 +210,7 @@ public class AudioChatAdapterDecorator extends ChatAdapterDecorator {
 							holder.seekBar.setMax(audioMessagePlayer.getDuration());
 							logger.debug("SeekBar: Position = " + audioMessagePlayer.getPosition());
 							updateProgressCount(holder, audioMessagePlayer.getPosition());
-							holder.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+							holder.seekBar.setOnSeekBarChangeListener(new AudioProgressBarView.OnSeekBarChangeListener() {
 								@Override
 								public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
 									if (fromUser) {

+ 3 - 2
app/src/main/java/ch/threema/app/adapters/decorators/FileChatAdapterDecorator.java

@@ -29,11 +29,12 @@ import android.text.format.Formatter;
 import android.view.View;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 
 import java.io.File;
 
-import androidx.annotation.NonNull;
 import ch.threema.app.R;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.services.PreferenceService;
@@ -160,7 +161,7 @@ public class FileChatAdapterDecorator extends ChatAdapterDecorator {
 			.addListener(LISTENER_TAG, new MessagePlayer.PlaybackListener() {
 				@Override
 				public void onPlay(AbstractMessageModel messageModel, boolean autoPlay) {
-					RuntimeUtil.runOnUiThread(() -> invalidate(holder, position));
+					invalidate(holder, position);
 				}
 
 				@Override

+ 1 - 0
app/src/main/java/ch/threema/app/archive/ArchiveActivity.java

@@ -59,6 +59,7 @@ import ch.threema.app.ui.ThreemaSearchView;
 import ch.threema.app.utils.AnimationUtil;
 import ch.threema.app.utils.ConfigUtils;
 import ch.threema.app.utils.IntentDataUtil;
+import ch.threema.app.utils.StringConversionUtil;
 import ch.threema.app.utils.TestUtil;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.utils.LoggingUtil;

+ 0 - 8
app/src/main/java/ch/threema/app/backuprestore/csv/BackupRestoreDataServiceImpl.java

@@ -21,8 +21,6 @@
 
 package ch.threema.app.backuprestore.csv;
 
-import android.content.Context;
-
 import org.slf4j.Logger;
 
 import java.io.File;
@@ -42,14 +40,10 @@ import ch.threema.base.utils.LoggingUtil;
 public class BackupRestoreDataServiceImpl implements BackupRestoreDataService {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("BackupRestoreDataServiceImpl");
 
-	private final Context context;
 	private final FileService fileService;
 
-
 	public BackupRestoreDataServiceImpl(
-			Context context,
 			FileService fileService) {
-		this.context = context;
 		this.fileService = fileService;
 	}
 
@@ -138,6 +132,4 @@ public class BackupRestoreDataServiceImpl implements BackupRestoreDataService {
 		}
 		return null;
 	}
-
-
 }

+ 5 - 4
app/src/main/java/ch/threema/app/backuprestore/csv/RestoreService.java

@@ -37,6 +37,10 @@ import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+
 import net.lingala.zip4j.ZipFile;
 import net.lingala.zip4j.io.inputstream.ZipInputStream;
 import net.lingala.zip4j.model.FileHeader;
@@ -55,9 +59,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.app.NotificationCompat;
 import ch.threema.app.BuildConfig;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
@@ -475,7 +476,7 @@ public class RestoreService extends Service {
 					} catch (UnknownHostException e) {
 						throw e;
 					} catch (Exception e) {
-						throw new ThreemaException("failed to restore identity: " + e.getMessage());
+						throw new ThreemaException(getString(R.string.unable_to_restore_identity_because, e.getMessage()));
 					}
 
 					updateProgress(STEP_SIZE_IDENTITY);

+ 132 - 173
app/src/main/java/ch/threema/app/camera/VideoEditView.java

@@ -30,9 +30,8 @@ import android.graphics.DashPathEffect;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.media.MediaMetadataRetriever;
-import android.os.Build;
 import android.os.Handler;
+import android.os.Looper;
 import android.text.format.Formatter;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -43,15 +42,18 @@ import android.widget.GridLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.UiThread;
+import androidx.core.view.ViewCompat;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
 import com.google.android.exoplayer2.ExoPlayer;
 import com.google.android.exoplayer2.Player;
 import com.google.android.exoplayer2.source.ClippingMediaSource;
-import com.google.android.exoplayer2.source.MediaSource;
-import com.google.android.exoplayer2.source.ProgressiveMediaSource;
+import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
 import com.google.android.exoplayer2.ui.PlayerView;
-import com.google.android.exoplayer2.upstream.DataSource;
-import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
-import com.google.android.exoplayer2.util.Util;
 
 import org.slf4j.Logger;
 
@@ -59,48 +61,47 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.UiThread;
-import androidx.core.view.ViewCompat;
-import androidx.lifecycle.DefaultLifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ui.MediaItem;
-import ch.threema.app.utils.BitmapUtil;
 import ch.threema.app.utils.FileUtil;
 import ch.threema.app.utils.LocaleUtil;
 import ch.threema.app.utils.RuntimeUtil;
 import ch.threema.app.utils.VideoUtil;
-import ch.threema.app.video.VideoTimelineCache;
+import ch.threema.app.video.VideoTimelineThumbnailTask;
 import ch.threema.base.utils.LoggingUtil;
 
 import static com.google.android.exoplayer2.C.TIME_END_OF_SOURCE;
 
-public class VideoEditView extends FrameLayout implements DefaultLifecycleObserver {
+public class VideoEditView extends FrameLayout implements DefaultLifecycleObserver, VideoTimelineThumbnailTask.VideoTimelineListener {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("VideoEditView");
 
 	private static final int MOVING_NONE = 0;
 	private static final int MOVING_LEFT = 1;
 	private static final int MOVING_RIGHT = 2;
 	private static final String THUMBNAIL_THREAD_NAME = "TimelineThumbs";
+	private static final int MARKER_MOVE_MESSAGE_QUEUE_ID = 771294;
+	private static final int MARKER_MOVE_UPDATE_FREQUENCY_MS = 200;
 
 	private Context context;
 	private int targetHeight, calculatedWidth;
 	private Paint borderPaint, arrowPaint, dashPaint, progressPaint, dimPaint;
 	private int arrowWidth, arrowHeight, borderWidth;
 	private int offsetLeft = 0, offsetRight = 0, touchTargetWidth;
-	private long videoCurrentPosition = 0L, videoFileSize = 0L;
+	private long videoCurrentPosition = 0L, videoFileSize = 0L, clippedStartTimeMs, clippedEndTimeMs;
 	private MediaItem videoItem;
 	private int isMoving = MOVING_NONE;
+	private boolean isClipped = false;
 	private GridLayout timelineGridLayout;
 	private PlayerView videoView;
 	private ExoPlayer videoPlayer;
-	private MediaSource videoSource;
+	private com.google.android.exoplayer2.MediaItem videoSourceMediaItem;
+	private DefaultMediaSourceFactory mediaSourceFactory;
+
 	private TextView startTimeTextView, endTimeTextView, sizeTextView;
 	private Thread thumbnailThread;
 	private final Handler progressHandler = new Handler();
+	private final Handler markerMoveHandler = new Handler(Looper.getMainLooper());
 	private final List<Rect> exclusionRects = new ArrayList<>();
 
 	public VideoEditView(Context context) {
@@ -130,6 +131,8 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 
 		LayoutInflater.from(context).inflate(R.layout.view_video_edit, this, true);
 
+		this.mediaSourceFactory = new DefaultMediaSourceFactory(context);
+
 		this.timelineGridLayout = findViewById(R.id.video_timeline);
 		this.videoView = findViewById(R.id.video_view);
 		this.startTimeTextView = findViewById(R.id.start);
@@ -185,16 +188,6 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 				Player.Listener.super.onPlaybackStateChanged(playbackState);
 				updateProgressBar();
 			}
-
-			@Override
-			public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
-				Player.Listener.super.onPositionDiscontinuity(oldPosition, newPosition, reason);
-				// tapping on the play button after moving end time should start playback from beginning
-				if (oldPosition.positionMs == 0 && newPosition.positionMs == videoItem.getEndTimeMs()) {
-					videoPlayer.seekTo(videoItem.getStartTimeMs());
-					videoPlayer.play();
-				}
-			}
 		});
 
 		this.videoView.setPlayer(videoPlayer);
@@ -296,6 +289,15 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 		}
 	}
 
+	private void resetClipping() {
+		if (isClipped) {
+			videoPlayer.pause();
+			videoPlayer.setMediaItem(videoSourceMediaItem);
+			isClipped = false;
+		}
+		videoCurrentPosition = 0;
+	}
+
 	@SuppressLint("ClickableViewAccessibility")
 	@Override
 	public boolean onTouchEvent(MotionEvent event) {
@@ -308,13 +310,16 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 
 		switch (action) {
 			case MotionEvent.ACTION_DOWN:
+				clippedStartTimeMs = videoItem.getStartTimeMs();
+				clippedEndTimeMs = videoItem.getEndTimeMs();
+
 				if (y >= (this.timelineGridLayout.getTop() - arrowHeight) && y <= (this.timelineGridLayout.getBottom() + arrowHeight)) {
 					if (x >= (left - touchTargetWidth) && x <= (left + touchTargetWidth)) {
-						logger.debug("start moving left: " + x);
+						logger.debug("start moving left: {}", x);
 						isMoving = MOVING_LEFT;
 						return true;
 					} else if (x >= (right - touchTargetWidth) && x <= (right + touchTargetWidth)) {
-						logger.debug("start moving right: " + x);
+						logger.debug("start moving right: {}", x);
 						isMoving = MOVING_RIGHT;
 						return true;
 					}
@@ -322,14 +327,14 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 				isMoving = MOVING_NONE;
 				break;
 			case MotionEvent.ACTION_MOVE:
-				logger.debug("moving " + x);
+				logger.debug("moving {}", x);
 				if (isMoving != MOVING_NONE) {
 					int oldOffsetLeft = offsetLeft;
 					int oldOffsetRight = offsetRight;
 
 					switch (isMoving) {
 						case MOVING_LEFT:
-							logger.debug("moving left to: " + x);
+							logger.debug("moving left to: {}", x);
 							offsetLeft = x - this.timelineGridLayout.getLeft();
 
 							if (offsetLeft < 0) {
@@ -338,15 +343,20 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 								offsetLeft = right - this.timelineGridLayout.getLeft() - touchTargetWidth;
 							}
 
+							clippedStartTimeMs = getVideoPositionFromTimelinePosition(offsetLeft);
+
 							if (oldOffsetLeft != offsetLeft) {
-								videoItem.setStartTimeMs(getVideoPositionFromTimelinePosition(offsetLeft));
-								updateStartAndEnd();
-								invalidate();
+								if (!markerMoveHandler.hasMessages(MARKER_MOVE_MESSAGE_QUEUE_ID)) {
+									resetClipping();
+									videoPlayer.seekTo(clippedStartTimeMs);
+									markerMoveHandler.sendMessageDelayed(markerMoveHandler.obtainMessage(MARKER_MOVE_MESSAGE_QUEUE_ID), MARKER_MOVE_UPDATE_FREQUENCY_MS);
+									updateStartAndEnd(clippedStartTimeMs, clippedEndTimeMs);
+									invalidate();
+								}
 							}
-
 							break;
 						case MOVING_RIGHT:
-							logger.debug("moving right to: " + x);
+							logger.debug("moving right to: {}", x);
 							offsetRight = this.timelineGridLayout.getRight() - x;
 
 							if (offsetRight < 0) {
@@ -355,10 +365,16 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 								offsetRight = this.timelineGridLayout.getRight() - (left + touchTargetWidth);
 							}
 
+							clippedEndTimeMs = getVideoPositionFromTimelinePosition(timelineGridLayout.getWidth() - offsetRight);
+
 							if (oldOffsetRight != offsetRight) {
-								videoItem.setEndTimeMs(getVideoPositionFromTimelinePosition(this.timelineGridLayout.getWidth() - offsetRight));
-								updateStartAndEnd();
-								invalidate();
+								if (!markerMoveHandler.hasMessages(MARKER_MOVE_MESSAGE_QUEUE_ID)) {
+									resetClipping();
+									videoPlayer.seekTo(clippedEndTimeMs);
+									markerMoveHandler.sendMessageDelayed(markerMoveHandler.obtainMessage(MARKER_MOVE_MESSAGE_QUEUE_ID), MARKER_MOVE_UPDATE_FREQUENCY_MS);
+									updateStartAndEnd(clippedStartTimeMs, clippedEndTimeMs);
+									invalidate();
+								}
 							}
 							break;
 					}
@@ -367,16 +383,16 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 				break;
 			case MotionEvent.ACTION_CANCEL:
 			case MotionEvent.ACTION_UP:
-				if (isMoving == MOVING_LEFT || isMoving == MOVING_RIGHT) {
-					boolean previewLastFrame = isMoving == MOVING_RIGHT;
+				markerMoveHandler.removeCallbacksAndMessages(null);
 
+				if (isMoving == MOVING_LEFT || isMoving == MOVING_RIGHT) {
 					videoItem.setStartTimeMs(getVideoPositionFromTimelinePosition(offsetLeft));
 					videoItem.setEndTimeMs(getVideoPositionFromTimelinePosition(this.timelineGridLayout.getWidth() - offsetRight));
 
 					isMoving = MOVING_NONE;
 
-					updateStartAndEnd();
-					preparePlayer(previewLastFrame);
+					updateStartAndEnd(videoItem.getStartTimeMs(), videoItem.getEndTimeMs());
+					preparePlayer();
 
 					return true;
 				}
@@ -412,6 +428,7 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 			imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
 			imageView.setAdjustViewBounds(false);
 			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+			imageView.setScaleY(-1);
 			imageView.setTag(i);
 			frameLayout.addView(imageView);
 			GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
@@ -427,147 +444,49 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 			this.timelineGridLayout.setColumnCount(numColumns);
 		} catch (IllegalArgumentException e) {
 			logger.debug("Invalid column count. Num columns {}", numColumns);
+			return;
 		}
 
-		thumbnailThread = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				int height = 0, width = 0, duration = 0;
-
-				// do not use automatic resource management on MediaMetadataRetriever
-				MediaMetadataRetriever metaDataRetriever = new MediaMetadataRetriever();
-				try {
-					metaDataRetriever.setDataSource(ThreemaApplication.getAppContext(), mediaItem.getUri());
-					try {
-						height = Integer.parseInt(metaDataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
-						width = Integer.parseInt(metaDataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
-						duration = Integer.parseInt(metaDataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
-					} catch (NumberFormatException e) {
-						// some phones (notably the galaxy s7) do not provide width/height.
-						Bitmap bitmap = metaDataRetriever.getFrameAtTime(1);
-						if (bitmap != null) {
-							height = bitmap.getHeight();
-							width = bitmap.getWidth();
-						}
-					}
-
-					if (duration == 0 || height == 0 || width == 0) {
-						return;
-					}
-
-					// works with file URIs only
-					String path = FileUtil.getRealPathFromURI(ThreemaApplication.getAppContext(), mediaItem.getUri());
-					if (path != null) {
-						File f = new File(path);
-						videoFileSize = f.length();
-					}
-
-					if (videoItem.getStartTimeMs() < 0) {
-						videoItem.setStartTimeMs(0);
-					}
-					if (videoItem.getEndTimeMs() == MediaItem.TIME_UNDEFINED) {
-						videoItem.setEndTimeMs(duration);
-					}
-					videoItem.setDurationMs(duration);
-
-					offsetLeft = VideoEditView.this.getTimelinePositionFromVideoPosition(videoItem.getStartTimeMs());
-					offsetRight = timelineGridLayout.getWidth() - VideoEditView.this.getTimelinePositionFromVideoPosition(videoItem.getEndTimeMs());
-
-					RuntimeUtil.runOnUiThread(new Runnable() {
-						@Override
-						public void run() {
-							if (isAttachedToWindow()) {
-								updateStartAndEnd();
-							}
-						}
-					});
-
-					int numColumns = timelineGridLayout.getColumnCount();
-
-					if (numColumns != GridLayout.UNDEFINED) {
-						int step = (int) ((float) duration * 1000 / numColumns);
-
-						for (int i = 0; i < numColumns; i++) {
-							int position = i * step;
-
-							logger.debug("*** frame at position: " + position);
-
-							Bitmap bitmap = VideoTimelineCache.getInstance().get(mediaItem.getUri(), i);
-							if (bitmap == null) {
-								if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {
-									bitmap = metaDataRetriever.getFrameAtTime(position, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
-									if (bitmap.getWidth() > calculatedWidth || bitmap.getHeight() > targetHeight) {
-										bitmap = BitmapUtil.resizeBitmap(bitmap, calculatedWidth, targetHeight);
-									}
-								} else {
-									bitmap = metaDataRetriever.getScaledFrameAtTime(position, MediaMetadataRetriever.OPTION_CLOSEST_SYNC, calculatedWidth, targetHeight);
-								}
-
-								VideoTimelineCache.getInstance().set(mediaItem.getUri(), i, bitmap);
-
-								logger.debug("*** bitmap width: " + bitmap.getWidth() + " height: " + bitmap.getHeight());
-							}
-							final int column = i;
-							Bitmap finalBitmap = bitmap;
-
-							if (Thread.interrupted()) {
-								throw new InterruptedException();
-							} else {
-								RuntimeUtil.runOnUiThread(new Runnable() {
-									@Override
-									public void run() {
-										if (isAttachedToWindow()) {
-											ImageView imageView = findViewWithTag(column);
-											if (imageView != null) {
-												imageView.setImageBitmap(finalBitmap);
-											}
-										}
-									}
-								});
-							}
-						}
-					}
-				} catch (Exception e) {
-					if (!(e instanceof InterruptedException)) {
-						logger.error("Exception", e);
-					}
-				} finally {
-					metaDataRetriever.release();
-				}
+		if (numColumns != GridLayout.UNDEFINED) {
+			thumbnailThread = new Thread(
+			new VideoTimelineThumbnailTask(context,
+				videoItem,
+				numColumns,
+				calculatedWidth,
+				targetHeight,
+				this), THUMBNAIL_THREAD_NAME);
+
+			if (isAttachedToWindow() && context != null) {
+				thumbnailThread.start();
+				videoSourceMediaItem = com.google.android.exoplayer2.MediaItem.fromUri(videoItem.getUri());
+				preparePlayer();
 			}
-		}, THUMBNAIL_THREAD_NAME);
-
-		if (isAttachedToWindow() && context != null) {
-			thumbnailThread.start();
-
-			DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, context.getString(R.string.app_name)));
-			videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
-				.createMediaSource(com.google.android.exoplayer2.MediaItem.fromUri(videoItem.getUri()));
-
-			preparePlayer(false);
 		}
 	}
 
-	private void preparePlayer(boolean seekToEnd) {
-		if (videoPlayer != null && videoSource != null) {
+	private void preparePlayer() {
+		if (videoPlayer != null && videoSourceMediaItem != null) {
+			long startPosition = videoItem.getStartTimeMs() * 1000;
 			long endPosition = (videoItem.getEndTimeMs() == videoItem.getDurationMs() || videoItem.getEndTimeMs() == 0 || videoItem.getEndTimeMs() == MediaItem.TIME_UNDEFINED) ?
 							TIME_END_OF_SOURCE :
 							videoItem.getEndTimeMs() * 1000;
 
-			logger.debug("startPosition: " + (videoItem.getStartTimeMs() * 1000) + " endPosition: " + endPosition);
+			logger.debug("startPosition: " + startPosition + " endPosition: " + endPosition);
 
-			ClippingMediaSource clippingSource = new ClippingMediaSource(videoSource,
-					videoItem.getStartTimeMs() * 1000,
+			videoPlayer.setMediaItem(videoSourceMediaItem);
+			ClippingMediaSource clippingSource = new ClippingMediaSource(mediaSourceFactory.createMediaSource(videoSourceMediaItem),
+					startPosition,
 					endPosition);
+			isClipped = true;
 
 			if (videoPlayer.isLoading() || videoPlayer.isPlaying()) {
-				videoPlayer.stop(true);
+				videoPlayer.stop();
+				videoPlayer.clearMediaItems();
 			}
+
+			videoPlayer.setMediaSource(clippingSource);
 			videoPlayer.setPlayWhenReady(false);
-			videoPlayer.prepare(clippingSource);
-			if (seekToEnd) {
-				videoPlayer.seekTo(videoItem.getEndTimeMs());
-			}
+			videoPlayer.prepare();
 		}
 	}
 
@@ -589,12 +508,12 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 	}
 
 	@MainThread
-	private void updateStartAndEnd() {
-		startTimeTextView.setText(LocaleUtil.formatTimerText(videoItem.getStartTimeMs(), true));
-		endTimeTextView.setText(LocaleUtil.formatTimerText(videoItem.getEndTimeMs(), true));
+	private void updateStartAndEnd(long startTime, long endTime) {
+		startTimeTextView.setText(LocaleUtil.formatTimerText(startTime, true));
+		endTimeTextView.setText(LocaleUtil.formatTimerText(endTime, true));
 
 		if (videoFileSize > 0L) {
-			long croppedDurationMs = videoItem.getEndTimeMs() - videoItem.getStartTimeMs();
+			long croppedDurationMs = endTime - startTime;
 
 			long size = videoFileSize * croppedDurationMs / videoItem.getDurationMs();
 			sizeTextView.setText(Formatter.formatFileSize(context, size));
@@ -665,4 +584,44 @@ public class VideoEditView extends FrameLayout implements DefaultLifecycleObserv
 
 		this.context = null;
 	}
+
+	@Override
+	public boolean setThumbnail(int column, Bitmap thumbnail) {
+		if (isAttachedToWindow()) {
+			RuntimeUtil.runOnUiThread(() -> {
+				if (isAttachedToWindow()) {
+					ImageView imageView = findViewWithTag(column);
+					if (imageView != null) {
+						imageView.setImageBitmap(thumbnail);
+					}
+				}
+			});
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public void onMetadataReady() {
+		// works with file URIs only
+		String path = FileUtil.getRealPathFromURI(ThreemaApplication.getAppContext(), videoItem.getUri());
+		if (path != null) {
+			File f = new File(path);
+			videoFileSize = f.length();
+		}
+
+		offsetLeft = VideoEditView.this.getTimelinePositionFromVideoPosition(videoItem.getStartTimeMs());
+		offsetRight = timelineGridLayout.getWidth() - VideoEditView.this.getTimelinePositionFromVideoPosition(videoItem.getEndTimeMs());
+
+		RuntimeUtil.runOnUiThread(() -> {
+			if (isAttachedToWindow()) {
+				updateStartAndEnd(videoItem.getStartTimeMs(), videoItem.getEndTimeMs());
+			}
+		});
+	}
+
+	@Override
+	public void onError(String errorMessage) {
+		logger.info("Unable to get video thumbnails. Reason: {}", errorMessage);
+	}
 }

+ 3 - 2
app/src/main/java/ch/threema/app/dialogs/WizardDialog.java

@@ -28,10 +28,11 @@ import android.view.View;
 import android.widget.Button;
 import android.widget.TextView;
 
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
 import androidx.appcompat.app.AppCompatDialog;
 import androidx.core.content.res.ResourcesCompat;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import ch.threema.app.R;
 
 public class WizardDialog extends ThreemaDialogFragment {

+ 25 - 16
app/src/main/java/ch/threema/app/fragments/ComposeMessageFragment.java

@@ -69,6 +69,7 @@ import android.widget.RelativeLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.google.android.material.snackbar.BaseTransientBottomBar;
 import com.google.android.material.snackbar.Snackbar;
 
 import org.slf4j.Logger;
@@ -480,25 +481,25 @@ public class ComposeMessageFragment extends Fragment implements
 		}
 
 		@Override
-		public void onFinished(@NonNull String peerIdentity, boolean outgoing, int duration) {
+		public void onFinished(long callId, @NonNull String peerIdentity, boolean outgoing, int duration) {
 			logger.debug("VoipCallEventListener onFinished");
 			updateVoipCallMenuItem(true);
 		}
 
 		@Override
-		public void onRejected(String peerIdentity, boolean outgoing, byte reason) {
+		public void onRejected(long callId, String peerIdentity, boolean outgoing, byte reason) {
 			logger.debug("VoipCallEventListener onRejected");
 			updateVoipCallMenuItem(true);
 		}
 
 		@Override
-		public void onMissed(String peerIdentity, boolean accepted) {
+		public void onMissed(long callId, String peerIdentity, boolean accepted, @Nullable Date date) {
 			logger.debug("VoipCallEventListener onMissed");
 			updateVoipCallMenuItem(true);
 		}
 
 		@Override
-		public void onAborted(String peerIdentity) {
+		public void onAborted(long callId, String peerIdentity) {
 			logger.debug("VoipCallEventListener onAborted");
 			updateVoipCallMenuItem(true); }
 	};
@@ -1440,7 +1441,10 @@ public class ComposeMessageFragment extends Fragment implements
 						if (isQuotePanelShown() && abstractMessageModel.equals(quoteInfo.messageModel)) {
 							closeQuoteMode();
 						} else {
-							startQuoteMode(abstractMessageModel, () -> RuntimeUtil.runOnUiThread(() -> EditTextUtil.showSoftKeyboard(messageText)));
+							startQuoteMode(abstractMessageModel, () -> RuntimeUtil.runOnUiThread(() -> {
+								messageText.requestFocus();
+								EditTextUtil.showSoftKeyboard(messageText);
+							}));
 						}
 					}
 				}
@@ -2983,31 +2987,33 @@ public class ComposeMessageFragment extends Fragment implements
 	}
 
 	private void copySelectedMessagesToClipboard() {
-		AbstractMessageModel messageModel = selectedMessages.get(0);
-
-		if (messageModel == null) {
-			logger.error("no message model", activity);
+		if (selectedMessages.isEmpty()) {
+			logger.error("no selected messages");
 			return;
 		}
 
-		String body = "";
+		StringBuilder body = new StringBuilder();
 		for (AbstractMessageModel message : selectedMessages) {
 			if (body.length() > 0) {
-				body += "\n";
+				body.append("\n");
 			}
 
-			body += message.getType() == MessageType.TEXT ?
+			body.append(message.getType() == MessageType.TEXT ?
 				QuoteUtil.getMessageBody(message, false) :
-				message.getCaption();
+				message.getCaption());
 		}
 
 		try {
 			ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
 			if (clipboard != null) {
-				ClipData clipData = ClipData.newPlainText(null, body);
+				ClipData clipData = ClipData.newPlainText(null, body.toString());
 				if (clipData != null) {
 					clipboard.setPrimaryClip(clipData);
-					Snackbar.make(coordinatorLayout, R.string.message_copied, Snackbar.LENGTH_SHORT).show();
+					Snackbar.make(
+						coordinatorLayout,
+						getResources().getQuantityString(R.plurals.message_copied, selectedMessages.size()),
+						BaseTransientBottomBar.LENGTH_SHORT
+					).show();
 				}
 			}
 		} catch (Exception e) {
@@ -3918,7 +3924,10 @@ public class ComposeMessageFragment extends Fragment implements
 					mode.finish();
 					break;
 				case R.id.menu_message_quote:
-					startQuoteMode(null, null);
+					startQuoteMode(null, () -> RuntimeUtil.runOnUiThread(() -> {
+						messageText.requestFocus();
+						EditTextUtil.showSoftKeyboard(messageText);
+					}));
 					mode.finish();
 					break;
 				case R.id.menu_show_text:

+ 6 - 0
app/src/main/java/ch/threema/app/fragments/ContactsSectionFragment.java

@@ -109,6 +109,7 @@ import ch.threema.app.ui.SelectorDialogItem;
 import ch.threema.app.utils.AnimationUtil;
 import ch.threema.app.utils.BitmapUtil;
 import ch.threema.app.utils.ConfigUtils;
+import ch.threema.app.utils.EditTextUtil;
 import ch.threema.app.utils.IntentDataUtil;
 import ch.threema.app.utils.MimeUtil;
 import ch.threema.app.utils.NameUtil;
@@ -1075,6 +1076,11 @@ public class ContactsSectionFragment
 	}
 
 	private void openConversationForIdentity(@Nullable View v, String identity) {
+		// Close keyboard if search view is expanded
+		if (searchView != null && !searchView.isIconified()) {
+			EditTextUtil.hideSoftKeyboard(searchView);
+		}
+
 		Intent intent = new Intent(getActivity(), ComposeMessageActivity.class);
 		intent.putExtra(ThreemaApplication.INTENT_DATA_CONTACT, identity);
 		intent.putExtra(ThreemaApplication.INTENT_DATA_EDITFOCUS, Boolean.TRUE);

+ 38 - 30
app/src/main/java/ch/threema/app/fragments/MessageSectionFragment.java

@@ -34,6 +34,7 @@ import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
 import android.text.Html;
 import android.text.format.DateUtils;
@@ -46,16 +47,6 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Toast;
 
-import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
-import com.google.android.material.snackbar.Snackbar;
-
-import org.slf4j.Logger;
-
-import java.io.File;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
@@ -67,6 +58,17 @@ import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.SimpleItemAnimator;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
+
+import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.activities.ComposeMessageActivity;
@@ -102,7 +104,6 @@ import ch.threema.app.messagereceiver.GroupMessageReceiver;
 import ch.threema.app.messagereceiver.MessageReceiver;
 import ch.threema.app.preference.SettingsActivity;
 import ch.threema.app.routines.SynchronizeContactsRoutine;
-import ch.threema.app.services.AvatarCacheService;
 import ch.threema.app.services.ContactService;
 import ch.threema.app.services.ConversationService;
 import ch.threema.app.services.ConversationTagService;
@@ -123,6 +124,7 @@ import ch.threema.app.utils.AnimationUtil;
 import ch.threema.app.utils.AppRestrictionUtil;
 import ch.threema.app.utils.ConfigUtils;
 import ch.threema.app.utils.DialogUtil;
+import ch.threema.app.utils.EditTextUtil;
 import ch.threema.app.utils.FileUtil;
 import ch.threema.app.utils.HiddenChatUtil;
 import ch.threema.app.utils.IntentDataUtil;
@@ -191,7 +193,6 @@ public class MessageSectionFragment extends MainFragment
 
 	private ServiceManager serviceManager;
 	private ConversationService conversationService;
-	private AvatarCacheService avatarCacheService;
 	private ContactService contactService;
 	private GroupService groupService;
 	private MessageService messageService;
@@ -382,7 +383,6 @@ public class MessageSectionFragment extends MainFragment
 	protected boolean checkInstances() {
 		return TestUtil.required(
 				this.serviceManager,
-				this.avatarCacheService,
 				this.contactListener,
 				this.groupService,
 				this.conversationService,
@@ -401,7 +401,6 @@ public class MessageSectionFragment extends MainFragment
 
 		if (this.serviceManager != null) {
 			try {
-				this.avatarCacheService = this.serviceManager.getAvatarCacheService();
 				this.contactService = this.serviceManager.getContactService();
 				this.groupService = this.serviceManager.getGroupService();
 				this.messageService = this.serviceManager.getMessageService();
@@ -573,6 +572,11 @@ public class MessageSectionFragment extends MainFragment
 	private void showConversation(ConversationModel conversationModel, View v) {
 		conversationTagService.unTag(conversationModel, unreadTagModel);
 
+		// Close keyboard if search view is expanded
+		if (searchView != null && !searchView.isIconified()) {
+			EditTextUtil.hideSoftKeyboard(searchView);
+		}
+
 		Intent intent = IntentDataUtil.getShowConversationIntent(conversationModel, activity);
 
 		if (intent == null) {
@@ -869,7 +873,7 @@ public class MessageSectionFragment extends MainFragment
 						updateList(null, conversationModels, new Runnable() {
 							@Override
 							public void run() {
-								ListenerManager.conversationListeners.handle((ConversationListener listener) -> {
+								conversationListeners.handle((ConversationListener listener) -> {
 									listener.onModified(holder.getConversationModel(), oldPosition);
 								});
 							}
@@ -999,24 +1003,29 @@ public class MessageSectionFragment extends MainFragment
 					}
 				}
 			});
-			recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
-				private final int TOUCH_SAFE_AREA_PX = 5;
 
-				// ignore touches at the very left and right edge of the screen to prevent interference with UI gestures
-				@Override
-				public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
-					int width = getResources().getDisplayMetrics().widthPixels;
-					int touchX = (int) e.getRawX();
+			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getActivity() != null && getActivity().isInMultiWindowMode()) {
+				recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
+					private final int TOUCH_SAFE_AREA_PX = 5;
 
-					return touchX < TOUCH_SAFE_AREA_PX || touchX > width - TOUCH_SAFE_AREA_PX;
-				}
+					// ignore touches at the very left and right edge of the screen to prevent interference with UI gestures
+					@Override
+					public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
+						int width = getResources().getDisplayMetrics().widthPixels;
+						int touchX = (int) e.getRawX();
 
-				@Override
-				public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { }
+						return touchX < TOUCH_SAFE_AREA_PX || touchX > width - TOUCH_SAFE_AREA_PX;
+					}
 
-				@Override
-				public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
-			});
+					@Override
+					public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
+					}
+
+					@Override
+					public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+					}
+				});
+			}
 
 			//instantiate fragment
 			//
@@ -1473,7 +1482,6 @@ public class MessageSectionFragment extends MainFragment
 			logger.error("could not instantiate required objects");
 			return;
 		}
-
 		logger.debug("*** update list [" + scrollToPosition + ", " + (changedPositions != null ? changedPositions.size() : "0") + "]");
 
 		Thread updateListThread = new Thread(new Runnable() {

+ 5 - 5
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment1.java

@@ -21,6 +21,9 @@
 
 package ch.threema.app.fragments.wizard;
 
+import static ch.threema.app.threemasafe.ThreemaSafeServiceImpl.MAX_PW_LENGTH;
+import static ch.threema.app.threemasafe.ThreemaSafeServiceImpl.MIN_PW_LENGTH;
+
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -45,9 +48,6 @@ import ch.threema.app.utils.ConfigUtils;
 import ch.threema.app.utils.EditTextUtil;
 import ch.threema.app.utils.TestUtil;
 
-import static ch.threema.app.threemasafe.ThreemaSafeServiceImpl.MAX_PW_LENGTH;
-import static ch.threema.app.threemasafe.ThreemaSafeServiceImpl.MIN_PW_LENGTH;
-
 public class WizardFragment1 extends WizardFragment implements ThreemaSafeAdvancedDialog.WizardDialogCallback {
 	public static final int PAGE_ID = 1;
 
@@ -69,7 +69,7 @@ public class WizardFragment1 extends WizardFragment implements ThreemaSafeAdvanc
 		contentViewStub.setLayoutResource(R.layout.fragment_wizard1);
 		contentViewStub.inflate();
 
-		WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+		WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 
 		this.password1 = rootView.findViewById(R.id.safe_password1);
 		this.password2 = rootView.findViewById(R.id.safe_password2);
@@ -219,7 +219,7 @@ public class WizardFragment1 extends WizardFragment implements ThreemaSafeAdvanc
 
 	private void initValues() {
 		if (isResumed()) {
-			WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+			WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 			if (callback.isSafeEnabled()) {
 				password1.setText(callback.getSafePassword());
 				password2.setText(callback.getSafePassword());

+ 2 - 2
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment2.java

@@ -51,7 +51,7 @@ public class WizardFragment2 extends WizardFragment {
 							 Bundle savedInstanceState) {
 		View rootView = Objects.requireNonNull(super.onCreateView(inflater, container, savedInstanceState));
 
-		WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+		WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 
 		TextView title = rootView.findViewById(R.id.wizard_title);
 		title.setText(R.string.new_wizard_choose_nickname);
@@ -133,7 +133,7 @@ public class WizardFragment2 extends WizardFragment {
 
 	private void initValues() {
 		if (isResumed()) {
-			WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+			WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 			String nickname = callback.getNickname();
 			nicknameText.setText(nickname);
 			if (!TestUtil.empty(nickname)) {

+ 2 - 2
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment3.java

@@ -98,7 +98,7 @@ public class WizardFragment3 extends WizardFragment {
 		contentViewStub.setLayoutResource(R.layout.fragment_wizard3);
 		contentViewStub.inflate();
 
-		WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+		WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 
 		countrySpinner = rootView.findViewById(R.id.country_spinner);
 		emailEditText = rootView.findViewById(R.id.wizard_email);
@@ -435,7 +435,7 @@ public class WizardFragment3 extends WizardFragment {
 
 	void initValues() {
 		if (isResumed()) {
-			WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
+			WizardFragment4.SettingsInterface callback = (WizardFragment4.SettingsInterface) requireActivity();
 			emailEditText.setText(callback.getEmail());
 
 			if (TestUtil.empty(callback.getPresetEmail())) {

+ 161 - 60
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment4.java

@@ -21,73 +21,73 @@
 
 package ch.threema.app.fragments.wizard;
 
+import static ch.threema.app.ThreemaApplication.EMAIL_LINKED_PLACEHOLDER;
+import static ch.threema.app.ThreemaApplication.PHONE_LINKED_PLACEHOLDER;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.CompoundButton;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import java.util.Objects;
-
-import androidx.appcompat.widget.SwitchCompat;
 import ch.threema.app.R;
-import ch.threema.app.activities.wizard.WizardBaseActivity;
-import ch.threema.app.utils.AppRestrictionUtil;
+import ch.threema.app.dialogs.WizardDialog;
+import ch.threema.app.threemasafe.ThreemaSafeServerInfo;
 import ch.threema.app.utils.ConfigUtils;
-import ch.threema.app.utils.SynchronizeContactsUtil;
-
-public class WizardFragment4 extends WizardFragment {
-	private static boolean defaultSwitchValue = WizardBaseActivity.DEFAULT_SYNC_CONTACTS;
-	private SwitchCompat syncContactsSwitch;
+import ch.threema.app.utils.TestUtil;
+
+public class WizardFragment4 extends WizardFragment implements View.OnClickListener {
+	private TextView nicknameText, phoneText, emailText, syncContactsText, phoneWarnText, emailWarnText, safeText;
+	private ImageView phoneWarn, emailWarn;
+	private ProgressBar phoneProgress, emailProgress, syncContactsProgress, safeProgress;
+	private Button finishButton;
+	private SettingsInterface callback;
 	public static final int PAGE_ID = 4;
 
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 							 Bundle savedInstanceState) {
-		View rootView = Objects.requireNonNull(super.onCreateView(inflater, container, savedInstanceState));
-
-		TextView title = rootView.findViewById(R.id.wizard_title);
-		title.setText(R.string.new_wizard_find_friends);
-
-		// inflate content layout
-		contentViewStub.setLayoutResource(R.layout.fragment_wizard4);
-		contentViewStub.inflate();
+		View rootView = inflater.inflate(R.layout.fragment_wizard4, container, false);
+
+		nicknameText = rootView.findViewById(R.id.wizard_nickname_preset);
+		phoneText = rootView.findViewById(R.id.wizard_phone_preset);
+		emailText = rootView.findViewById(R.id.wizard_email_preset);
+		syncContactsText = rootView.findViewById(R.id.sync_contacts_preset);
+		syncContactsProgress = rootView.findViewById(R.id.wizard_contact_sync_progress);
+		phoneProgress = rootView.findViewById(R.id.wizard_phone_progress);
+		emailProgress = rootView.findViewById(R.id.wizard_email_progress);
+		phoneWarn = rootView.findViewById(R.id.wizard_phone_warn);
+		emailWarn = rootView.findViewById(R.id.wizard_email_warn);
+		phoneWarnText = rootView.findViewById(R.id.wizard_phone_error_text);
+		emailWarnText = rootView.findViewById(R.id.wizard_email_error_text);
+		safeText = rootView.findViewById(R.id.threema_safe_preset);
+		safeProgress = rootView.findViewById(R.id.threema_safe_progress);
+
+		finishButton = rootView.findViewById(R.id.wizard_finish);
+		finishButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				phoneText.setClickable(false);
+				emailText.setClickable(false);
+				callback.onWizardFinished(WizardFragment4.this, finishButton);
+				phoneText.setClickable(true);
+				emailText.setClickable(true);
+			}
+		});
 
-		syncContactsSwitch = rootView.findViewById(R.id.wizard_switch_sync_contacts);
+		emailText.setOnClickListener(this);
+		phoneText.setOnClickListener(this);
+		emailWarnText.setOnClickListener(this);
+		phoneWarnText.setOnClickListener(this);
 
-		if (ConfigUtils.isOnPremBuild() && ConfigUtils.isDemoOPServer(preferenceService)) {
-			defaultSwitchValue = false;
-			// Add another warning for dull-witted G**gle reviewers
-			TextView textView = rootView.findViewById(R.id.disabled_by_policy);
-			textView.setText(R.string.new_wizard_info_sync_contacts);
-			textView.setVisibility(View.VISIBLE);
-		}
-
-		Boolean contactSyncRestriction = AppRestrictionUtil.getBooleanRestriction(getString(R.string.restriction__contact_sync));
-
-		OnSettingsChangedListener settingsChangedListener = (OnSettingsChangedListener) requireActivity();
-		if (SynchronizeContactsUtil.isRestrictedProfile(requireActivity())) {
-			// restricted user profiles cannot add accounts
-			syncContactsSwitch.setChecked(false);
-			syncContactsSwitch.setEnabled(false);
-			settingsChangedListener.onSyncContactsSet(false);
-			rootView.findViewById(R.id.disabled_by_policy).setVisibility(View.VISIBLE);
-		} else {
-			if (contactSyncRestriction != null) {
-				syncContactsSwitch.setChecked(contactSyncRestriction);
-				syncContactsSwitch.setEnabled(false);
-				rootView.findViewById(R.id.disabled_by_policy).setVisibility(View.VISIBLE);
-			} else {
-				syncContactsSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-					@Override
-					public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-						settingsChangedListener.onSyncContactsSet(isChecked);
-					}
-				});
-				syncContactsSwitch.setChecked(defaultSwitchValue);
-				settingsChangedListener.onSyncContactsSet(defaultSwitchValue);
-			}
+		if (!ConfigUtils.isWorkBuild()) {
+			rootView.findViewById(R.id.wizard_email_layout).setVisibility(View.GONE);
+			rootView.findViewById(R.id.wizard_email_error_layout).setVisibility(View.GONE);
 		}
 
 		return rootView;
@@ -95,23 +95,124 @@ public class WizardFragment4 extends WizardFragment {
 
 	@Override
 	protected int getAdditionalInfoText() {
-		return R.string.new_wizard_info_sync_contacts;
+		return 0;
+	}
+
+	@Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
+		callback = (SettingsInterface) activity;
+	}
+
+	void initValues() {
+		if (isResumed()) {
+			String email = callback.getEmail();
+			String phone = callback.getPhone();
+
+			nicknameText.setText(callback.getNickname());
+			emailText.setText(TestUtil.empty(email) ? getString(R.string.not_linked) : EMAIL_LINKED_PLACEHOLDER.equals(email) ? getString(R.string.unchanged) : email);
+			phoneText.setText(TestUtil.empty(phone) ? getString(R.string.not_linked) : PHONE_LINKED_PLACEHOLDER.equals(phone) ? getString(R.string.unchanged) : phone);
+			syncContactsText.setText(callback.getSyncContacts() ? R.string.on : R.string.off);
+			setThreemaSafeInProgress(false, null);
+		}
 	}
 
 	@Override
-	public void onResume() {
+	@SuppressLint("NewApi")
+	public void onResume () {
 		super.onResume();
+
 		initValues();
+
+		if (ConfigUtils.isWorkRestricted() && callback.isSkipWizard()) {
+			finishButton.callOnClick();
+		}
 	}
 
-	void initValues() {
-		if (isResumed() && ConfigUtils.isWorkRestricted()) {
-			WizardFragment5.SettingsInterface callback = (WizardFragment5.SettingsInterface) requireActivity();
-			syncContactsSwitch.setChecked(callback.getSyncContacts());
+	@Override
+	public void onClick(View v) {
+		int id = v.getId();
+		if (id == R.id.wizard_phone_error_text) {
+			WizardDialog.newInstance(phoneWarnText.getText().toString(), R.string.ok).show(getFragmentManager(), "ph");
+		} else if (id == R.id.wizard_email_error_text) {
+			WizardDialog.newInstance(emailWarnText.getText().toString(), R.string.ok).show(getFragmentManager(), "em");
+		} else if (id == R.id.wizard_email_preset || id == R.id.wizard_phone_preset) {
+			setPage(2);
+		}
+	}
+
+	public void setMobileLinkingInProgress(boolean inProgress) {
+		phoneWarn.setVisibility(View.GONE);
+		phoneProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
+		phoneWarnText.setVisibility(View.GONE);
+		phoneText.setVisibility(inProgress ? View.GONE : View.VISIBLE);
+	}
+
+	public void setEmailLinkingInProgress(boolean inProgress) {
+		emailWarn.setVisibility(View.GONE);
+		emailProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
+		emailWarnText.setVisibility(View.GONE);
+		emailText.setVisibility(inProgress ? View.GONE : View.VISIBLE);
+	}
+
+	public void setMobileLinkingAlert(String message) {
+		phoneWarn.setVisibility(View.VISIBLE);
+		phoneWarnText.setText(message);
+		phoneWarnText.setVisibility(View.VISIBLE);
+		phoneProgress.setVisibility(View.GONE);
+		phoneText.setVisibility(View.VISIBLE);
+	}
+
+	public void setEmailLinkingAlert(String message) {
+		emailWarn.setVisibility(View.VISIBLE);
+		emailWarnText.setText(message);
+		emailWarnText.setVisibility(View.VISIBLE);
+		emailProgress.setVisibility(View.GONE);
+		emailText.setVisibility(View.VISIBLE);
+	}
+
+	public void setContactsSyncInProgress(boolean inProgress, String text) {
+		syncContactsProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
+		if (TestUtil.empty(text)) {
+			syncContactsText.setText(callback.getSyncContacts() ? R.string.on : R.string.off);
+		} else {
+			syncContactsText.setText(text);
+		}
+	}
+
+	public void setThreemaSafeInProgress(boolean inProgress, String text) {
+		safeProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
+		if (TestUtil.empty(text)) {
+			if (TestUtil.empty(callback.getSafePassword())) {
+				safeText.setText(R.string.off);
+			} else {
+				if (callback.getSafeServerInfo().isDefaultServer()) {
+					safeText.setText(getString(R.string.on));
+				} else {
+					safeText.setText(String.format("%s - %s", getString(R.string.on), callback.getSafeServerInfo().getHostName()));
+				}
+			}
+		} else {
+			safeText.setText(text);
 		}
 	}
 
-	public interface OnSettingsChangedListener {
-		void onSyncContactsSet(boolean enabled);
+	public interface SettingsInterface {
+		String getNickname();
+		String getPhone();
+		String getPrefix();
+		String getNumber();
+		String getEmail();
+		String getPresetPhone();
+		String getPresetEmail();
+		boolean getSafeForcePasswordEntry();
+		boolean getSafeSkipBackupPasswordEntry();
+		boolean isSafeEnabled();
+		String getSafePassword();
+		ThreemaSafeServerInfo getSafeServerInfo();
+		boolean getSyncContacts();
+		boolean isReadOnlyProfile();
+		boolean isSkipWizard();
+		void onWizardFinished(WizardFragment4 fragment, Button finishButton);
 	}
 }

+ 0 - 224
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment5.java

@@ -1,224 +0,0 @@
-/*  _____ _
- * |_   _| |_  _ _ ___ ___ _ __  __ _
- *   | | | ' \| '_/ -_) -_) '  \/ _` |_
- *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
- *
- * Threema for Android
- * Copyright (c) 2015-2022 Threema GmbH
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-package ch.threema.app.fragments.wizard;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import ch.threema.app.R;
-import ch.threema.app.dialogs.WizardDialog;
-import ch.threema.app.threemasafe.ThreemaSafeServerInfo;
-import ch.threema.app.utils.ConfigUtils;
-import ch.threema.app.utils.TestUtil;
-
-import static ch.threema.app.ThreemaApplication.EMAIL_LINKED_PLACEHOLDER;
-import static ch.threema.app.ThreemaApplication.PHONE_LINKED_PLACEHOLDER;
-
-public class WizardFragment5 extends WizardFragment implements View.OnClickListener {
-	private TextView nicknameText, phoneText, emailText, syncContactsText, phoneWarnText, emailWarnText, safeText;
-	private ImageView phoneWarn, emailWarn;
-	private ProgressBar phoneProgress, emailProgress, syncContactsProgress, safeProgress;
-	private Button finishButton;
-	private SettingsInterface callback;
-	public static final int PAGE_ID = 5;
-
-	@Override
-	public View onCreateView(LayoutInflater inflater, ViewGroup container,
-							 Bundle savedInstanceState) {
-		View rootView = inflater.inflate(R.layout.fragment_wizard5, container, false);
-
-		nicknameText = rootView.findViewById(R.id.wizard_nickname_preset);
-		phoneText = rootView.findViewById(R.id.wizard_phone_preset);
-		emailText = rootView.findViewById(R.id.wizard_email_preset);
-		syncContactsText = rootView.findViewById(R.id.sync_contacts_preset);
-		syncContactsProgress = rootView.findViewById(R.id.wizard_contact_sync_progress);
-		phoneProgress = rootView.findViewById(R.id.wizard_phone_progress);
-		emailProgress = rootView.findViewById(R.id.wizard_email_progress);
-		phoneWarn = rootView.findViewById(R.id.wizard_phone_warn);
-		emailWarn = rootView.findViewById(R.id.wizard_email_warn);
-		phoneWarnText = rootView.findViewById(R.id.wizard_phone_error_text);
-		emailWarnText = rootView.findViewById(R.id.wizard_email_error_text);
-		safeText = rootView.findViewById(R.id.threema_safe_preset);
-		safeProgress = rootView.findViewById(R.id.threema_safe_progress);
-
-		finishButton = rootView.findViewById(R.id.wizard_finish);
-		finishButton.setOnClickListener(new View.OnClickListener() {
-			@Override
-			public void onClick(View v) {
-				phoneText.setClickable(false);
-				emailText.setClickable(false);
-				callback.onWizardFinished(WizardFragment5.this, finishButton);
-				phoneText.setClickable(true);
-				emailText.setClickable(true);
-			}
-		});
-
-		emailText.setOnClickListener(this);
-		phoneText.setOnClickListener(this);
-		emailWarnText.setOnClickListener(this);
-		phoneWarnText.setOnClickListener(this);
-
-		if (!ConfigUtils.isWorkBuild()) {
-			rootView.findViewById(R.id.wizard_email_layout).setVisibility(View.GONE);
-			rootView.findViewById(R.id.wizard_email_error_layout).setVisibility(View.GONE);
-		}
-
-		return rootView;
-	}
-
-	@Override
-	protected int getAdditionalInfoText() {
-		return 0;
-	}
-
-	@Override
-	public void onAttach(Activity activity) {
-		super.onAttach(activity);
-		callback = (SettingsInterface) activity;
-	}
-
-	void initValues() {
-		if (isResumed()) {
-			String email = callback.getEmail();
-			String phone = callback.getPhone();
-
-			nicknameText.setText(callback.getNickname());
-			emailText.setText(TestUtil.empty(email) ? getString(R.string.not_linked) : EMAIL_LINKED_PLACEHOLDER.equals(email) ? getString(R.string.unchanged) : email);
-			phoneText.setText(TestUtil.empty(phone) ? getString(R.string.not_linked) : PHONE_LINKED_PLACEHOLDER.equals(phone) ? getString(R.string.unchanged) : phone);
-			syncContactsText.setText(callback.getSyncContacts() ? R.string.on : R.string.off);
-			setThreemaSafeInProgress(false, null);
-		}
-	}
-
-	@Override
-	@SuppressLint("NewApi")
-	public void onResume () {
-		super.onResume();
-
-		initValues();
-
-		if (ConfigUtils.isWorkRestricted() && callback.isSkipWizard()) {
-			finishButton.callOnClick();
-		}
-	}
-
-	@Override
-	public void onClick(View v) {
-		switch(v.getId()) {
-			case R.id.wizard_phone_error_text:
-				WizardDialog.newInstance(phoneWarnText.getText().toString(), R.string.ok).show(getFragmentManager(),"ph");
-				break;
-			case R.id.wizard_email_error_text:
-				WizardDialog.newInstance(emailWarnText.getText().toString(), R.string.ok).show(getFragmentManager(), "em");
-				break;
-			case R.id.wizard_email_preset:
-			case R.id.wizard_phone_preset:
-				setPage(2);
-				break;
-			default:
-				break;
-		}
-	}
-
-	public void setMobileLinkingInProgress(boolean inProgress) {
-		phoneWarn.setVisibility(View.GONE);
-		phoneProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
-		phoneWarnText.setVisibility(View.GONE);
-		phoneText.setVisibility(inProgress ? View.GONE : View.VISIBLE);
-	}
-
-	public void setEmailLinkingInProgress(boolean inProgress) {
-		emailWarn.setVisibility(View.GONE);
-		emailProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
-		emailWarnText.setVisibility(View.GONE);
-		emailText.setVisibility(inProgress ? View.GONE : View.VISIBLE);
-	}
-
-	public void setMobileLinkingAlert(String message) {
-		phoneWarn.setVisibility(View.VISIBLE);
-		phoneWarnText.setText(message);
-		phoneWarnText.setVisibility(View.VISIBLE);
-		phoneProgress.setVisibility(View.GONE);
-		phoneText.setVisibility(View.VISIBLE);
-	}
-
-	public void setEmailLinkingAlert(String message) {
-		emailWarn.setVisibility(View.VISIBLE);
-		emailWarnText.setText(message);
-		emailWarnText.setVisibility(View.VISIBLE);
-		emailProgress.setVisibility(View.GONE);
-		emailText.setVisibility(View.VISIBLE);
-	}
-
-	public void setContactsSyncInProgress(boolean inProgress, String text) {
-		syncContactsProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
-		if (TestUtil.empty(text)) {
-			syncContactsText.setText(callback.getSyncContacts() ? R.string.on : R.string.off);
-		} else {
-			syncContactsText.setText(text);
-		}
-	}
-
-	public void setThreemaSafeInProgress(boolean inProgress, String text) {
-		safeProgress.setVisibility(inProgress ? View.VISIBLE : View.GONE);
-		if (TestUtil.empty(text)) {
-			if (TestUtil.empty(callback.getSafePassword())) {
-				safeText.setText(R.string.off);
-			} else {
-				if (callback.getSafeServerInfo().isDefaultServer()) {
-					safeText.setText(getString(R.string.on));
-				} else {
-					safeText.setText(String.format("%s - %s", getString(R.string.on), callback.getSafeServerInfo().getHostName()));
-				}
-			}
-		} else {
-			safeText.setText(text);
-		}
-	}
-
-	public interface SettingsInterface {
-		String getNickname();
-		String getPhone();
-		String getPrefix();
-		String getNumber();
-		String getEmail();
-		String getPresetPhone();
-		String getPresetEmail();
-		boolean getSafeForcePasswordEntry();
-		boolean getSafeSkipBackupPasswordEntry();
-		boolean isSafeEnabled();
-		String getSafePassword();
-		ThreemaSafeServerInfo getSafeServerInfo();
-		boolean getSyncContacts();
-		boolean isReadOnlyProfile();
-		boolean isSkipWizard();
-		void onWizardFinished(WizardFragment5 fragment, Button finishButton);
-	}
-}

+ 3 - 3
app/src/main/java/ch/threema/app/managers/ServiceManager.java

@@ -23,13 +23,14 @@ package ch.threema.app.managers;
 
 import android.content.Context;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import org.apache.commons.io.Charsets;
 import org.slf4j.Logger;
 
 import java.util.Locale;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import ch.threema.app.BuildFlavor;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.backuprestore.BackupChatService;
@@ -518,7 +519,6 @@ public class ServiceManager {
 	public BackupRestoreDataService getBackupRestoreDataService() throws FileSystemNotPresentException {
 		if(this.backupRestoreDataService == null) {
 			this.backupRestoreDataService = new BackupRestoreDataServiceImpl(
-					this.getContext(),
 					this.getFileService());
 		}
 

+ 11 - 0
app/src/main/java/ch/threema/app/messagereceiver/ContactMessageReceiver.java

@@ -334,6 +334,17 @@ public class ContactMessageReceiver implements MessageReceiver<MessageModel> {
 				filter);
 	}
 
+	/**
+	 * Check if there is a call among the latest calls with the given call id.
+	 *
+	 * @param callId the call id
+	 * @param limit the maximum number of latest calls
+	 * @return {@code true} if there is a call with the given id within the latest calls, {@code false} otherwise
+	 */
+	public boolean hasVoipCallStatus(long callId, int limit) {
+		return databaseServiceNew.getMessageModelFactory().hasVoipStatusForCallId(contactModel.getIdentity(), callId, limit);
+	}
+
 	@Override
 	public long getMessagesCount() {
 		return databaseServiceNew.getMessageModelFactory().countMessages(

+ 8 - 0
app/src/main/java/ch/threema/app/preference/SettingsCallsFragment.kt

@@ -55,6 +55,7 @@ class SettingsCallsFragment : ThreemaPreferenceFragment() {
             val callEnable: CheckBoxPreference = getPref(R.string.preferences__voip_enable)
             val disableCalls = AppRestrictionUtil.getBooleanRestriction(resources.getString(R.string.restriction__disable_calls))
             var disableVideoCalls = AppRestrictionUtil.getBooleanRestriction(resources.getString(R.string.restriction__disable_video_calls))
+
             if (disableCalls != null) {
                 // admin does not want user to tamper with call setting
                 callEnable.isEnabled = false
@@ -63,6 +64,13 @@ class SettingsCallsFragment : ThreemaPreferenceFragment() {
                 if (disableCalls) {
                     // disabled calls also disable video calls
                     disableVideoCalls = true
+                } else {
+                    // remove dependency to allow user to manipulate advanced call settings if admin enabled calls
+                    val forceTurn: CheckBoxPreference = getPref(R.string.preferences__voip_force_turn)
+                    val rejectCalls: CheckBoxPreference = getPref(R.string.preferences__voip_reject_mobile_calls)
+
+                    forceTurn.dependency = null
+                    rejectCalls.dependency = null
                 }
             }
 

+ 12 - 10
app/src/main/java/ch/threema/app/preference/SettingsDeveloperFragment.java

@@ -54,6 +54,8 @@ import ch.threema.storage.DatabaseServiceNew;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.data.status.VoipStatusDataModel;
 
+import static ch.threema.storage.models.data.status.VoipStatusDataModel.NO_CALL_ID;
+
 @SuppressWarnings("unused")
 public class SettingsDeveloperFragment extends ThreemaPreferenceFragment {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("SettingsDeveloperFragment");
@@ -134,16 +136,16 @@ public class SettingsDeveloperFragment extends ThreemaPreferenceFragment {
 
 		// Test messages
 		final VoipMessage[] testMessages = new VoipMessage[]{
-			new VoipMessage(VoipStatusDataModel.createMissed(), "missed"),
-			new VoipMessage(VoipStatusDataModel.createFinished(42), "finished"),
-			new VoipMessage(VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.UNKNOWN), "rejected (unknown)"),
-			new VoipMessage(VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.BUSY), "rejected (busy)"),
-			new VoipMessage(VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.TIMEOUT), "rejected (timeout)"),
-			new VoipMessage(VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.REJECTED), "rejected (rejected)"),
-			new VoipMessage(VoipStatusDataModel.createRejected(VoipCallAnswerData.RejectReason.DISABLED), "rejected (disabled)"),
-			new VoipMessage(VoipStatusDataModel.createRejected((byte) 99), "rejected (invalid reason code)"),
-			new VoipMessage(VoipStatusDataModel.createRejected(null), "rejected (null reason code)"),
-			new VoipMessage(VoipStatusDataModel.createAborted(), "aborted"),
+			new VoipMessage(VoipStatusDataModel.createMissed(NO_CALL_ID, null), "missed"),
+			new VoipMessage(VoipStatusDataModel.createFinished(NO_CALL_ID,42), "finished"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.UNKNOWN), "rejected (unknown)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.BUSY), "rejected (busy)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.TIMEOUT), "rejected (timeout)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.REJECTED), "rejected (rejected)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, VoipCallAnswerData.RejectReason.DISABLED), "rejected (disabled)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID, (byte) 99), "rejected (invalid reason code)"),
+			new VoipMessage(VoipStatusDataModel.createRejected(NO_CALL_ID,null), "rejected (null reason code)"),
+			new VoipMessage(VoipStatusDataModel.createAborted(NO_CALL_ID), "aborted"),
 		};
 
 		new AsyncTask<Void, Void, Exception>() {

+ 20 - 1
app/src/main/java/ch/threema/app/services/AppRestrictionService.java

@@ -51,6 +51,7 @@ public class AppRestrictionService {
 
 	private Bundle appRestrictions;
 	private volatile WorkMDMSettings workMDMSettings;
+	private boolean hasExternalMDMRestrictions;
 	private static final String PREFERENCE_KEY = "wrk_app_restriction";
 
 	/**
@@ -88,6 +89,22 @@ public class AppRestrictionService {
 		return this.workMDMSettings;
 	}
 
+	/**
+	 * Determine if this app is under control of Threema MDM and has at least one parameter set
+	 * @return true if Threema MDM is active
+	 */
+	public boolean hasThreemaMDMRestrictions() {
+		return this.workMDMSettings != null && this.workMDMSettings.parameters != null && this.workMDMSettings.parameters.size() > 0;
+	}
+
+	/**
+	 * Determine if this app is under control of an external MDM/EMM with a local DPC and at least one parameter set
+	 * @return true if an external MDM is active
+	 */
+	public boolean hasExternalMDMRestrictions() {
+		return this.hasExternalMDMRestrictions;
+	}
+
 	/**
 	 * Fetch the MDM Settings
 	 */
@@ -126,9 +143,11 @@ public class AppRestrictionService {
 			this.appRestrictions = new Bundle();
 		}
 
+		hasExternalMDMRestrictions = this.appRestrictions.size() > 0;
+
 		WorkMDMSettings settings = this.getWorkMDMSettings();
 
-		// Get Mini MDM Settings and override
+		// Get Threema MDM Settings and override
 		if (settings != null) {
 			for(Map.Entry<String, Object> miniMDMSetting: settings.parameters.entrySet()) {
 				if (settings.override

+ 4 - 8
app/src/main/java/ch/threema/app/services/ConversationServiceImpl.java

@@ -41,6 +41,7 @@ import ch.threema.app.messagereceiver.DistributionListMessageReceiver;
 import ch.threema.app.messagereceiver.GroupMessageReceiver;
 import ch.threema.app.messagereceiver.MessageReceiver;
 import ch.threema.app.utils.MessageUtil;
+import ch.threema.app.utils.StringConversionUtil;
 import ch.threema.app.utils.TestUtil;
 import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.DatabaseServiceNew;
@@ -192,7 +193,7 @@ public class ConversationServiceImpl implements ConversationService {
 					filtered = Functional.filter(filtered, new IPredicateNonNull<ConversationModel>() {
 						@Override
 						public boolean apply(@NonNull ConversationModel conversationModel) {
-							return TestUtil.contains(filter.filterQuery(), conversationModel.getReceiver().getDisplayName());
+							return TestUtil.matchesConversationSearch(filter.filterQuery(), conversationModel.getReceiver().getDisplayName());
 						}
 					});
 				}
@@ -631,15 +632,10 @@ public class ConversationServiceImpl implements ConversationService {
 			List<ConversationResult> res = this.selectAll(true);
 
 			if (!TestUtil.empty(constraint)) {
-				constraint = constraint.toLowerCase();
 				for(ConversationResult r: res) {
 					ConversationModel conversationModel = this.parseResult(r, null, false);
-					String title = conversationModel.toString();
-
-					if (!TestUtil.empty(title)) {
-						if (title.toLowerCase().contains(constraint)) {
-							conversationModels.add(conversationModel);
-						}
+					if (TestUtil.matchesConversationSearch(constraint, conversationModel.toString())) {
+						conversationModels.add(conversationModel);
 					}
 				}
 			} else {

+ 12 - 11
app/src/main/java/ch/threema/app/services/FileServiceImpl.java

@@ -44,6 +44,15 @@ import android.view.View;
 import android.webkit.MimeTypeMap;
 import android.widget.Toast;
 
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+import androidx.annotation.WorkerThread;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.preference.PreferenceManager;
+
 import com.google.android.material.snackbar.Snackbar;
 
 import org.apache.commons.io.FileUtils;
@@ -72,14 +81,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import javax.crypto.CipherInputStream;
 import javax.crypto.CipherOutputStream;
 
-import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresPermission;
-import androidx.annotation.WorkerThread;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.content.res.AppCompatResources;
-import androidx.preference.PreferenceManager;
 import ch.threema.app.BuildConfig;
 import ch.threema.app.NamedFileProvider;
 import ch.threema.app.R;
@@ -564,12 +565,12 @@ public class FileServiceImpl implements FileService {
 		try {
 			is = getDecryptedMessageStream(messageModel);
 			if (is != null) {
-				File decoded = this.createTempFile(messageModel.getId() + "" + messageModel.getCreatedAt().getTime(), ext, false);
-				fos = new FileOutputStream(decoded);
+				File decrypted = this.createTempFile(messageModel.getId() + "" + messageModel.getCreatedAt().getTime(), ext, false);
+				fos = new FileOutputStream(decrypted);
 
 				IOUtils.copy(is, fos);
 
-				return decoded;
+				return decrypted;
 			}
 		} finally {
 			if (fos != null) {

+ 39 - 37
app/src/main/java/ch/threema/app/services/MessageServiceImpl.java

@@ -21,6 +21,21 @@
 
 package ch.threema.app.services;
 
+import static ch.threema.app.ThreemaApplication.MAX_BLOB_SIZE;
+import static ch.threema.app.ThreemaApplication.MAX_BLOB_SIZE_MB;
+import static ch.threema.app.services.PreferenceService.ImageScale_DEFAULT;
+import static ch.threema.app.ui.MediaItem.TIME_UNDEFINED;
+import static ch.threema.app.ui.MediaItem.TYPE_FILE;
+import static ch.threema.app.ui.MediaItem.TYPE_GIF;
+import static ch.threema.app.ui.MediaItem.TYPE_IMAGE;
+import static ch.threema.app.ui.MediaItem.TYPE_IMAGE_CAM;
+import static ch.threema.app.ui.MediaItem.TYPE_LOCATION;
+import static ch.threema.app.ui.MediaItem.TYPE_TEXT;
+import static ch.threema.app.ui.MediaItem.TYPE_VIDEO;
+import static ch.threema.app.ui.MediaItem.TYPE_VIDEO_CAM;
+import static ch.threema.app.ui.MediaItem.TYPE_VOICEMESSAGE;
+import static ch.threema.domain.protocol.csp.messages.file.FileData.RENDERING_STICKER;
+
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
@@ -41,6 +56,13 @@ import android.text.format.DateUtils;
 import android.util.SparseIntArray;
 import android.widget.Toast;
 
+import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.collection.ArrayMap;
+import androidx.core.app.NotificationManagerCompat;
+
 import com.neilalexander.jnacl.NaCl;
 
 import org.apache.commons.io.IOUtils;
@@ -74,12 +96,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import javax.crypto.CipherInputStream;
 import javax.crypto.CipherOutputStream;
 
-import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-import androidx.collection.ArrayMap;
-import androidx.core.app.NotificationManagerCompat;
 import ch.threema.app.BuildConfig;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
@@ -181,21 +197,6 @@ import ch.threema.storage.models.data.media.MediaMessageDataInterface;
 import ch.threema.storage.models.data.media.VideoDataModel;
 import ch.threema.storage.models.data.status.VoipStatusDataModel;
 
-import static ch.threema.app.ThreemaApplication.MAX_BLOB_SIZE;
-import static ch.threema.app.ThreemaApplication.MAX_BLOB_SIZE_MB;
-import static ch.threema.app.services.PreferenceService.ImageScale_DEFAULT;
-import static ch.threema.app.ui.MediaItem.TIME_UNDEFINED;
-import static ch.threema.app.ui.MediaItem.TYPE_FILE;
-import static ch.threema.app.ui.MediaItem.TYPE_GIF;
-import static ch.threema.app.ui.MediaItem.TYPE_IMAGE;
-import static ch.threema.app.ui.MediaItem.TYPE_IMAGE_CAM;
-import static ch.threema.app.ui.MediaItem.TYPE_LOCATION;
-import static ch.threema.app.ui.MediaItem.TYPE_TEXT;
-import static ch.threema.app.ui.MediaItem.TYPE_VIDEO;
-import static ch.threema.app.ui.MediaItem.TYPE_VIDEO_CAM;
-import static ch.threema.app.ui.MediaItem.TYPE_VOICEMESSAGE;
-import static ch.threema.domain.protocol.csp.messages.file.FileData.RENDERING_STICKER;
-
 public class MessageServiceImpl implements MessageService {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("MessageServiceImpl");
 
@@ -358,7 +359,7 @@ public class MessageServiceImpl implements MessageService {
 		final AbstractMessageModel model = receiver.createLocalModel(
 			MessageType.VOIP_STATUS,
 			MessageContentsType.VOIP_STATUS,
-			new Date()
+			data.getDate() != null ? data.getDate() : new Date()
 		);
 		model.setOutbox(isOutbox);
 		model.setVoipStatusData(data);
@@ -2271,26 +2272,27 @@ public class MessageServiceImpl implements MessageService {
 	private boolean saveStrippedImage(byte[] image, AbstractMessageModel messageModel) throws Exception {
 		boolean success = true;
 
-		// extract caption from exif data and strip all metadata, if any
+		// extract caption from exif data (legacy image format only) and strip all metadata, if any
 		try (ByteArrayOutputStream strippedImageOS = new ByteArrayOutputStream()) {
 			try (ByteArrayInputStream originalImageIS = new ByteArrayInputStream(image)) {
 				ExifInterface originalImageExif = new ExifInterface(originalImageIS);
+				if (messageModel.getType() == MessageType.IMAGE) {
+					String caption = originalImageExif.getUTF8StringAttribute(ExifInterface.TAG_ARTIST);
 
-				String caption = originalImageExif.getUTF8StringAttribute(ExifInterface.TAG_ARTIST);
-
-				if (TestUtil.empty(caption)) {
-					caption = originalImageExif.getUTF8StringAttribute(ExifInterface.TAG_USER_COMMENT);
-				}
+					if (TestUtil.empty(caption)) {
+						caption = originalImageExif.getUTF8StringAttribute(ExifInterface.TAG_USER_COMMENT);
+					}
 
-				if (!TestUtil.empty(caption)) {
-					// strip trailing zero character from EXIF, if any
-					if (caption.charAt(caption.length() - 1) == '\u0000') {
-						caption = caption.substring(0, caption.length() - 1);
+					if (!TestUtil.empty(caption)) {
+						// strip trailing zero character from EXIF, if any
+						if (caption.charAt(caption.length() - 1) == '\u0000') {
+							caption = caption.substring(0, caption.length() - 1);
+						}
+						messageModel.setCaption(caption);
 					}
-					messageModel.setCaption(caption);
-				}
 
-				originalImageIS.reset();
+					originalImageIS.reset();
+				}
 				// strip all exif data while saving
 				originalImageExif.saveAttributes(originalImageIS, strippedImageOS, true);
 			} catch (IOException e) {
@@ -4133,7 +4135,7 @@ public class MessageServiceImpl implements MessageService {
 			messageModel.setState(MessageState.PENDING); // shows a progress bar
 			messageModel.setFileData(fileDataModel);
 			messageModel.setCorrelationId(correlationId);
-			messageModel.setCaption(mediaItem.getCaption());
+			messageModel.setCaption(mediaItem.getTrimmedCaption());
 			messageModel.setSaved(true);
 
 			messageReceiver.saveLocalModel(messageModel);
@@ -4235,7 +4237,7 @@ public class MessageServiceImpl implements MessageService {
 			0,
 			filename,
 			renderingType,
-			mediaItem.getCaption(),
+			mediaItem.getTrimmedCaption(),
 			true,
 			null);
 	}

+ 10 - 0
app/src/main/java/ch/threema/app/services/ServerAddressProviderServiceImpl.java

@@ -130,6 +130,16 @@ public class ServerAddressProviderServiceImpl implements ServerAddressProviderSe
 			public String getWebServerUrl() throws ThreemaException {
 				return BuildConfig.WEB_SERVER_URL;
 			}
+
+			@Override
+			public String getWebOverrideSaltyRtcHost() throws ThreemaException {
+				return null;
+			}
+
+			@Override
+			public int getWebOverrideSaltyRtcPort() throws ThreemaException {
+				return 0;
+			}
 		};
 	}
 

+ 6 - 6
app/src/main/java/ch/threema/app/services/messageplayer/AudioMessagePlayer.java

@@ -30,11 +30,12 @@ import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.Build;
 
+import androidx.core.content.ContextCompat;
+
 import org.slf4j.Logger;
 
 import java.io.File;
 
-import androidx.core.content.ContextCompat;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.listeners.SensorListener;
@@ -59,9 +60,8 @@ import static android.media.AudioManager.STREAM_MUSIC;
 
 public class AudioMessagePlayer extends MessagePlayer implements AudioManager.OnAudioFocusChangeListener, SensorListener {
 	private final Logger logger = LoggingUtil.getThreemaLogger("AudioMessagePlayer");
-	private final String UID;
 
-	private final int SEEKBAR_UPDATE_FREQUENCY = 500;
+	private static final int SEEKBAR_UPDATE_FREQUENCY = 250;
 	private MediaPlayerStateWrapper mediaPlayer;
 	private File decryptedFile = null;
 	private int duration = 0;
@@ -90,12 +90,12 @@ public class AudioMessagePlayer extends MessagePlayer implements AudioManager.On
 		this.mediaPlayer = null;
 		this.micPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
 
-		this.UID = messageModel.getUid();
-		logger.info("New MediaPlayer instance: {}", this.UID);
+		String UID = messageModel.getUid();
+		logger.info("New MediaPlayer instance: {}", UID);
 
 		// Set logger prefix
 		if (logger instanceof ThreemaLogger) {
-			((ThreemaLogger) logger).setPrefix(String.valueOf(this.UID));
+			((ThreemaLogger) logger).setPrefix(String.valueOf(UID));
 		}
 	}
 

+ 19 - 0
app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeConfigureActivity.java

@@ -27,6 +27,7 @@ import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.MenuItem;
@@ -45,6 +46,7 @@ import androidx.annotation.WorkerThread;
 import androidx.appcompat.app.ActionBar;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
+import ch.threema.app.activities.HomeActivity;
 import ch.threema.app.activities.ThreemaToolbarActivity;
 import ch.threema.app.dialogs.GenericAlertDialog;
 import ch.threema.app.dialogs.GenericProgressDialog;
@@ -68,6 +70,7 @@ public class ThreemaSafeConfigureActivity extends ThreemaToolbarActivity impleme
 
 	public static final String EXTRA_CHANGE_PASSWORD = "cp";
 	public static final String EXTRA_WORK_FORCE_PASSWORD = "fp";
+	public static final String EXTRA_OPEN_HOME_ACTIVITY = "oha";
 	private static final String DIALOG_TAG_UNSAFE_PASSWORD = "unsafe";
 	private static final String DIALOG_TAG_UNSAFE_PASSWORD_WORK = "unsafework";
 
@@ -80,6 +83,7 @@ public class ThreemaSafeConfigureActivity extends ThreemaToolbarActivity impleme
 	private Button nextButton;
 	private boolean updatePasswordOnly;
 	private ThreemaSafeServerInfo serverInfo;
+	private boolean openHomeActivity = false;
 
 	@SuppressLint("SetTextI18n")
 	@Override
@@ -147,9 +151,19 @@ public class ThreemaSafeConfigureActivity extends ThreemaToolbarActivity impleme
 			}
 		}
 
+		openHomeActivity = (intent != null && intent.getBooleanExtra(EXTRA_OPEN_HOME_ACTIVITY, false))
+			|| (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_OPEN_HOME_ACTIVITY, false));
+
 		return true;
 	}
 
+	@Override
+	public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
+		super.onSaveInstanceState(outState, outPersistentState);
+
+		outState.putBoolean(EXTRA_OPEN_HOME_ACTIVITY, openHomeActivity);
+	}
+
 	@Override
 	public int getLayoutResource() {
 		return R.layout.activity_threema_safe_configure;
@@ -246,6 +260,11 @@ public class ThreemaSafeConfigureActivity extends ThreemaToolbarActivity impleme
 		} else {
 			Toast.makeText(ThreemaApplication.getAppContext(), R.string.safe_activated, Toast.LENGTH_LONG).show();
 		}
+
+		if (openHomeActivity) {
+			startActivity(new Intent(ThreemaSafeConfigureActivity.this, HomeActivity.class));
+		}
+
 		finish();
 	}
 

+ 7 - 1
app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeService.java

@@ -76,5 +76,11 @@ public interface ThreemaSafeService {
 
 	@Nullable ArrayList<String> searchID(String phone, String email);
 
-	void launchForcedPasswordDialog(Activity activity);
+	/**
+	 * Launch the password dialog to setup Threema Safe.
+	 *
+	 * @param activity         the activity that starts the threema safe config activity
+	 * @param openHomeActivity if set to true, the home activity is started after successfully choosing a password
+	 */
+	void launchForcedPasswordDialog(Activity activity, boolean openHomeActivity);
 }

+ 22 - 19
app/src/main/java/ch/threema/app/threemasafe/ThreemaSafeServiceImpl.java

@@ -21,6 +21,15 @@
 
 package ch.threema.app.threemasafe;
 
+import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_EVERYONE;
+import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_NOBODY;
+import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_SOME;
+import static ch.threema.app.threemasafe.ThreemaSafeConfigureActivity.EXTRA_OPEN_HOME_ACTIVITY;
+import static ch.threema.app.threemasafe.ThreemaSafeConfigureActivity.EXTRA_WORK_FORCE_PASSWORD;
+import static ch.threema.app.threemasafe.ThreemaSafeServerTestResponse.CONFIG_MAX_BACKUP_BYTES;
+import static ch.threema.app.threemasafe.ThreemaSafeServerTestResponse.CONFIG_RETENTION_DAYS;
+import static ch.threema.app.threemasafe.ThreemaSafeUploadService.EXTRA_FORCE_UPLOAD;
+
 import android.app.Activity;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
@@ -65,8 +74,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.zip.Deflater;
 import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
 
 import javax.net.ssl.HttpsURLConnection;
 
@@ -89,6 +98,7 @@ import ch.threema.app.stores.IdentityStore;
 import ch.threema.app.utils.AppRestrictionUtil;
 import ch.threema.app.utils.BitmapUtil;
 import ch.threema.app.utils.ConfigUtils;
+import ch.threema.app.utils.GzipOutputStream;
 import ch.threema.app.utils.RuntimeUtil;
 import ch.threema.app.utils.StringConversionUtil;
 import ch.threema.app.utils.TestUtil;
@@ -121,14 +131,6 @@ import ch.threema.storage.models.group.GroupInviteModel;
 import ch.threema.storage.models.group.IncomingGroupJoinRequestModel;
 import ch.threema.storage.models.group.OutgoingGroupJoinRequestModel;
 
-import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_EVERYONE;
-import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_NOBODY;
-import static ch.threema.app.services.PreferenceService.PROFILEPIC_RELEASE_SOME;
-import static ch.threema.app.threemasafe.ThreemaSafeConfigureActivity.EXTRA_WORK_FORCE_PASSWORD;
-import static ch.threema.app.threemasafe.ThreemaSafeServerTestResponse.CONFIG_MAX_BACKUP_BYTES;
-import static ch.threema.app.threemasafe.ThreemaSafeServerTestResponse.CONFIG_RETENTION_DAYS;
-import static ch.threema.app.threemasafe.ThreemaSafeUploadService.EXTRA_FORCE_UPLOAD;
-
 public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("ThreemaSafeServiceImpl");
 
@@ -511,11 +513,11 @@ public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 
 		if (!force) {
 			if (hashString.equals(preferenceService.getThreemaSafeHashString())) {
-				Date aWeekAgo = new Date(System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS);
+				long halfRetentionTimeMillis = (serverTestResponse.retentionDays == 0 ? 180 : serverTestResponse.retentionDays) * DateUtils.DAY_IN_MILLIS / 2;
+				Date reUploadThreshold = new Date(System.currentTimeMillis() - halfRetentionTimeMillis);
 				if (preferenceService.getThreemaSafeErrorCode() == ERROR_CODE_OK &&
-					aWeekAgo.before(preferenceService.getThreemaSafeUploadDate())) {
+					reUploadThreshold.before(preferenceService.getThreemaSafeUploadDate())) {
 					preferenceService.setThreemaSafeErrorCode(ERROR_CODE_OK);
-					preferenceService.setThreemaSafeBackupDate(new Date());
 					logger.info("Threema Safe contents unchanged. Not uploaded");
 					return;
 				}
@@ -676,13 +678,12 @@ public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 			throw new ThreemaException("Unable to decrypt");
 		}
 
-		byte[] uncompressed = gZipUncompress(gzippedData);
-		if (uncompressed == null) {
+		byte[] uncompressedData = gZipUncompress(gzippedData);
+		if (uncompressedData == null) {
 			throw new ThreemaException("Uncompress failed");
 		}
 
-		String json;
-		json = new String(uncompressed, StandardCharsets.UTF_8);
+		String json = new String(uncompressedData, StandardCharsets.UTF_8);
 
 		parseJson(identity, json);
 
@@ -770,7 +771,7 @@ public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 		try {
 			userService.restoreIdentity(identity, privateKey, publicKey);
 		} catch (Exception e) {
-			throw new ThreemaException("Unable to restore identity: " + e.getMessage());
+			throw new ThreemaException(context.getString(R.string.unable_to_restore_identity_because, e.getMessage()));
 		}
 
 		String nickname = user.optString(TAG_SAFE_USER_NICKNAME, identity);
@@ -1277,10 +1278,11 @@ public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 	}
 
 	@Override
-	public void launchForcedPasswordDialog(Activity activity) {
+	public void launchForcedPasswordDialog(Activity activity, boolean openHomeActivity) {
 		// ask user for a new password
 		Intent intent = new Intent(activity, ThreemaSafeConfigureActivity.class);
 		intent.putExtra(EXTRA_WORK_FORCE_PASSWORD, true);
+		intent.putExtra(EXTRA_OPEN_HOME_ACTIVITY, openHomeActivity);
 		activity.startActivity(intent);
 		activity.overridePendingTransition(R.anim.slide_in_right_short, R.anim.slide_out_left_short);
 	}
@@ -1338,7 +1340,8 @@ public class ThreemaSafeServiceImpl implements ThreemaSafeService {
 	private byte[] gZipCompress(byte[] uncompressedBytes) {
 		try {
 			ByteArrayOutputStream outputStream = new ByteArrayOutputStream(uncompressedBytes.length);
-			GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
+			// Use gzip for backward compatibility, but don't actually compress (to avoid compression oracles)
+			GzipOutputStream gzipOutputStream = new GzipOutputStream(outputStream, Deflater.NO_COMPRESSION, 512, false);
 			gzipOutputStream.write(uncompressedBytes);
 			gzipOutputStream.close();
 			byte[] compressedBytes = outputStream.toByteArray();

+ 303 - 0
app/src/main/java/ch/threema/app/ui/AudioProgressBarView.kt

@@ -0,0 +1,303 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package ch.threema.app.ui
+
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.view.ViewGroup
+import android.view.animation.DecelerateInterpolator
+import androidx.core.graphics.applyCanvas
+import androidx.transition.ChangeClipBounds
+import androidx.transition.Transition
+import androidx.transition.TransitionManager
+import ch.threema.app.R
+import ch.threema.app.ThreemaApplication
+import ch.threema.app.cache.ThumbnailCache
+import ch.threema.app.utils.RuntimeUtil
+import ch.threema.base.utils.LoggingUtil
+import ch.threema.storage.models.AbstractMessageModel
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+class AudioProgressBarView : androidx.appcompat.widget.AppCompatSeekBar, AudioWaveformGeneratorTask.AudioWaveformGeneratorListener {
+    private val logger = LoggingUtil.getThreemaLogger("AudioProgressBarView")
+
+    private var barHeight = 20
+    private var barWidth = 5
+    private var spaceWidth: Int = 3
+    private var barMinHeight = 4
+    private var halfBarMinHeight = 2F
+
+    var barColor = Color.TRANSPARENT
+    var barColorActivated = Color.TRANSPARENT
+    private lateinit var barPaint: Paint
+    private lateinit var barPaintActivated: Paint
+    private var viewWidth: Int = 0
+    private var viewHeight: Int = 0
+    private var numSamples: Int = 24
+    private var waveBitmap: Bitmap? = null
+    private var emptyBitmap: Bitmap? = null
+    private var waveFormTask: AudioWaveformGeneratorTask? = null
+    private var thumbnailCache: ThumbnailCache<Any>? = null
+    private var messageModel: AbstractMessageModel? = null
+    private var changeBounds: Transition = ChangeClipBounds()
+
+    // we calculate a sufficiently large number of samples upfront so we don't need to wait for onLayout
+    private val numPreCalculatedSamples = 30
+
+    // radius of bar edges in px
+    private val radius = 2F
+
+    constructor(context: Context) : super(context)
+
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+        init(attrs)
+    }
+
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+        init(attrs)
+    }
+
+    fun init(attrs: AttributeSet?) {
+        val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.AudioProgressBarView, 0, 0)
+
+        with(typedArray) {
+            barHeight = getDimensionPixelSize(R.styleable.AudioProgressBarView_barHeight, barHeight)
+            barWidth = getDimensionPixelSize(R.styleable.AudioProgressBarView_barWidth, barWidth)
+            spaceWidth = getDimensionPixelSize(R.styleable.AudioProgressBarView_spaceWidth, spaceWidth)
+            barMinHeight = getDimensionPixelSize(R.styleable.AudioProgressBarView_barMinHeight, barMinHeight)
+            halfBarMinHeight = barMinHeight / 2F
+            barColor = getColor(R.styleable.AudioProgressBarView_barColor, barColor)
+            barColorActivated = getColor(R.styleable.AudioProgressBarView_barColorActivated, barColorActivated)
+            recycle()
+        }
+
+        barPaint = Paint().apply {
+            isAntiAlias = true
+            color = barColor
+        }
+
+        barPaintActivated = Paint().apply {
+            isAntiAlias = true
+            colorFilter = PorterDuffColorFilter(barColorActivated, PorterDuff.Mode.SRC_IN)
+        }
+
+        changeBounds.duration = 800
+        changeBounds.interpolator = DecelerateInterpolator()
+        changeBounds.addTarget(this)
+    }
+
+    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+        super.onLayout(changed, left, top, right, bottom)
+
+        viewWidth = right - left
+        viewHeight = bottom - top
+
+        numSamples = viewWidth / (barWidth + spaceWidth)
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+
+        if (!isAttachedToWindow) {
+            return
+        }
+
+        if (max == 0) {
+            max = 100
+        }
+
+        var drawBitmap = waveBitmap
+        if (drawBitmap == null) {
+            if (emptyBitmap != null) {
+                drawBitmap = emptyBitmap
+            } else {
+                emptyBitmap = createEmptyBitmap()
+                drawBitmap = emptyBitmap
+            }
+        }
+
+        if (drawBitmap != null) {
+            canvas.apply {
+                save()
+                clipRect((viewWidth * progress / max), 0, viewWidth, viewHeight)
+                drawBitmap(drawBitmap, 0F, 0F, barPaint)
+                restore()
+            }
+
+            canvas.apply {
+                save()
+                clipRect(0, 0, (viewWidth * progress / max), viewHeight)
+                drawBitmap(drawBitmap, 0F, 0F, barPaintActivated)
+                restore()
+            }
+        }
+    }
+
+    private fun createEmptyBitmap() : Bitmap {
+        val tmpBitmap = Bitmap.createBitmap(viewWidth, barHeight, Bitmap.Config.ARGB_8888)
+        val unusedHeight: Float = (barHeight / 2F) - halfBarMinHeight
+        val halfSpace = spaceWidth.toFloat() / 2F;
+
+        for (i: Int in 0 until numSamples) {
+            tmpBitmap.applyCanvas {
+                drawRoundRect(
+                        RectF(
+                                halfSpace + (i * (barWidth + spaceWidth)),
+                                unusedHeight,
+                                halfSpace + (i * (barWidth + spaceWidth)) + barWidth,
+                                barHeight - unusedHeight
+                        ),
+                        radius,
+                        radius,
+                        barPaint
+                )
+            }
+        }
+        return tmpBitmap
+    }
+
+    private fun createWaveformBitmap(samplesData: List<Float>) : Bitmap {
+        val tmpBitmap = Bitmap.createBitmap(viewWidth, barHeight, Bitmap.Config.ARGB_8888)
+        val factor: Float = samplesData.size.toFloat() / numSamples.toFloat()
+        val halfSpace = spaceWidth.toFloat() / 2F
+        val halfBarHeight = barHeight / 2F
+
+        for (i: Int in 0 until numSamples) {
+            val sample = samplesData[(i * factor).roundToInt()]
+            val unusedHeight: Float = min(halfBarHeight * (1F - sample), halfBarHeight - halfBarMinHeight)
+
+            tmpBitmap.applyCanvas {
+                drawRoundRect(
+                        RectF(
+                                halfSpace + (i * (barWidth + spaceWidth)),
+                                unusedHeight,
+                                halfSpace + (i * (barWidth + spaceWidth)) + barWidth,
+                                barHeight - unusedHeight
+                        ),
+                        radius,
+                        radius,
+                        barPaint
+                )
+            }
+        }
+        return tmpBitmap
+    }
+
+    override fun onDataReady(newMessageModel: AbstractMessageModel, sampleData: List<Float>) {
+        if (!isAttachedToWindow) {
+            return
+        }
+
+        if (viewHeight == 0 || barHeight == 0) {
+            return
+        }
+
+        waveFormTask = null
+        if (messageModel?.id == newMessageModel.id) {
+            if (sampleData.isNotEmpty()) {
+                waveBitmap = createWaveformBitmap(sampleData)
+                thumbnailCache?.set(messageModel?.id, waveBitmap)
+                postInvalidate()
+                show()
+            }
+        }
+    }
+
+    override fun onError(errorMessageModel: AbstractMessageModel, errorMessage: String?) {
+        waveFormTask = null
+    }
+
+    override fun onCanceled(cancelMessageModel: AbstractMessageModel) {
+        waveFormTask = null
+    }
+
+    override fun onDetachedFromWindow() {
+        waveFormTask?.cancel()
+        waveFormTask = null
+
+        super.onDetachedFromWindow()
+    }
+
+    fun setMessageModel(newMessageModel: AbstractMessageModel?, thumbnailCache: ThumbnailCache<Any>?) {
+        if (newMessageModel == null) {
+            return
+        }
+
+        if (thumbnailCache == null) {
+            return
+        }
+
+        this.thumbnailCache = thumbnailCache
+
+        if (messageModel?.id != newMessageModel.id) {
+            // recycled view
+            waveFormTask?.let {
+                if (it.getMessageId() == newMessageModel.id) {
+                    return
+                } else {
+                    it.cancel()
+                }
+            }
+        }
+
+        val cachedBitmap = thumbnailCache.get(newMessageModel.id);
+        if (cachedBitmap != null) {
+            messageModel = newMessageModel
+            waveBitmap = cachedBitmap
+
+            postInvalidate()
+        } else {
+            waveFormTask?.let {
+                if (it.getMessageId() == newMessageModel.id) {
+                    return
+                }
+            }
+
+            waveBitmap = null
+            messageModel = newMessageModel
+            waveFormTask = AudioWaveformGeneratorTask(newMessageModel,
+                    numPreCalculatedSamples,
+                    this@AudioProgressBarView);
+
+            ThreemaApplication.voiceMessageThumbnailExecutorService.execute(Thread(waveFormTask, "WaveformGenerator"))
+        }
+    }
+
+    private fun show() {
+        if (messageModel == null) {
+            return
+        }
+
+        RuntimeUtil.runOnUiThread {
+            if (viewWidth > 0) {
+                if (messageModel != null) {
+                    clipBounds = Rect(0, ((viewHeight / 2F) - halfBarMinHeight).toInt(), viewWidth, ((viewHeight / 2F) + halfBarMinHeight).toInt())
+                    TransitionManager.beginDelayedTransition(parent as ViewGroup, changeBounds)
+                }
+                clipBounds = Rect(0, 0, viewWidth, viewHeight)
+                visibility = VISIBLE
+            }
+        }
+    }
+}

+ 178 - 0
app/src/main/java/ch/threema/app/ui/AudioWaveformGeneratorTask.kt

@@ -0,0 +1,178 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package ch.threema.app.ui
+
+import android.media.MediaCodec
+import android.media.MediaExtractor
+import android.media.MediaFormat
+import android.net.Uri
+import ch.threema.app.ThreemaApplication
+import ch.threema.app.video.transcoder.MediaComponent
+import ch.threema.app.video.transcoder.VideoTranscoder
+import ch.threema.base.utils.LoggingUtil
+import ch.threema.storage.models.AbstractMessageModel
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.math.pow
+import kotlin.math.sqrt
+
+/**
+ * Waveform generator for voice messages. Accepts 16bit sampled audio data only
+ *
+ * @param messageModel The AbstractMessageModel of a voice message
+ * @param requestedSamplesCount How many points to expect to be drawn in the end
+ */
+class AudioWaveformGeneratorTask(private val messageModel: AbstractMessageModel, private val requestedSamplesCount: Int, private val listener: AudioWaveformGeneratorListener) : Runnable {
+    private val logger = LoggingUtil.getThreemaLogger("AudioWaveFormGenerator")
+
+    private var sampleRate = 0
+    private var channels = 1
+    private val sampleData = ArrayList<Float>()
+    var canceled: AtomicBoolean = AtomicBoolean(false)
+
+    interface AudioWaveformGeneratorListener {
+        fun onDataReady(newMessageModel: AbstractMessageModel, sampleData : List<Float>)
+        fun onError(errorMessageModel: AbstractMessageModel, errorMessage: String?)
+        fun onCanceled(cancelMessageModel: AbstractMessageModel)
+    }
+
+    override fun run() {
+        if (canceled.get()) {
+            listener.onCanceled(messageModel)
+            return
+        }
+
+        var decoder: MediaCodec? = null
+        var inputAudioComponent: MediaComponent? = null
+        try {
+            val file = ThreemaApplication.getServiceManager()?.fileService?.getDecryptedMessageFile(messageModel)
+            if (file == null || !file.exists()) {
+                listener.onError(messageModel, "Unable to open audio file")
+                return
+            }
+
+            inputAudioComponent = MediaComponent(ThreemaApplication.getAppContext(), Uri.fromFile(file), MediaComponent.COMPONENT_TYPE_AUDIO)
+            if (inputAudioComponent.mimeType != null) {
+                val mediaFormat = inputAudioComponent.trackFormat
+                if (mediaFormat != null) {
+                    val durationMs = inputAudioComponent.durationUs / 1000
+                    if (durationMs > 0) {
+                        sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)
+                        channels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
+
+                        decoder = MediaCodec.createDecoderByType(inputAudioComponent.mimeType!!)
+                        decoder.configure(mediaFormat, null, null, 0)
+                        decoder.start()
+                        extractSamples(inputAudioComponent.mediaExtractor, decoder, inputAudioComponent.durationUs)
+
+                        if (!canceled.get()) {
+                            listener.onDataReady(messageModel, sampleData)
+                            return
+                        }
+                    }
+                }
+            }
+        } catch (e: Exception) {
+            logger.error("Media failure", e)
+        } finally {
+            inputAudioComponent?.release()
+            decoder?.let {
+                try {
+                    it.stop()
+                    it.release()
+                } catch (e: Exception) {
+                    logger.error("Failed to stop decoder", e)
+                }
+            }
+        }
+        if (canceled.get()) {
+            listener.onCanceled(messageModel)
+        } else {
+            listener.onError(messageModel,  "Audio waveform generating failed or interrupted")
+        }
+    }
+
+    private fun extractSamples(extractor: MediaExtractor, decoder: MediaCodec, duration: Long) {
+        val info = MediaCodec.BufferInfo()
+        var outputDone = false
+        var inputDone = false
+        var samplesExtracted = 0
+        var sampleIndex = 0
+        while (!outputDone && !canceled.get()) {
+            if (!inputDone) {
+                val decoderInputBufferIndex = decoder.dequeueInputBuffer(VideoTranscoder.TIMEOUT_USEC.toLong())
+                if (decoderInputBufferIndex >= 0) {
+                    val chunkSize = extractor.readSampleData(decoder.getInputBuffer(decoderInputBufferIndex)!!, 0)
+                    if (chunkSize < 0 || samplesExtracted >= requestedSamplesCount) {
+                        decoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
+                        inputDone = true
+                    } else {
+                        decoder.queueInputBuffer(decoderInputBufferIndex, 0, chunkSize, extractor.sampleTime, 0)
+                        samplesExtracted++
+                        extractor.seekTo(duration * samplesExtracted / requestedSamplesCount, MediaExtractor.SEEK_TO_CLOSEST_SYNC)
+                    }
+                }
+            }
+            val outputBufIndex = decoder.dequeueOutputBuffer(info, VideoTranscoder.TIMEOUT_USEC.toLong())
+            if (outputBufIndex >= 0) {
+                if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) {
+                    outputDone = true
+                }
+                val shouldRender = info.size != 0
+                if (shouldRender) {
+                    if (sampleIndex < requestedSamplesCount) {
+                        decoder.getOutputBuffer(outputBufIndex)?.let { buf ->
+                            val size = info.size
+                            var sampleSum = 0.0
+
+                            buf.position(info.offset)
+                            repeat(size / if (channels == 2) 4 else 2) {
+                                // voice messages are one channel only
+                                val a = buf.get().toInt()
+                                val b = buf.get().toInt() shl 8
+                                val value = (a or b) / 32768f
+                                if (channels == 2) {
+                                    // skip right channel, if there is one
+                                    buf.get()
+                                    buf.get()
+                                }
+                                sampleSum += value.toDouble().pow(2.0)
+                            }
+
+                            val rms = sqrt(sampleSum / size) * 15
+                            sampleData.add(rms.toFloat())
+                        }
+                    }
+                    sampleIndex++
+                }
+                decoder.releaseOutputBuffer(outputBufIndex, shouldRender)
+            }
+        }
+    }
+
+    fun cancel() {
+        canceled.set(true)
+    }
+
+    fun getMessageId() : Int {
+        return messageModel.id
+    }
+}

+ 10 - 6
app/src/main/java/ch/threema/app/ui/AvatarEditView.java

@@ -502,14 +502,18 @@ public class AvatarEditView extends FrameLayout implements DefaultLifecycleObser
 	@UiThread
 	private void setAvatarBitmap(@Nullable Bitmap bitmap) {
 		if (bitmap != null) {
-			if (hires) {
-				if (isMyProfilePicture) {
-					this.avatarImage.setImageDrawable(AvatarConverterUtil.convertToRound(getResources(), bitmap));
+			try {
+				if (hires) {
+					if (isMyProfilePicture) {
+						this.avatarImage.setImageDrawable(AvatarConverterUtil.convertToRound(getResources(), bitmap));
+					} else {
+						this.avatarImage.setImageBitmap(bitmap);
+					}
 				} else {
-					this.avatarImage.setImageBitmap(bitmap);
+					this.avatarImage.setImageDrawable(AvatarConverterUtil.convertToRound(getResources(), bitmap));
 				}
-			} else {
-				this.avatarImage.setImageDrawable(AvatarConverterUtil.convertToRound(getResources(), bitmap));
+			} catch (RuntimeException e) {
+				logger.error("Unable to set avatar bitmap", e);
 			}
 			if (ColorUtil.getInstance().calculateBrightness(bitmap, 2) > 100) {
 				this.avatarImage.setColorFilter(getResources().getColor(R.color.material_grey_300), PorterDuff.Mode.DARKEN);

+ 7 - 0
app/src/main/java/ch/threema/app/ui/MediaItem.java

@@ -237,6 +237,13 @@ public class MediaItem implements Parcelable {
 		return caption;
 	}
 
+	public @Nullable String getTrimmedCaption() {
+		if (caption != null) {
+			return caption.trim();
+		}
+		return null;
+	}
+
 	public void setCaption(@Nullable String caption) {
 		this.caption = caption;
 	}

+ 20 - 5
app/src/main/java/ch/threema/app/ui/ThreemaEditText.java

@@ -24,12 +24,14 @@ package ch.threema.app.ui;
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.os.AsyncTask;
 import android.os.Build;
 import android.util.AttributeSet;
 
+import androidx.preference.PreferenceManager;
+
 import com.google.android.material.textfield.TextInputEditText;
 
-import androidx.preference.PreferenceManager;
 import ch.threema.app.R;
 
 public class ThreemaEditText extends TextInputEditText {
@@ -54,10 +56,23 @@ public class ThreemaEditText extends TextInputEditText {
 
 	private void init(Context context) {
 		// PreferenceService may not yet be available at this time
-		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-		if (sharedPreferences != null && sharedPreferences.getBoolean(getResources().getString(R.string.preferences__incognito_keyboard), false)) {
-			setImeOptions(getImeOptions() | 0x1000000);
-		}
+		new AsyncTask<Void, Void, Boolean>() {
+			@Override
+			protected Boolean doInBackground(Void... voids) {
+				SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+				if (sharedPreferences != null) {
+					return sharedPreferences.getBoolean(getResources().getString(R.string.preferences__incognito_keyboard), false);
+				}
+				return null;
+			}
+
+			@Override
+			protected void onPostExecute(Boolean aBoolean) {
+				if (aBoolean != null && aBoolean == true) {
+					setImeOptions(getImeOptions() | 0x1000000);
+				}
+			}
+		}.execute();
 	}
 
 	@Override

+ 2 - 2
app/src/main/java/ch/threema/app/ui/listitemholder/ComposeMessageHolder.java

@@ -25,13 +25,13 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.SeekBar;
 import android.widget.TextView;
 
 import com.google.android.material.button.MaterialButton;
 import com.google.android.material.chip.Chip;
 
 import ch.threema.app.services.messageplayer.MessagePlayer;
+import ch.threema.app.ui.AudioProgressBarView;
 import ch.threema.app.ui.ControllerView;
 import ch.threema.app.ui.TranscoderView;
 
@@ -47,7 +47,7 @@ public class ComposeMessageHolder extends AvatarListItemHolder {
 	public ImageView attachmentImage;
 	public ViewGroup messageBlockView;
 	public ViewGroup contentView;
-	public SeekBar seekBar;
+	public AudioProgressBarView seekBar;
 	public View quoteBar;
 	public ImageView quoteThumbnail, quoteTypeImage;
 	public TranscoderView transcoderView;

+ 37 - 16
app/src/main/java/ch/threema/app/utils/ConfigUtils.java

@@ -63,21 +63,6 @@ import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.Toast;
 
-import com.datatheorem.android.trustkit.TrustKit;
-import com.google.android.material.snackbar.BaseTransientBottomBar;
-import com.google.android.material.snackbar.Snackbar;
-
-import org.slf4j.Logger;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import javax.net.ssl.SSLSocketFactory;
-
 import androidx.annotation.AttrRes;
 import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
@@ -98,6 +83,23 @@ import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceManager;
+
+import com.datatheorem.android.trustkit.TrustKit;
+import com.google.android.material.snackbar.BaseTransientBottomBar;
+import com.google.android.material.snackbar.Snackbar;
+
+import org.slf4j.Logger;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+
 import ch.threema.app.BuildConfig;
 import ch.threema.app.BuildFlavor;
 import ch.threema.app.R;
@@ -265,7 +267,10 @@ public class ConfigUtils {
 	 * Get a Socket Factory for certificate pinning and forced TLS version upgrade.
 	 */
 	public static @NonNull SSLSocketFactory getSSLSocketFactory(String host) {
-		return new TLSUpgradeSocketFactoryWrapper(TrustKit.getInstance().getSSLSocketFactory(host));
+		return new TLSUpgradeSocketFactoryWrapper(
+			ConfigUtils.isOnPremBuild() ?
+				HttpsURLConnection.getDefaultSSLSocketFactory() :
+				TrustKit.getInstance().getSSLSocketFactory(host));
 	}
 
 	public static boolean hasNoMapLibreSupport() {
@@ -503,6 +508,22 @@ public class ConfigUtils {
 		final StringBuilder info = new StringBuilder();
 		if (includeAppVersion) {
 			info.append(getAppVersion(context)).append("/");
+			if (ConfigUtils.isWorkRestricted()) {
+				AppRestrictionService appRestrictionService = AppRestrictionService.getInstance();
+				if (appRestrictionService != null) {
+					final StringBuilder mdmBuilder = new StringBuilder();
+					if (appRestrictionService.hasThreemaMDMRestrictions()) {
+						mdmBuilder.append("m");
+					}
+					if (appRestrictionService.hasExternalMDMRestrictions()) {
+						mdmBuilder.append("e");
+					}
+
+					if (mdmBuilder.length() > 0) {
+						info.append(mdmBuilder).append("/");
+					}
+				}
+			}
 		}
 		info.append(Build.MANUFACTURER).append(";")
 			.append(Build.MODEL).append("/")

+ 93 - 0
app/src/main/java/ch/threema/app/utils/GzipOutputStream.java

@@ -0,0 +1,93 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2018-2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package ch.threema.app.utils;
+
+import static java.util.zip.GZIPInputStream.GZIP_MAGIC;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+/**
+ * Copy of AOSP's GZIPOutputStream exposing a parameter for Deflator's compression level
+ */
+public class GzipOutputStream extends DeflaterOutputStream {
+	protected CRC32 crc = new CRC32();
+	private final static int TRAILER_SIZE = 8;
+
+	public GzipOutputStream(OutputStream out, int level, int size, boolean syncFlush) throws IOException {
+		super(out, new Deflater(level, true), size, syncFlush);
+		writeHeader();
+		crc.reset();
+	}
+
+	public synchronized void write(byte[] buf, int off, int len) throws IOException {
+		super.write(buf, off, len);
+		crc.update(buf, off, len);
+	}
+
+	public void finish() throws IOException {
+		if (!def.finished()) {
+			def.finish();
+			while (!def.finished()) {
+				int len = def.deflate(buf, 0, buf.length);
+				if (def.finished() && len <= buf.length - TRAILER_SIZE) {
+					writeTrailer(buf, len);
+					len = len + TRAILER_SIZE;
+					out.write(buf, 0, len);
+					return;
+				}
+				if (len > 0)
+					out.write(buf, 0, len);
+			}
+			byte[] trailer = new byte[TRAILER_SIZE];
+			writeTrailer(trailer, 0);
+			out.write(trailer);
+		}
+	}
+
+	private void writeHeader() throws IOException {
+		out.write(new byte[] {
+			(byte) GZIP_MAGIC,
+			(byte)(GZIP_MAGIC >> 8),
+			Deflater.DEFLATED,
+			0,0,0,0,0,0,0
+		});
+	}
+
+	private void writeTrailer(byte[] buf, int offset) {
+		writeInt((int)crc.getValue(), buf, offset);
+		writeInt(def.getTotalIn(), buf, offset + 4);
+	}
+
+	private void writeInt(int i, byte[] buf, int offset) {
+		writeShort(i & 0xffff, buf, offset);
+		writeShort((i >> 16) & 0xffff, buf, offset + 2);
+	}
+
+	private void writeShort(int s, byte[] buf, int offset) {
+		buf[offset] = (byte)(s & 0xff);
+		buf[offset + 1] = (byte)((s >> 8) & 0xff);
+	}
+}

+ 13 - 3
app/src/main/java/ch/threema/app/utils/LocaleUtil.java

@@ -24,13 +24,14 @@ package ch.threema.app.utils;
 import android.content.Context;
 import android.text.format.DateUtils;
 
+import androidx.annotation.NonNull;
+import androidx.core.os.ConfigurationCompat;
+
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.text.Normalizer;
 import java.util.Locale;
 
-import androidx.annotation.NonNull;
-import androidx.core.os.ConfigurationCompat;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.services.PreferenceService;
 
@@ -102,7 +103,16 @@ public class LocaleUtil {
 
 		if (showMs) {
 			int milliseconds = (int) ((elapsedTime % 60000) % 1000);
-			return String.format(Locale.US, "%01d:%02d:%02d", minutes, seconds, milliseconds / 10);
+
+			if (elapsedTime > DateUtils.HOUR_IN_MILLIS) {
+				return String.format(Locale.US, "%d:%02d:%02d.%02d",
+					minutes / 60,
+					minutes % 60,
+					seconds,
+					milliseconds / 10);
+			} else {
+				return String.format(Locale.US, "%01d:%02d.%02d", minutes, seconds, milliseconds / 10);
+			}
 		}
 		return String.format(Locale.US, "%01d:%02d", minutes, seconds);
 	}

+ 11 - 6
app/src/main/java/ch/threema/app/utils/QuoteUtil.java

@@ -25,14 +25,15 @@ package ch.threema.app.utils;
 import android.content.Context;
 import android.graphics.Bitmap;
 
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import org.slf4j.Logger;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.cache.ThumbnailCache;
@@ -46,6 +47,7 @@ import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.DistributionListMessageModel;
 import ch.threema.storage.models.GroupMessageModel;
 import ch.threema.storage.models.MessageType;
+import ch.threema.storage.models.data.MessageContentsType;
 
 import static ch.threema.app.messagereceiver.MessageReceiver.Type_CONTACT;
 import static ch.threema.app.messagereceiver.MessageReceiver.Type_DISTRIBUTION_LIST;
@@ -173,9 +175,12 @@ public class QuoteUtil {
 				final @NonNull String quotedText = TestUtil.empty(viewElement.text) ? (viewElement.placeholder != null ? viewElement.placeholder : "") : viewElement.text;
 				final @DrawableRes Integer icon = viewElement.icon;
 				Bitmap thumbnail = null;
-				try {
-					thumbnail = fileService.getMessageThumbnailBitmap(quotedMessageModel, thumbnailCache);
-				} catch (Exception ignore) {
+				if (quotedMessageModel.getMessageContentsType() != MessageContentsType.VOICE_MESSAGE) {
+					// ignore thumbnails of voice messages
+					try {
+						thumbnail = fileService.getMessageThumbnailBitmap(quotedMessageModel, thumbnailCache);
+					} catch (Exception ignore) {
+					}
 				}
 				return QuoteContent.createV2(
 						identity,

+ 12 - 4
app/src/main/java/ch/threema/app/utils/StringConversionUtil.java

@@ -22,6 +22,7 @@
 package ch.threema.app.utils;
 
 import android.content.Context;
+import android.text.format.DateUtils;
 
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
@@ -30,6 +31,7 @@ import androidx.annotation.NonNull;
 import ch.threema.app.R;
 
 public class StringConversionUtil {
+
 	public static byte[] stringToByteArray(String s) {
 		if(s == null) {
 			return new byte[0];
@@ -74,11 +76,17 @@ public class StringConversionUtil {
 				context.getString(R.string.and) + " " + seconds + " " + context.getString(R.string.seconds);
 	}
 
-
 	public static String getDurationString(long milliseconds) {
-		return String.format(Locale.US, "%02d:%02d",
-			TimeUnit.MILLISECONDS.toMinutes(milliseconds) % TimeUnit.HOURS.toMinutes(1),
-			TimeUnit.MILLISECONDS.toSeconds(milliseconds) % TimeUnit.MINUTES.toSeconds(1));
+		if (milliseconds > DateUtils.HOUR_IN_MILLIS) {
+			return String.format(Locale.US, "%d:%02d:%02d",
+				TimeUnit.MILLISECONDS.toHours(milliseconds),
+				TimeUnit.MILLISECONDS.toMinutes(milliseconds) % TimeUnit.HOURS.toMinutes(1),
+				TimeUnit.MILLISECONDS.toSeconds(milliseconds) % TimeUnit.MINUTES.toSeconds(1));
+		} else {
+			return String.format(Locale.US, "%02d:%02d",
+				TimeUnit.MILLISECONDS.toMinutes(milliseconds) % TimeUnit.HOURS.toMinutes(1),
+				TimeUnit.MILLISECONDS.toSeconds(milliseconds) % TimeUnit.MINUTES.toSeconds(1));
+		}
 	}
 
 	public static String xDigit(int number, int digits) {

+ 39 - 0
app/src/main/java/ch/threema/app/utils/TestUtil.java

@@ -23,9 +23,12 @@ package ch.threema.app.utils;
 
 import android.text.TextUtils;
 
+import java.text.Normalizer;
 import java.util.Arrays;
 import java.util.Date;
 
+import androidx.annotation.Nullable;
+
 public class TestUtil {
 	@Deprecated
 	public static boolean required(Object o) {
@@ -147,6 +150,42 @@ public class TestUtil {
 					string.contains(search));
 	}
 
+	/**
+	 * Check if the query string matches the conversation title. A query matches the conversation
+	 * text if
+	 * <ul>
+	 *     <li>the conversation text contains the query, or</li>
+	 *     <li>the normalized conversation text without the diacritics contains the query.</li>
+	 * </ul>
+	 *
+	 * If any of the arguments is null, {@code false} is returned.
+	 *
+	 * @param query        the query
+	 * @param conversation the conversation text
+	 * @return {@code true} if there is a match, {@code false} otherwise
+	 */
+	public static boolean matchesConversationSearch(@Nullable String query, @Nullable String conversation) {
+		if (query == null || conversation == null) {
+			return false;
+		}
+
+		query = query.toUpperCase();
+		conversation = conversation.toUpperCase();
+
+		if (conversation.contains(query)) {
+			return true;
+		}
+
+		// Only normalize the query without removing the diacritics
+		String queryNorm = Normalizer.isNormalized(query, Normalizer.Form.NFD) ? query :
+			Normalizer.normalize(query, Normalizer.Form.NFD);
+
+		// Normalize conversation and remove diacritics
+		String conversationNormDiacritics = LocaleUtil.normalize(conversation);
+
+		return conversationNormDiacritics.contains(queryNorm);
+	}
+
 	public static boolean empty(CharSequence charSequence) {
 		if (!TextUtils.isEmpty(charSequence)) {
 			String messageString = charSequence.toString();

+ 146 - 0
app/src/main/java/ch/threema/app/video/VideoTimelineThumbnailTask.kt

@@ -0,0 +1,146 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2020-2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package ch.threema.app.video
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.media.MediaCodec
+import android.media.MediaExtractor
+import android.opengl.GLES20
+import ch.threema.app.ui.MediaItem
+import ch.threema.app.video.transcoder.MediaComponent
+import ch.threema.app.video.transcoder.OutputSurface
+import ch.threema.app.video.transcoder.VideoTranscoder
+import ch.threema.app.video.transcoder.VideoTranscoderUtil
+import ch.threema.base.ThreemaException
+import ch.threema.base.utils.LoggingUtil
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+
+class VideoTimelineThumbnailTask(private val context: Context, private val mediaItem: MediaItem, private val thumbnailCount: Int, private val targetWidth: Int, private val targetHeight: Int, private val listener: VideoTimelineListener) : Runnable {
+    private val logger = LoggingUtil.getThreemaLogger("VideoTimelineThumbnailTask")
+
+    interface VideoTimelineListener {
+        fun onMetadataReady()
+        fun onError(errorMessage: String?)
+        fun setThumbnail(column: Int, thumbnail: Bitmap?): Boolean
+    }
+
+    override fun run() {
+        var decoder: MediaCodec? = null
+        var outputSurface: OutputSurface? = null
+        var inputVideoComponent: MediaComponent? = null
+        try {
+            inputVideoComponent = MediaComponent(context, mediaItem.uri, MediaComponent.COMPONENT_TYPE_VIDEO)
+            val mediaFormat = inputVideoComponent.trackFormat
+            if (mediaFormat != null) {
+                if (mediaItem.startTimeMs < 0) {
+                    mediaItem.startTimeMs = 0
+                }
+                if (mediaItem.endTimeMs == MediaItem.TIME_UNDEFINED) {
+                    mediaItem.endTimeMs = inputVideoComponent.durationUs / 1000
+                }
+                mediaItem.durationMs = inputVideoComponent.durationUs / 1000
+                listener.onMetadataReady()
+                val orientationHint = VideoTranscoderUtil.getOrientationHint(context, inputVideoComponent, mediaItem.uri)
+                val outputDimensions = VideoTranscoderUtil.calculateOutputDimensions(inputVideoComponent, targetWidth, targetHeight)
+                if (outputDimensions != null) {
+                    if (orientationHint % 180 == 90) {
+                        val height = outputDimensions.height
+                        outputDimensions.height = outputDimensions.width
+                        outputDimensions.width = height
+                    }
+                    outputSurface = OutputSurface(outputDimensions.width, outputDimensions.height, 0)
+                    decoder = MediaCodec.createDecoderByType(inputVideoComponent.mimeType!!)
+                    decoder.configure(mediaFormat, outputSurface.surface, null, 0)
+                    decoder.start()
+                    extractThumbnails(inputVideoComponent.mediaExtractor, decoder, outputSurface, outputDimensions.width, outputDimensions.height, inputVideoComponent.durationUs)
+                }
+            }
+        } catch (e: Exception) {
+            logger.error("Media failure", e)
+            listener.onError(e.message)
+        } finally {
+            inputVideoComponent?.release()
+            outputSurface?.release()
+            if (decoder != null) {
+                try {
+                    decoder.stop()
+                    decoder.release()
+                } catch (e: Exception) {
+                    logger.error("Failed to stop decoder", e)
+                }
+            }
+        }
+    }
+
+    @Throws(ThreemaException::class)
+    private fun extractThumbnails(extractor: MediaExtractor, decoder: MediaCodec, outputSurface: OutputSurface, outputWidth: Int, outputHeight: Int, duration: Long) {
+        val info = MediaCodec.BufferInfo()
+        val byteBuffer = ByteBuffer.allocateDirect(outputWidth * outputHeight * 4)
+        byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
+        var outputDone = false
+        var inputDone = false
+        var samplesExtracted = 0
+        var thumbnailIndex = 0
+        while (!outputDone) {
+            if (!inputDone) {
+                val decoderInputBufferIndex = decoder.dequeueInputBuffer(VideoTranscoder.TIMEOUT_USEC.toLong())
+                if (decoderInputBufferIndex >= 0) {
+                    val chunkSize = extractor.readSampleData(
+                            decoder.getInputBuffer(decoderInputBufferIndex)!!, 0)
+                    if (chunkSize < 0 || samplesExtracted >= thumbnailCount) {
+                        decoder.queueInputBuffer(decoderInputBufferIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
+                        inputDone = true
+                    } else {
+                        decoder.queueInputBuffer(decoderInputBufferIndex, 0, chunkSize, extractor.sampleTime, 0)
+                        samplesExtracted++
+                        extractor.seekTo(duration * samplesExtracted / thumbnailCount, MediaExtractor.SEEK_TO_CLOSEST_SYNC)
+                    }
+                }
+            }
+            val outputBufIndex = decoder.dequeueOutputBuffer(info, VideoTranscoder.TIMEOUT_USEC.toLong())
+            if (outputBufIndex >= 0) {
+                if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) {
+                    outputDone = true
+                }
+                val shouldRender = info.size != 0
+                decoder.releaseOutputBuffer(outputBufIndex, shouldRender)
+                if (shouldRender) {
+                    outputSurface.awaitNewImage()
+                    outputSurface.drawImage(false)
+                    if (thumbnailIndex < thumbnailCount) {
+                        byteBuffer.rewind()
+                        GLES20.glReadPixels(0, 0, outputWidth, outputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuffer)
+                        val bitmap = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888)
+                        byteBuffer.rewind()
+                        bitmap.copyPixelsFromBuffer(byteBuffer)
+                        if (!listener.setThumbnail(thumbnailIndex, bitmap)) {
+                            break
+                        }
+                    }
+                    thumbnailIndex++
+                }
+            }
+        }
+    }
+}

+ 24 - 1
app/src/main/java/ch/threema/app/video/transcoder/MediaComponent.java

@@ -26,9 +26,10 @@ import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.net.Uri;
 
+import androidx.annotation.Nullable;
+
 import java.io.IOException;
 
-import androidx.annotation.Nullable;
 import ch.threema.app.utils.MimeUtil;
 
 /**
@@ -43,6 +44,8 @@ public class MediaComponent {
     private Context mContext;
     private final Uri mSrcUri;
     private final int mType;
+	private String mimeType;
+	private long durationUs;
 
     private MediaExtractor mMediaExtractor;
     private MediaFormat mTrackFormat;
@@ -100,6 +103,18 @@ public class MediaComponent {
         return mType;
     }
 
+	/**
+	 * Get mime type of selected track for this component.
+	 * @return
+	 */
+	public @Nullable String getMimeType() {
+		return mimeType;
+	}
+
+	public long getDurationUs() {
+		return durationUs;
+	}
+
     public void release() {
         mContext = null;
         mMediaExtractor.release();
@@ -139,11 +154,19 @@ public class MediaComponent {
                 mMediaExtractor.selectTrack(index);
                 mSelectedTrackIndex = index;
                 mTrackFormat = trackFormat;
+				this.mimeType = mimeType;
+
+				if (trackFormat.containsKey(MediaFormat.KEY_DURATION)) {
+					this.durationUs = trackFormat.getLong(MediaFormat.KEY_DURATION);
+				} else {
+					this.durationUs = 0L;
+				}
                 return;
             }
         }
 
         mSelectedTrackIndex = -1;
         mTrackFormat = null;
+		mimeType = null;
     }
 }

+ 10 - 44
app/src/main/java/ch/threema/app/video/transcoder/VideoTranscoder.java

@@ -21,7 +21,6 @@
 
 package ch.threema.app.video.transcoder;
 
-import android.annotation.TargetApi;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
@@ -34,9 +33,11 @@ import android.media.MediaMetadataRetriever;
 import android.media.MediaMuxer;
 import android.net.Uri;
 import android.provider.OpenableColumns;
-import android.text.TextUtils;
 import android.view.Surface;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+
 import org.slf4j.Logger;
 
 import java.io.File;
@@ -46,8 +47,6 @@ import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.util.concurrent.atomic.AtomicReference;
 
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
 import ch.threema.app.utils.RuntimeUtil;
 import ch.threema.app.video.transcoder.audio.AbstractAudioTranscoder;
 import ch.threema.app.video.transcoder.audio.AudioComponent;
@@ -57,6 +56,8 @@ import ch.threema.app.video.transcoder.audio.UnsupportedAudioFormatException;
 import ch.threema.base.utils.LoggingUtil;
 import java8.util.Optional;
 
+import static ch.threema.app.video.transcoder.VideoTranscoderUtil.getRoundedSize;
+
 /**
  * Based on https://github.com/groupme/android-video-kit
  *
@@ -73,7 +74,6 @@ import java8.util.Optional;
  * limitations under the License.
  */
 
-@TargetApi(18)
 public class VideoTranscoder {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("VideoTranscoder");
 	private @NonNull Optional<AbstractAudioTranscoder> audioTranscoder = Optional.empty();
@@ -94,8 +94,6 @@ public class VideoTranscoder {
 	private static final int POLLING_ERROR = -1;
 	private static final int POLLING_CANCELED = 1;
 
-	private static final String KEY_ROTATION = "rotation";
-
 	/**
 	 * How long to wait for the next buffer to become available in microseconds.
 	 */
@@ -267,7 +265,7 @@ public class VideoTranscoder {
 		mStats = new Stats();
 		createComponents();
 
-		setOrientationHint();
+		mOrientationHint = VideoTranscoderUtil.getOrientationHint(mContext, mInputVideoComponent, mSrcUri);
 		if (!calculateOutputDimensions()) {
 			throw new UnrecoverableVideoTranscoderException("Unable to calculate dimensions");
 		}
@@ -869,33 +867,6 @@ public class VideoTranscoder {
 		return false;
 	}
 
-	private int getRoundedSize(float ratio, int size) {
-		// width/height need to be a multiple of 2 otherwise mediacodec encoder will crash
-		// with android.media.MediaCodec$CodecException: Error 0xfffffc0e
-		return 16 * Math.round(size * ratio / 16);
-	}
-
-
-	private void setOrientationHint() {
-		MediaFormat trackFormat = mInputVideoComponent.getTrackFormat();
-
-		if (trackFormat.containsKey(KEY_ROTATION)) {
-			mOrientationHint = trackFormat.getInteger(KEY_ROTATION);
-		} else {
-			// do not use automatic resource management on MediaMetadataRetriever
-			final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-			try {
-				retriever.setDataSource(mContext, mSrcUri);
-				String orientation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
-				if (!TextUtils.isEmpty(orientation)) {
-					mOrientationHint = Integer.parseInt(orientation);
-				}
-			} finally {
-				retriever.release();
-			}
-		}
-	}
-
 	private void createOutputFormats() {
 		createVideoOutputFormat();
 
@@ -933,21 +904,21 @@ public class VideoTranscoder {
 
 	private void createVideoDecoder() throws IOException {
 		MediaFormat inputFormat = mInputVideoComponent.getTrackFormat();
-		if(inputFormat == null) {
+		if (inputFormat == null) {
 			throw new UnrecoverableVideoTranscoderException("Could not detect video track");
 		}
 
 		if (mTrimEndTimeMs == TRIM_TIME_END) {
-			if (!inputFormat.containsKey(MediaFormat.KEY_DURATION)) {
+			if (mInputVideoComponent.getDurationUs() == 0L) {
 				throw new UnrecoverableVideoTranscoderException("Video key length duration could not be detected");
 			}
-			outputDurationUs = inputFormat.getLong(MediaFormat.KEY_DURATION);
+			outputDurationUs = mInputVideoComponent.getDurationUs();
 		} else {
 			outputDurationUs = (mTrimEndTimeMs - mTrimStartTimeMs) * 1000;
 		}
 		outputStartTimeUs = mTrimStartTimeMs * 1000;
 
-		mVideoDecoder = MediaCodec.createDecoderByType(getMimeTypeFor(inputFormat));
+		mVideoDecoder = MediaCodec.createDecoderByType(mInputVideoComponent.getMimeType());
 		mVideoDecoder.configure(inputFormat, mOutputSurface.getSurface(), null, 0);
 		mVideoDecoder.start();
 	}
@@ -983,7 +954,6 @@ public class VideoTranscoder {
 				);
 			} finally {
 				retriever.release();
-
 			}
 		}
 
@@ -1042,10 +1012,6 @@ public class VideoTranscoder {
 		}
 	}
 
-	public static String getMimeTypeFor(MediaFormat format) {
-		return format.getString(MediaFormat.KEY_MIME);
-	}
-
 	public static final class Builder {
 		private final Uri mSrcUri;
 		private final File mDestFile;

+ 98 - 0
app/src/main/java/ch/threema/app/video/transcoder/VideoTranscoderUtil.java

@@ -0,0 +1,98 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2019-2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package ch.threema.app.video.transcoder;
+
+import android.content.Context;
+import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.Build;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import ch.threema.base.utils.LoggingUtil;
+
+public class VideoTranscoderUtil {
+	private static final Logger logger = LoggingUtil.getThreemaLogger("VideoTranscoderUtil");
+    private static final String KEY_ROTATION = "rotation"; // not to be confused with MediaFormat.KEY_ROTATION
+
+	public static class OutputDimensions {
+		public int width, height;
+	}
+
+	public static int getRoundedSize(float ratio, int size) {
+		// width/height need to be a multiple of 2 otherwise mediacodec encoder will crash
+		// with android.media.MediaCodec$CodecException: Error 0xfffffc0e
+		return 16 * Math.round(size * ratio / 16);
+	}
+
+	public static int getOrientationHint(Context context, MediaComponent mediaComponent, @NonNull Uri srcUri) {
+		MediaFormat trackFormat = mediaComponent.getTrackFormat();
+
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && trackFormat != null && trackFormat.containsKey(KEY_ROTATION)) {
+			return trackFormat.getInteger(KEY_ROTATION);
+		} else {
+			// do not use automatic resource management on MediaMetadataRetriever
+			final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+			try {
+				retriever.setDataSource(context, srcUri);
+				String orientation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
+				if (!TextUtils.isEmpty(orientation)) {
+					return Integer.parseInt(orientation);
+				}
+			} finally {
+				retriever.release();
+			}
+		}
+		return 0;
+	}
+
+	// smallest width should be equal or slightly larger than targetSize
+	@Nullable
+	public static OutputDimensions calculateOutputDimensions(@NonNull MediaComponent mediaComponent, int targetWidth, int targetHeight) {
+		OutputDimensions outputDimensions = new OutputDimensions();
+		MediaFormat trackFormat = mediaComponent.getTrackFormat();
+
+		if (trackFormat != null) {
+			int inputWidth = trackFormat.getInteger(MediaFormat.KEY_WIDTH);
+			int inputHeight = trackFormat.getInteger(MediaFormat.KEY_HEIGHT);
+
+			if (inputWidth > targetWidth || inputHeight > targetHeight) {
+				float ratio = Math.max(targetWidth / (float) inputWidth, targetHeight / (float) inputHeight);
+				outputDimensions.height = Math.round(inputHeight * ratio);
+				outputDimensions.width = Math.round(inputWidth * ratio);
+			} else {
+				outputDimensions.height = inputHeight;
+				outputDimensions.width = inputWidth;
+			}
+
+			logger.info("Target size: {}x{}, Input dimensions: {}x{}, Output dimensions: {}x{}", targetWidth, targetHeight, inputWidth, inputHeight, outputDimensions.width, outputDimensions.height);
+
+			return outputDimensions;
+		}
+		return null;
+	}
+}

+ 8 - 6
app/src/main/java/ch/threema/app/voicemessage/VoiceRecorderActivity.java

@@ -44,6 +44,12 @@ import android.widget.SeekBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
 import org.slf4j.Logger;
 
 import java.io.File;
@@ -51,11 +57,6 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.Locale;
 
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.lifecycle.DefaultLifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.dialogs.GenericAlertDialog;
@@ -87,6 +88,7 @@ public class VoiceRecorderActivity extends AppCompatActivity implements DefaultL
 	public static final int BLUETOOTH_SAMPLING_RATE_HZ = 8000;
 
 	public static final String VOICEMESSAGE_FILE_EXTENSION = ".aac";
+	private static final int DISCARD_CONFIRMATION_THRESHOLD_SECONDS = 10;
 
 	private enum MediaState {
 		STATE_NONE,
@@ -652,7 +654,7 @@ public class VoiceRecorderActivity extends AppCompatActivity implements DefaultL
 		switch (v.getId()) {
 			case R.id.discard_button:
 				stopAndReleaseMediaPlayer(mediaPlayer);
-				if (status == MediaState.STATE_RECORDING && getRecordingDuration() >= 5) {
+				if (status == MediaState.STATE_RECORDING && getRecordingDuration() >= DISCARD_CONFIRMATION_THRESHOLD_SECONDS) {
 					stopRecording();
 					cancelRecording();
 				} else {

+ 9 - 1
app/src/main/java/ch/threema/app/voip/activities/CallActivity.java

@@ -1515,7 +1515,15 @@ public class CallActivity extends ThreemaActivity implements
 					// Call is not yet connected
 					this.commonViews.callDuration.setVisibility(View.GONE);
 					this.commonViews.callStatus.setVisibility(View.VISIBLE);
-					this.commonViews.callStatus.setText(getString(R.string.voip_status_connecting));
+					if (this.voipStateService.isPeerRinging()) {
+						this.commonViews.callStatus.setText(getString(R.string.voip_status_ringing));
+					} else {
+						// If it is not ringing, show initialization text. The connecting state is
+						// usually very short and it is unlikely to restart this activity in this
+						// state. However, if it is still resumed while connecting, the call will be
+						// initialized very soon anyway and the call status text will be replaced.
+						this.commonViews.callStatus.setText(getString(R.string.voip_status_initializing));
+					}
 					if (this.videoViews != null) {
 						this.videoViews.switchCamButton.setVisibility(View.GONE);
 					}

+ 12 - 4
app/src/main/java/ch/threema/app/voip/listeners/VoipCallEventListener.java

@@ -21,8 +21,11 @@
 
 package ch.threema.app.voip.listeners;
 
+import java.util.Date;
+
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 /**
  * Events that happen before, during and after a call
@@ -47,34 +50,39 @@ public interface VoipCallEventListener {
 	/**
 	 * A call was finished.
 	 *
+	 * @param callId The call id of the finished call (might be 0).
 	 * @param peerIdentity The identity of the peer.
 	 * @param outgoing Whether this is an outgoing call (initiated by us).
 	 * @param duration The duration of the call in seconds.
 	 */
-	@AnyThread void onFinished(@NonNull String peerIdentity, boolean outgoing, int duration);
+	@AnyThread void onFinished(long callId, @NonNull String peerIdentity, boolean outgoing, int duration);
 
 	/**
 	 * A call was rejected.
 	 *
+	 * @param callId The call id of the rejected call (might be 0).
 	 * @param peerIdentity The identity of the peer.
 	 * @param outgoing Whether the rejected call was an outgoing call (initiated by us).
 	 * @param reason The reject reason. The meaning can be determined using the
 	 *     `VoipCallAnswerData.RejectReason` class.
 	 */
-	@AnyThread void onRejected(String peerIdentity, boolean outgoing, byte reason);
+	@AnyThread void onRejected(long callId, String peerIdentity, boolean outgoing, byte reason);
 
 	/**
 	 * An incoming call was missed or failed to be established.
 	 *
+	 * @param callId The call id of the missed call (might be 0).
 	 * @param peerIdentity The identity of the peer.
 	 * @param accepted Whether the call was accepted by the user or not.
+	 * @param date The created-at date of the hangup message, or {@code null} if the current date should be used
 	 */
-	@AnyThread void onMissed(String peerIdentity, boolean accepted);
+	@AnyThread void onMissed(long callId, String peerIdentity, boolean accepted, @Nullable Date date);
 
 	/**
 	 * An outgoing call was aborted or failed to be established.
 	 *
+	 * @param callId The call id of the aborted call (might be 0).
 	 * @param peerIdentity The identity of the peer.
 	 */
-	@AnyThread void onAborted(String peerIdentity);
+	@AnyThread void onAborted(long callId, String peerIdentity);
 }

+ 2 - 1
app/src/main/java/ch/threema/app/voip/services/VoipCallService.java

@@ -1214,6 +1214,7 @@ public class VoipCallService extends LifecycleService implements PeerConnectionC
 				logCallInfo(callId, "Peer device is ringing");
 				startLoopingSound(callId, R.raw.ringing_tone, "ringing");
 				VoipUtil.sendVoipBroadcast(getAppContext(), CallActivity.ACTION_PEER_RINGING);
+				voipStateService.setPeerRinging(true);
 
 				if (launchVideo) {
 					startCapturing();
@@ -1471,7 +1472,7 @@ public class VoipCallService extends LifecycleService implements PeerConnectionC
 					} else if (duration == null) {
 						logger.error("duration is null in disconnect()");
 					} else {
-						listener.onFinished(contactIdentity, isInitiator, duration);
+						listener.onFinished(callId, contactIdentity, isInitiator, duration);
 					}
 				});
 			}

+ 86 - 7
app/src/main/java/ch/threema/app/voip/services/VoipStateService.java

@@ -49,10 +49,12 @@ import org.webrtc.SessionDescription;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
@@ -98,6 +100,7 @@ import ch.threema.domain.protocol.csp.messages.voip.VoipCallRingingData;
 import ch.threema.domain.protocol.csp.messages.voip.VoipCallRingingMessage;
 import ch.threema.domain.protocol.csp.messages.voip.VoipICECandidatesData;
 import ch.threema.domain.protocol.csp.messages.voip.VoipICECandidatesMessage;
+import ch.threema.domain.protocol.csp.messages.voip.VoipMessage;
 import ch.threema.domain.protocol.csp.messages.voip.features.VideoFeature;
 import ch.threema.storage.models.ContactModel;
 import java8.util.concurrent.CompletableFuture;
@@ -152,6 +155,7 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 	private volatile Boolean initiator = null;
 	private final CallState callState = new CallState();
 	private Long callStartTimestamp = null;
+	private boolean isPeerRinging = false;
 
 	// Map that stores incoming offers
 	private final HashMap<Long, VoipCallOfferData> offerMap = new HashMap<>();
@@ -162,6 +166,9 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 	// Candidate cache
 	private final Map<String, List<VoipICECandidatesData>> candidatesCache;
 
+	// Call cache
+	private final Set<Long> recentCallIds = new HashSet<>();
+
 	// Notifications
 	private final List<String> callNotificationTags = new ArrayList<>();
 	private MediaPlayerStateWrapper ringtonePlayer;
@@ -294,6 +301,12 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 			newState.getName(), newState.getCallId(), newState.getIncomingCallCounter()
 		);
 
+		// As soon as the callers state changes from initializing to another state, the callee is
+		// not ringing anymore
+		if (oldState.isInitializing()) {
+			isPeerRinging = false;
+		}
+
 		// Clear pending accept intent
 		if (!newState.isRinging()) {
 			this.acceptIntent = null;
@@ -309,6 +322,11 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 		if (newState.isDisconnecting() || newState.isIdle()) {
 			audioManager.unregisterMediaButtonEventReceiver(new ComponentName(appContext, VoipMediaButtonReceiver.class));
 		}
+
+		long callId = oldState.getCallId();
+		if (callId != 0L) {
+			recentCallIds.add(callId);
+		}
 	}
 
 	/**
@@ -442,6 +460,25 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 		}
 	}
 
+	/**
+	 * Set the current state of the peer device regarding ringing.
+	 *
+	 * @param isPeerRinging the current peer ringing state
+	 */
+	public void setPeerRinging(boolean isPeerRinging) {
+		this.isPeerRinging = isPeerRinging;
+	}
+
+	/**
+	 * Check whether the peer device is currently ringing. This function returns {@code true} from
+	 * the time the other device rings until the call state changes on this device.
+	 *
+	 * @return {@code true} if the other device is ringing, {@code false} otherwise
+	 */
+	public boolean isPeerRinging() {
+		return this.isPeerRinging;
+	}
+
 	//endregion
 
 	/**
@@ -741,7 +778,7 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 				case VoipCallAnswerData.Action.REJECT:
 					// TODO: only for tests!
 					VoipListenerManager.callEventListener.handle(listener -> {
-						listener.onRejected(msg.getFromIdentity(), false, callAnswerData.getRejectReason());
+						listener.onRejected(callId, msg.getFromIdentity(), false, callAnswerData.getRejectReason());
 					});
 					logCallInfo(callId, "Call answer received from {}: reject/{}",
 						msg.getFromIdentity(), callAnswerData.getRejectReasonName());
@@ -885,10 +922,16 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 		// Validate Call ID
 		//
 		// NOTE: Hangup messages from older Threema versions may not have any associated data!
+		// NOTE: If a remote hangup message arrives with an invalid call id that does not appear
+		// in the call history, it is a missed call
 		final long callId = msg.getData() == null
 			? 0L
 			: msg.getData().getCallIdOrDefault(0L);
 		if (!this.isCallIdValid(callId)) {
+			if (isMissedCall(msg, callId)) {
+				handleMissedCall(msg, callId);
+				return true;
+			}
 			logger.info(
 				"Call hangup message received from {} for an invalid Call ID ({}, local={}), ignoring",
 				msg.getFromIdentity(), callId, this.callState.getCallId()
@@ -925,18 +968,31 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 			VoipListenerManager.callEventListener.handle(
 				listener -> {
 					final boolean accepted = prevState.isInitializing();
-					listener.onMissed(identity, accepted);
+					listener.onMissed(callId, identity, accepted, msg.getDate());
 				}
 			);
 		} else if (prevState.isCalling() && duration != null) {
 			VoipListenerManager.callEventListener.handle(listener -> {
-				listener.onFinished(msg.getFromIdentity(), !incoming, duration);
+				listener.onFinished(callId, msg.getFromIdentity(), !incoming, duration);
 			});
 		}
 
 		return true;
 	}
 
+	/**
+	 * Handle a missed call.
+	 *
+	 * @param msg the hangup message of the missed call
+	 * @param callId the call id of the missed call
+	 */
+	private void handleMissedCall(@NonNull final VoipCallHangupMessage msg, final long callId) {
+		logger.info("Missed call received from {} with call id {}", msg.getFromIdentity(), callId);
+		VoipListenerManager.callEventListener.handle(
+			listener -> listener.onMissed(callId, msg.getFromIdentity(), false, msg.getDate())
+		);
+	}
+
 	//endregion
 
 	/**
@@ -965,6 +1021,29 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 		return false;
 	}
 
+	/**
+	 * Check whether this hangup voip message is a missed call.
+	 *
+	 * @param msg the received voip message that is checked for a missed call
+	 * @param callId the call id
+	 * @return {@code true} if it is a missed call, {@code false} otherwise
+	 */
+	public boolean isMissedCall(VoipMessage msg, long callId) {
+		if (recentCallIds.contains(callId)) {
+			logger.info("No missed call: call id {} is contained in recent call ids", callId);
+			return false;
+		}
+		// Limit the check to the last 4 calls. Note that only call status messages with the
+		// contact of this hangup message are considered.
+		if (contactService.createReceiver(contactService.getByIdentity(msg.getFromIdentity())).hasVoipCallStatus(callId, 4)) {
+			logger.info("No missed call: call id {} found in database", callId);
+			return false;
+		}
+
+		return true;
+	}
+
+
 	/**
 	 * Send a call offer to the specified contact.
 	 *
@@ -1072,10 +1151,10 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 					case VoipCallAnswerData.RejectReason.BUSY:
 					case VoipCallAnswerData.RejectReason.TIMEOUT:
 					case VoipCallAnswerData.RejectReason.OFF_HOURS:
-						listener.onMissed(receiver.getIdentity(), false);
+						listener.onMissed(callId, receiver.getIdentity(), false, null);
 						break;
 					default:
-						listener.onRejected(receiver.getIdentity(), true, reason);
+						listener.onRejected(callId, receiver.getIdentity(), true, reason);
 						break;
 				}
 			});
@@ -1236,9 +1315,9 @@ public class VoipStateService implements AudioManager.OnAudioFocusChangeListener
 			VoipListenerManager.callEventListener.handle(
 				listener -> {
 					if (outgoing) {
-						listener.onAborted(peerIdentity);
+						listener.onAborted(callId, peerIdentity);
 					} else {
-						listener.onMissed(peerIdentity, true);
+						listener.onMissed(callId, peerIdentity, true, null);
 					}
 				}
 			);

+ 14 - 2
app/src/main/java/ch/threema/app/webclient/activities/SessionsActivity.java

@@ -97,6 +97,7 @@ import ch.threema.app.webclient.state.WebClientSessionState;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.utils.Base64;
 import ch.threema.base.utils.LoggingUtil;
+import ch.threema.domain.protocol.ServerAddressProvider;
 import ch.threema.storage.DatabaseServiceNew;
 import ch.threema.storage.models.WebClientSessionModel;
 
@@ -859,12 +860,23 @@ public class SessionsActivity extends ThreemaToolbarActivity
 			// Make sure that all listeners are initialized
 			this.init();
 
+			// Override saltyRtcHost/Port from OPPF?
+			String saltyRtcHost = qrCodeResult.saltyRtcHost;
+			int saltyRtcPort = qrCodeResult.saltyRtcPort;
+			ServerAddressProvider serverAddressProvider = serviceManager.getServerAddressProviderService().getServerAddressProvider();
+			if (serverAddressProvider.getWebOverrideSaltyRtcHost() != null) {
+				saltyRtcHost = serverAddressProvider.getWebOverrideSaltyRtcHost();
+			}
+			if (serverAddressProvider.getWebOverrideSaltyRtcPort() != 0) {
+				saltyRtcPort = serverAddressProvider.getWebOverrideSaltyRtcPort();
+			}
+
 			// Create new session
 			this.sessionService.create(
 				qrCodeResult.key,
 				qrCodeResult.authToken,
-				qrCodeResult.saltyRtcHost,
-				qrCodeResult.saltyRtcPort,
+				saltyRtcHost,
+				saltyRtcPort,
 				qrCodeResult.serverKey,
 				qrCodeResult.isPermanent,
 				qrCodeResult.isSelfHosted,

+ 9 - 9
app/src/main/java/ch/threema/app/webclient/services/instance/message/updater/VoipStatusUpdateHandler.java

@@ -22,18 +22,18 @@
 package ch.threema.app.webclient.services.instance.message.updater;
 
 
-import androidx.annotation.AnyThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.StringDef;
-
 import org.msgpack.core.MessagePackException;
 import org.slf4j.Logger;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Date;
 
+import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringDef;
 import androidx.annotation.WorkerThread;
-
 import ch.threema.app.utils.executor.HandlerExecutor;
 import ch.threema.app.voip.listeners.VoipCallEventListener;
 import ch.threema.app.voip.managers.VoipListenerManager;
@@ -122,22 +122,22 @@ public class VoipStatusUpdateHandler extends MessageUpdater {
 		}
 
 		@Override
-		public void onFinished(@NonNull String peerIdentity, boolean outgoing, int duration) {
+		public void onFinished(long callId, @NonNull String peerIdentity, boolean outgoing, int duration) {
 			this.update(VoipStatus.convertOnFinished(peerIdentity, outgoing, duration), TYPE_FINISHED);
 		}
 
 		@Override
-		public void onRejected(String peerIdentity, boolean outgoing, byte reason) {
+		public void onRejected(long callId, String peerIdentity, boolean outgoing, byte reason) {
 			this.update(VoipStatus.convertOnRejected(peerIdentity, outgoing, reason), TYPE_REJECTED);
 		}
 
 		@Override
-		public void onMissed(String peerIdentity, boolean accepted) {
+		public void onMissed(long callId, String peerIdentity, boolean accepted, @Nullable Date date) {
 			this.update(VoipStatus.convertOnMissed(peerIdentity), TYPE_MISSED);
 		}
 
 		@Override
-		public void onAborted(String peerIdentity) {
+		public void onAborted(long callId, String peerIdentity) {
 			this.update(VoipStatus.convertOnAborted(peerIdentity), TYPE_ABORTED);
 		}
 

+ 43 - 0
app/src/main/java/ch/threema/storage/factories/MessageModelFactory.java

@@ -28,6 +28,7 @@ import net.sqlcipher.Cursor;
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.annotation.NonNull;
 import ch.threema.app.services.MessageService;
 import ch.threema.domain.models.MessageId;
 import ch.threema.storage.CursorHelper;
@@ -357,6 +358,48 @@ public class MessageModelFactory extends AbstractMessageModelFactory {
 		return messageModels;
 	}
 
+	/**
+	 * Check if there is a call with the given identity and call id within the latest calls.
+	 *
+	 * @param identity the identity of the call partner
+	 * @param callId the call id
+	 * @param limit the maximum number of latest calls
+	 * @return {@code true} if this call exists in the latest calls, {@code false} otherwise
+	 */
+	public boolean hasVoipStatusForCallId(@NonNull String identity, long callId, int limit) {
+		QueryBuilder queryBuilder = new QueryBuilder();
+
+		String orderBy = AbstractMessageModel.COLUMN_CREATED_AT + " DESC";
+
+		queryBuilder.appendWhere(AbstractMessageModel.COLUMN_IDENTITY + "=?");
+		queryBuilder.appendWhere(AbstractMessageModel.COLUMN_TYPE + "=?");
+
+		queryBuilder.setTables(this.getTableName());
+
+		Cursor cursor = queryBuilder.query(this.databaseService.getReadableDatabase(),
+			null,
+			null,
+			new String[]{identity, String.valueOf(MessageType.VOIP_STATUS.ordinal())},
+			null,
+			null,
+			orderBy,
+			String.valueOf(limit));
+
+		if (cursor != null) {
+			try (cursor) {
+				List<MessageModel> messageModels = convertList(cursor);
+				for (MessageModel messageModel : messageModels) {
+					if (callId == messageModel.getVoipStatusData().getCallId()) {
+						return true;
+					}
+				}
+			} finally {
+				cursor.close();
+			}
+		}
+		return false;
+	}
+
 	public List<MessageModel> getByIdentityUnsorted(String identity) {
 		return convertList(this.databaseService.getReadableDatabase().query(this.getTableName(),
 				null,

+ 3 - 3
app/src/main/java/ch/threema/storage/models/MessageType.java

@@ -23,9 +23,9 @@ package ch.threema.storage.models;
 
 public enum MessageType {
 	TEXT,
-	IMAGE,
-	VIDEO,
-	VOICEMESSAGE,
+	@Deprecated IMAGE,
+	@Deprecated VIDEO,
+	@Deprecated VOICEMESSAGE,
 	LOCATION,
 	CONTACT,
 	STATUS,

+ 1 - 0
app/src/main/java/ch/threema/storage/models/data/media/AudioDataModel.java

@@ -32,6 +32,7 @@ import java.io.StringWriter;
 import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.Utils;
 
+@Deprecated
 public class AudioDataModel implements MediaMessageDataInterface {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("AudioDataModel");
 

+ 1 - 0
app/src/main/java/ch/threema/storage/models/data/media/ImageDataModel.java

@@ -33,6 +33,7 @@ import ch.threema.app.utils.TestUtil;
 import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.Utils;
 
+@Deprecated
 public class ImageDataModel implements MediaMessageDataInterface {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("ImageDataModel");
 

+ 3 - 1
app/src/main/java/ch/threema/storage/models/data/media/VideoDataModel.java

@@ -24,16 +24,18 @@ package ch.threema.storage.models.data.media;
 import android.util.JsonReader;
 import android.util.JsonWriter;
 
+import androidx.annotation.NonNull;
+
 import org.slf4j.Logger;
 
 import java.io.StringReader;
 import java.io.StringWriter;
 
-import androidx.annotation.NonNull;
 import ch.threema.app.utils.StringConversionUtil;
 import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.Utils;
 
+@Deprecated
 public class VideoDataModel implements MediaMessageDataInterface {
 	private static final Logger logger = LoggingUtil.getThreemaLogger("VideoDataModel");
 

+ 2 - 2
app/src/main/java/ch/threema/storage/models/data/status/StatusDataModel.java

@@ -40,7 +40,7 @@ public abstract class StatusDataModel {
 	public interface StatusDataModelInterface extends MessageDataInterface {
 		int getType();
 		void readData(String key, String value);
-		void readData(String key, int value);
+		void readData(String key, long value);
 		void readData(String key, boolean value);
 		void readDataNull(String key);
 		void writeData(JsonWriter j) throws IOException;
@@ -74,7 +74,7 @@ public abstract class StatusDataModel {
 						} else if (r.peek() == JsonToken.STRING) {
 							data.readData(key, r.nextString());
 						} else if (r.peek() == JsonToken.NUMBER) {
-							data.readData(key, r.nextInt());
+							data.readData(key, r.nextLong());
 						} else if (r.peek() == JsonToken.BOOLEAN) {
 							data.readData(key, r.nextBoolean());
 						}

+ 41 - 8
app/src/main/java/ch/threema/storage/models/data/status/VoipStatusDataModel.java

@@ -24,6 +24,9 @@ package ch.threema.storage.models.data.status;
 import android.util.JsonWriter;
 
 import java.io.IOException;
+import java.util.Date;
+
+import androidx.annotation.Nullable;
 
 public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInterface {
 	public static final int MISSED = 1;
@@ -32,11 +35,15 @@ public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInter
 	public static final int ABORTED = 4;
 	public static final int TYPE = 1;
 
+	public static final long NO_CALL_ID = 0L;
+
+	private long callId;
 	private int status;
 	private Byte reason;
 	private Integer duration;
+	private Date date;
 
-	protected VoipStatusDataModel(){
+	protected VoipStatusDataModel() {
 		//called by the parser
 	}
 
@@ -47,13 +54,16 @@ public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInter
 	}
 
 	@Override
-	public void readData(String key, int value) {
+	public void readData(String key, long value) {
 		switch (key) {
+			case "callId":
+				this.callId = value;
+				break;
 			case "status":
-				this.status = value;
+				this.status = (int) value;
 				break;
 			case "duration":
-				this.duration = value;
+				this.duration = (int) value;
 				break;
 			case "reason":
 				if (value <= 0Xff) {
@@ -75,6 +85,9 @@ public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInter
 	@Override
 	public void writeData(JsonWriter j) throws IOException {
 		j.name("status").value(this.status);
+		if (this.callId != NO_CALL_ID) {
+			j.name("callId").value(this.callId);
+		}
 		if (this.reason != null) {
 			j.name("reason").value(this.reason);
 		}
@@ -88,6 +101,10 @@ public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInter
 		// TODO
 	}
 
+	public long getCallId() {
+		return this.callId;
+	}
+
 	public int getStatus() {
 		return this.status;
 	}
@@ -100,28 +117,44 @@ public class VoipStatusDataModel implements StatusDataModel.StatusDataModelInter
 		return this.reason;
 	}
 
-	public static VoipStatusDataModel createRejected(Byte reason) {
+	/**
+	 * This is used for hangup messages that indicate a missed call. If it is null, then the
+	 * current time should be used.
+	 *
+	 * @return
+	 */
+	@Nullable
+	public Date getDate() {
+		return date;
+	}
+
+	public static VoipStatusDataModel createRejected(long callId, Byte reason) {
 		VoipStatusDataModel status = (new VoipStatusDataModel());
+		status.callId = callId;
 		status.reason = reason;
 		status.status = REJECTED;
 		return status;
 	}
 
-	public static VoipStatusDataModel createFinished(int duration) {
+	public static VoipStatusDataModel createFinished(long callId, int duration) {
 		VoipStatusDataModel status = (new VoipStatusDataModel());
+		status.callId = callId;
 		status.duration = duration;
 		status.status = FINISHED;
 		return status;
 	}
 
-	public static VoipStatusDataModel createMissed() {
+	public static VoipStatusDataModel createMissed(long callId, @Nullable Date date) {
 		VoipStatusDataModel status = (new VoipStatusDataModel());
+		status.callId = callId;
 		status.status = MISSED;
+		status.date = date;
 		return status;
 	}
 
-	public static VoipStatusDataModel createAborted() {
+	public static VoipStatusDataModel createAborted(long callId) {
 		VoipStatusDataModel status = (new VoipStatusDataModel());
+		status.callId = callId;
 		status.status = ABORTED;
 		return status;
 	}

+ 27 - 0
app/src/main/res/drawable-v24/ic_launcher_monochrome.xml

@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="1682.4324"
+    android:viewportHeight="1682.4324">
+  <group android:translateX="218.71622"
+      android:translateY="218.71622">
+    <path
+        android:pathData="M678.95,957.99C678.95,988.94 653.91,1014 622.95,1014C592.04,1014 567,988.94 567,957.99C567,927.1 592.04,902 622.95,902C653.91,902 678.95,927.1 678.95,957.99ZM477,957.99C477,988.94 451.96,1014 421,1014C390.09,1014 365.05,988.94 365.05,957.99C365.05,927.1 390.09,902 421,902C451.96,902 477,927.1 477,957.99ZM880.9,957.99C880.9,988.94 855.86,1014 824.9,1014C793.99,1014 768.95,988.94 768.95,957.99C768.95,927.1 793.99,902 824.9,902C855.86,902 880.9,927.1 880.9,957.99Z"
+        android:strokeWidth="1"
+        android:fillColor="#000000"
+        android:fillType="evenOdd"
+        android:strokeColor="#00000000"/>
+    <path
+        android:pathData="M678.95,957.99C678.95,988.94 653.91,1014 622.95,1014C592.04,1014 567,988.94 567,957.99C567,927.1 592.04,902 622.95,902C653.91,902 678.95,927.1 678.95,957.99ZM477,957.99C477,988.94 451.96,1014 421,1014C390.09,1014 365.05,988.94 365.05,957.99C365.05,927.1 390.09,902 421,902C451.96,902 477,927.1 477,957.99ZM880.9,957.99C880.9,988.94 855.86,1014 824.9,1014C793.99,1014 768.95,988.94 768.95,957.99C768.95,927.1 793.99,902 824.9,902C855.86,902 880.9,927.1 880.9,957.99Z"
+        android:strokeWidth="1"
+        android:fillColor="#000000"
+        android:fillType="evenOdd"
+        android:strokeColor="#00000000"/>
+    <path
+        android:pathData="M478.82,798.79L314,840L349.22,699.1C314.34,653.15 294,597.91 294,538.5C294,378.61 441.3,249 623,249C804.7,249 952,378.61 952,538.5C952,698.39 804.7,828 623,828C571.29,828 522.36,817.5 478.82,798.79L478.82,798.79ZM529.67,514.47L526,514.47C517.72,514.47 511,521.18 511,529.47L511,661C511,669.28 517.72,676 526,676L720,676C728.28,676 735,669.28 735,661L735,529.47C735,521.18 728.28,514.47 720,514.47L716.33,514.47L716.33,477.19C716.33,425.77 674.58,384 622.96,384C571.42,384 529.67,425.77 529.67,477.19L529.67,514.47ZM679,514.47L567,514.47L567,477.2C567,446.35 592.05,421.28 622.97,421.28C653.95,421.28 679,446.35 679,477.2C679,497.81 679,510.23 679,514.47Z"
+        android:strokeWidth="1"
+        android:fillColor="#000000"
+        android:fillType="evenOdd"
+        android:strokeColor="#00000000"/>
+  </group>
+</vector>

+ 3 - 2
app/src/main/res/drawable/ic_arrow_down_ios_black_24dp.xml → app/src/main/res/drawable/ic_chevron_down_slightly_bigger.xml

@@ -4,6 +4,7 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:pathData="M2.115,7.885l10,10l10,-10l-1.77,-1.77l-8.23,8.23l-8.23,-8.23z"
-      android:fillColor="#000000"/>
+      android:fillColor="#FF000000"
+      android:pathData="m6.568,7.64 l5.503,5.503 5.503,-5.503 1.69,1.702 -7.194,7.194 -7.194,-7.194z"
+      android:strokeWidth="1.19892"/>
 </vector>

+ 40 - 0
app/src/main/res/drawable/seekbar_thumb_audio.xml

@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false">
+            <shape
+                android:shape="ring"
+                android:innerRadius="2dp"
+                android:thickness="2dp"
+                android:useLevel="false"
+                android:tint="?attr/colorControlNormal"
+                android:opticalInsetLeft="3dp"
+                android:opticalInsetRight="3dp">
+                <solid
+                    android:color="@android:color/transparent" />
+                <size
+                    android:width="18dp"
+                    android:height="18dp" />
+            </shape>
+        </item>
+    <item android:state_pressed="true"
+        android:id="@+id/pressed"
+        android:drawable="@drawable/seekbar_thumb_audio_pressed" />
+    <item
+        android:id="@+id/unpressed"
+        android:drawable="@android:color/transparent"/>
+</animated-selector>

+ 38 - 0
app/src/main/res/drawable/seekbar_thumb_audio_pressed.xml

@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="seekbar_thumb_pressed_to_unpressed"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="18"
+    android:viewportHeight="18"
+    android:tint="?attr/colorControlActivated"
+    android:opticalInsetLeft="6dp"
+    android:opticalInsetRight="6dp">
+    <group
+        android:name="thumb"
+        android:translateX="9"
+        android:translateY="9"
+        android:scaleX="1.5"
+        android:scaleY="1.5">
+        <path
+            android:name="thumb_path"
+            android:fillColor="#FF000000"
+            android:pathData="M 0.0,-6.0 c 3.3137084988,0.0 6.0,2.6862915012 6.0,6.0 c 0.0,3.3137084988 -2.6862915012,6.0 -6.0,6.0 c -3.3137084988,0.0 -6.0,-2.6862915012 -6.0,-6.0 c 0.0,-3.3137084988 2.6862915012,-6.0 6.0,-6.0 Z" />
+    </group>
+</vector>

+ 1 - 1
app/src/main/res/layout/activity_edit_send_contact.xml

@@ -231,7 +231,7 @@
 			android:layout_width="match_parent"
 			android:layout_height="?attr/actionBarSize"
 			android:visibility="invisible"
-			app:navigationIcon="@drawable/ic_arrow_down_ios_black_24dp"
+			app:navigationIcon="@drawable/ic_chevron_down_slightly_bigger"
 			app:navigationIconTint="?attr/textColorSecondary">
 
 			<TextView

+ 1 - 1
app/src/main/res/layout/activity_media_attach.xml

@@ -119,7 +119,7 @@
 			android:layout_height="?attr/actionBarSize"
 			android:visibility="invisible"
 			app:menu="@menu/activity_media_attach"
-			app:navigationIcon="@drawable/ic_arrow_down_ios_black_24dp"
+			app:navigationIcon="@drawable/ic_chevron_down_slightly_bigger"
 			app:navigationIconTint="?attr/textColorSecondary">
 
 			<LinearLayout

+ 14 - 6
app/src/main/res/layout/conversation_list_item_audio.xml

@@ -14,17 +14,25 @@
 		android:layout_centerVertical="true"
 		android:layout_gravity="center"/>
 
-	<SeekBar
+	<ch.threema.app.ui.AudioProgressBarView
+		style="@style/SeekBar.Audio"
 		android:id="@+id/seek"
 		android:layout_width="fill_parent"
-		android:layout_height="wrap_content"
-		android:paddingLeft="12dp"
-		android:paddingRight="10dp"
+		android:layout_height="48dp"
+		android:layout_marginLeft="50dp"
+		android:layout_marginRight="10dp"
 		android:layout_centerVertical="true"
-		android:layout_marginLeft="@dimen/avatar_size_small"
+		android:paddingLeft="0dp"
+		android:paddingRight="0dp"
 		android:layout_toLeftOf="@+id/document_size_view"
 		android:enabled="false"
-		android:visibility="visible"/>
+		android:visibility="visible"
+		app:barColor="?attr/textColorTertiary"
+		app:barColorActivated="?attr/colorAccent"
+		app:barWidth="3dp"
+		app:spaceWidth="2dp"
+		app:barMinHeight="2dp"
+		app:barHeight="48dp"/>
 
 	<TextView
 		android:id="@+id/document_size_view"

+ 312 - 24
app/src/main/res/layout/fragment_wizard4.xml

@@ -1,39 +1,327 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-				android:layout_width="match_parent"
-				android:layout_height="match_parent"
-				android:paddingBottom="@dimen/wizard_contents_padding">
+                xmlns:app="http://schemas.android.com/apk/res-auto"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingBottom="@dimen/wizard_footer_height"
+                android:paddingLeft="@dimen/wizard_contents_padding_horizontal"
+                android:paddingRight="@dimen/wizard_contents_padding_horizontal"
+                android:paddingTop="@dimen/wizard_contents_padding">
 
 	<TextView
-			style="@style/WizardSubTitleText"
-			android:id="@+id/scooter"
-			android:layout_alignParentTop="true"
+		style="@style/WizardTitleText"
+		android:id="@+id/wizard_welcome"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_centerHorizontal="true"
+		android:layout_marginTop="8dp"
+		android:gravity="center_horizontal"
+		android:text="@string/new_wizard_done_title"/>
+
+	<TextView
+		android:id="@+id/wizard_your_nickname"
+		style="@style/WizardSummaryTitleText"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/wizard_welcome"
+		android:layout_marginTop="@dimen/wizard_paragraph_height"
+		android:text="@string/public_nickname"/>
+
+	<LinearLayout
+		android:id="@+id/wizard_nickname_layout"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/wizard_your_nickname"
+		android:layout_marginTop="8dp"
+		android:gravity="center_vertical"
+		android:orientation="horizontal">
+
+		<ImageView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_marginRight="8dp"
+			app:srcCompat="@drawable/ic_person_outline"
+			app:tint="@android:color/white" />
+
+		<View
+			android:layout_width="1dp"
+			android:layout_height="24dp"
+			android:background="@color/wizard_alpha_background"/>
+
+		<TextView
+			android:id="@+id/wizard_nickname_preset"
+			style="@style/WizardSummaryBodyText"
 			android:layout_width="wrap_content"
 			android:layout_height="wrap_content"
-			android:layout_centerHorizontal="true"
-			android:gravity="center_horizontal"
-			android:text="@string/new_wizard_sync_contacts_explain"
-			android:layout_marginTop="@dimen/wizard_paragraph_height"/>
+			android:layout_marginLeft="8dp"/>
+
+	</LinearLayout>
+
+	<View
+		android:id="@+id/separator1"
+		android:layout_width="match_parent"
+		android:layout_height="1dp"
+		android:layout_below="@id/wizard_nickname_layout"
+		android:layout_marginTop="12dp"
+		android:background="@color/wizard_alpha_background"/>
 
-	<androidx.appcompat.widget.SwitchCompat
-			style="@style/WizardSwitch"
-			android:id="@+id/wizard_switch_sync_contacts"
+	<TextView
+		android:id="@+id/linked_to"
+		style="@style/WizardSummaryTitleText"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/separator1"
+		android:layout_marginTop="@dimen/wizard_summary_spacing"
+		android:text="@string/new_wizard_linked_to"/>
+
+	<LinearLayout
+		android:id="@+id/wizard_phone_layout"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/linked_to"
+		android:layout_marginTop="8dp"
+		android:gravity="center_vertical"
+		android:orientation="horizontal">
+
+		<ImageView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_marginRight="8dp"
+			app:srcCompat="@drawable/ic_call_outline"
+			app:tint="@android:color/white" />
+
+		<View
+			android:layout_width="1dp"
+			android:layout_height="24dp"
+			android:background="@color/wizard_alpha_background"/>
+
+		<FrameLayout
 			android:layout_width="match_parent"
 			android:layout_height="wrap_content"
-			android:layout_below="@id/scooter"
-			android:layout_marginTop="@dimen/wizard_paragraph_height"
-			android:checked="true"
-			android:enabled="true"
-			android:text="@string/prefs_title_sync_contacts"/>
+			android:layout_gravity="center_vertical">
+
+			<TextView
+				android:id="@+id/wizard_phone_preset"
+				style="@style/WizardSummaryBodyText"
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:layout_gravity="center_vertical"
+				android:layout_marginLeft="8dp"/>
+
+			<ProgressBar
+				android:id="@+id/wizard_phone_progress"
+				android:layout_width="24dp"
+				android:layout_height="24dp"
+				android:layout_marginLeft="8dp"
+				android:indeterminate="true"
+				android:maxHeight="24dp"
+				android:maxWidth="24dp"
+				android:visibility="gone"/>
+
+		</FrameLayout>
+
+	</LinearLayout>
+
+	<LinearLayout
+		android:id="@+id/wizard_phone_error_layout"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/wizard_phone_layout"
+		android:layout_marginLeft="40dp"
+		android:orientation="horizontal">
+
+		<ImageView
+			android:id="@+id/wizard_phone_warn"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:src="@drawable/ic_error_red_24dp"
+			android:visibility="gone"/>
+
+		<TextView
+			android:id="@+id/wizard_phone_error_text"
+			style="@style/WizardSummaryBodyText"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_marginLeft="8dp"
+			android:clickable="true"
+			android:ellipsize="end"
+			android:maxLines="2"
+			android:visibility="gone"/>
+
+	</LinearLayout>
+
+	<LinearLayout
+		android:id="@+id/wizard_email_layout"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/wizard_phone_error_layout"
+		android:layout_marginTop="16dp"
+		android:gravity="center_vertical"
+		android:orientation="horizontal">
+
+		<ImageView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_marginRight="8dp"
+			app:srcCompat="@drawable/ic_email_outline"
+			app:tint="@android:color/white" />
+
+		<View
+			android:layout_width="1dp"
+			android:layout_height="24dp"
+			android:background="@color/wizard_alpha_background"/>
+
+		<FrameLayout
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:layout_gravity="center_vertical">
+
+			<TextView
+				android:id="@+id/wizard_email_preset"
+				style="@style/WizardSummaryBodyText"
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:layout_gravity="center_vertical"
+				android:layout_marginLeft="8dp"/>
+
+			<ProgressBar
+				android:id="@+id/wizard_email_progress"
+				android:layout_width="24dp"
+				android:layout_height="24dp"
+				android:layout_marginLeft="8dp"
+				android:indeterminate="true"
+				android:maxHeight="24dp"
+				android:maxWidth="24dp"
+				android:visibility="gone"/>
+
+		</FrameLayout>
+
+	</LinearLayout>
+
+	<LinearLayout
+		android:id="@+id/wizard_email_error_layout"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/wizard_email_layout"
+		android:layout_marginLeft="40dp"
+		android:orientation="horizontal">
+
+		<ImageView
+			android:id="@+id/wizard_email_warn"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:src="@drawable/ic_error_red_24dp"
+			android:visibility="gone"/>
+
+		<TextView
+			android:id="@+id/wizard_email_error_text"
+			style="@style/WizardSummaryBodyText"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_marginLeft="8dp"
+			android:clickable="true"
+			android:ellipsize="end"
+			android:maxLines="2"
+			android:visibility="gone"/>
+
+	</LinearLayout>
+
+	<View
+		android:id="@+id/separator2"
+		android:layout_width="match_parent"
+		android:layout_height="1dp"
+		android:layout_below="@id/wizard_email_error_layout"
+		android:layout_marginTop="12dp"
+		android:background="@color/wizard_alpha_background"/>
+
+	<TextView
+		android:id="@+id/sync_contacts"
+		style="@style/WizardSummaryTitleText"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/separator2"
+		android:layout_marginTop="@dimen/wizard_summary_spacing"
+		android:text="@string/prefs_title_sync_contacts"/>
+
+	<LinearLayout
+		android:id="@+id/sync_layout"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/sync_contacts"
+		android:layout_marginTop="8dp"
+		android:orientation="horizontal">
+
+		<ProgressBar
+			android:id="@+id/wizard_contact_sync_progress"
+			android:layout_width="24dp"
+			android:layout_height="24dp"
+			android:layout_marginRight="8dp"
+			android:indeterminate="true"
+			android:maxHeight="24dp"
+			android:maxWidth="24dp"
+			android:visibility="gone"/>
+
+		<TextView
+			android:id="@+id/sync_contacts_preset"
+			style="@style/WizardSummaryBodyText"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_gravity="center_vertical"/>
+
+	</LinearLayout>
+
+	<View
+		android:id="@+id/separator3"
+		android:layout_width="match_parent"
+		android:layout_height="1dp"
+		android:layout_below="@id/sync_layout"
+		android:layout_marginTop="12dp"
+		android:background="@color/wizard_alpha_background"/>
 
 	<TextView
-		android:id="@+id/disabled_by_policy"
+		android:id="@+id/threema_safe"
+		style="@style/WizardSummaryTitleText"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@id/separator3"
+		android:layout_marginTop="@dimen/wizard_summary_spacing"
+		android:text="@string/threema_safe"/>
+
+	<LinearLayout
+		android:id="@+id/safe_layout"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-		android:layout_marginTop="32dp"
-		android:layout_below="@+id/wizard_switch_sync_contacts"
-		android:textSize="14sp"
-		android:text="@string/disabled_by_policy"
-		android:visibility="gone"/>
+		android:layout_below="@id/threema_safe"
+		android:layout_marginTop="8dp"
+		android:orientation="horizontal">
+
+		<ProgressBar
+			android:id="@+id/threema_safe_progress"
+			android:layout_width="24dp"
+			android:layout_height="24dp"
+			android:layout_marginRight="8dp"
+			android:indeterminate="true"
+			android:maxHeight="24dp"
+			android:maxWidth="24dp"
+			android:visibility="gone"/>
+
+		<TextView
+			android:id="@+id/threema_safe_preset"
+			style="@style/WizardSummaryBodyText"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:maxLines="1"
+			android:ellipsize="end"
+			android:layout_gravity="center_vertical"/>
+
+	</LinearLayout>
+
+	<androidx.appcompat.widget.AppCompatButton
+		android:id="@+id/wizard_finish"
+		style="@style/WizardButtonRegular"
+		android:layout_width="match_parent"
+		android:layout_alignParentBottom="true"
+		android:layout_marginBottom="16dp"
+		android:text="@string/finish"/>
 
 </RelativeLayout>

+ 0 - 327
app/src/main/res/layout/fragment_wizard5.xml

@@ -1,327 +0,0 @@
-<?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"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:paddingBottom="@dimen/wizard_footer_height"
-                android:paddingLeft="@dimen/wizard_contents_padding_horizontal"
-                android:paddingRight="@dimen/wizard_contents_padding_horizontal"
-                android:paddingTop="@dimen/wizard_contents_padding">
-
-	<TextView
-		style="@style/WizardTitleText"
-		android:id="@+id/wizard_welcome"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_centerHorizontal="true"
-		android:layout_marginTop="8dp"
-		android:gravity="center_horizontal"
-		android:text="@string/new_wizard_done_title"/>
-
-	<TextView
-		android:id="@+id/wizard_your_nickname"
-		style="@style/WizardSummaryTitleText"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/wizard_welcome"
-		android:layout_marginTop="@dimen/wizard_paragraph_height"
-		android:text="@string/public_nickname"/>
-
-	<LinearLayout
-		android:id="@+id/wizard_nickname_layout"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/wizard_your_nickname"
-		android:layout_marginTop="8dp"
-		android:gravity="center_vertical"
-		android:orientation="horizontal">
-
-		<ImageView
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginRight="8dp"
-			app:srcCompat="@drawable/ic_person_outline"
-			app:tint="@android:color/white" />
-
-		<View
-			android:layout_width="1dp"
-			android:layout_height="24dp"
-			android:background="@color/wizard_alpha_background"/>
-
-		<TextView
-			android:id="@+id/wizard_nickname_preset"
-			style="@style/WizardSummaryBodyText"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginLeft="8dp"/>
-
-	</LinearLayout>
-
-	<View
-		android:id="@+id/separator1"
-		android:layout_width="match_parent"
-		android:layout_height="1dp"
-		android:layout_below="@id/wizard_nickname_layout"
-		android:layout_marginTop="12dp"
-		android:background="@color/wizard_alpha_background"/>
-
-	<TextView
-		android:id="@+id/linked_to"
-		style="@style/WizardSummaryTitleText"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/separator1"
-		android:layout_marginTop="@dimen/wizard_summary_spacing"
-		android:text="@string/new_wizard_linked_to"/>
-
-	<LinearLayout
-		android:id="@+id/wizard_phone_layout"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/linked_to"
-		android:layout_marginTop="8dp"
-		android:gravity="center_vertical"
-		android:orientation="horizontal">
-
-		<ImageView
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginRight="8dp"
-			app:srcCompat="@drawable/ic_call_outline"
-			app:tint="@android:color/white" />
-
-		<View
-			android:layout_width="1dp"
-			android:layout_height="24dp"
-			android:background="@color/wizard_alpha_background"/>
-
-		<FrameLayout
-			android:layout_width="match_parent"
-			android:layout_height="wrap_content"
-			android:layout_gravity="center_vertical">
-
-			<TextView
-				android:id="@+id/wizard_phone_preset"
-				style="@style/WizardSummaryBodyText"
-				android:layout_width="wrap_content"
-				android:layout_height="wrap_content"
-				android:layout_gravity="center_vertical"
-				android:layout_marginLeft="8dp"/>
-
-			<ProgressBar
-				android:id="@+id/wizard_phone_progress"
-				android:layout_width="24dp"
-				android:layout_height="24dp"
-				android:layout_marginLeft="8dp"
-				android:indeterminate="true"
-				android:maxHeight="24dp"
-				android:maxWidth="24dp"
-				android:visibility="gone"/>
-
-		</FrameLayout>
-
-	</LinearLayout>
-
-	<LinearLayout
-		android:id="@+id/wizard_phone_error_layout"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/wizard_phone_layout"
-		android:layout_marginLeft="40dp"
-		android:orientation="horizontal">
-
-		<ImageView
-			android:id="@+id/wizard_phone_warn"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:src="@drawable/ic_error_red_24dp"
-			android:visibility="gone"/>
-
-		<TextView
-			android:id="@+id/wizard_phone_error_text"
-			style="@style/WizardSummaryBodyText"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginLeft="8dp"
-			android:clickable="true"
-			android:ellipsize="end"
-			android:maxLines="2"
-			android:visibility="gone"/>
-
-	</LinearLayout>
-
-	<LinearLayout
-		android:id="@+id/wizard_email_layout"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/wizard_phone_error_layout"
-		android:layout_marginTop="16dp"
-		android:gravity="center_vertical"
-		android:orientation="horizontal">
-
-		<ImageView
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginRight="8dp"
-			app:srcCompat="@drawable/ic_email_outline"
-			app:tint="@android:color/white" />
-
-		<View
-			android:layout_width="1dp"
-			android:layout_height="24dp"
-			android:background="@color/wizard_alpha_background"/>
-
-		<FrameLayout
-			android:layout_width="match_parent"
-			android:layout_height="wrap_content"
-			android:layout_gravity="center_vertical">
-
-			<TextView
-				android:id="@+id/wizard_email_preset"
-				style="@style/WizardSummaryBodyText"
-				android:layout_width="wrap_content"
-				android:layout_height="wrap_content"
-				android:layout_gravity="center_vertical"
-				android:layout_marginLeft="8dp"/>
-
-			<ProgressBar
-				android:id="@+id/wizard_email_progress"
-				android:layout_width="24dp"
-				android:layout_height="24dp"
-				android:layout_marginLeft="8dp"
-				android:indeterminate="true"
-				android:maxHeight="24dp"
-				android:maxWidth="24dp"
-				android:visibility="gone"/>
-
-		</FrameLayout>
-
-	</LinearLayout>
-
-	<LinearLayout
-		android:id="@+id/wizard_email_error_layout"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/wizard_email_layout"
-		android:layout_marginLeft="40dp"
-		android:orientation="horizontal">
-
-		<ImageView
-			android:id="@+id/wizard_email_warn"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:src="@drawable/ic_error_red_24dp"
-			android:visibility="gone"/>
-
-		<TextView
-			android:id="@+id/wizard_email_error_text"
-			style="@style/WizardSummaryBodyText"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_marginLeft="8dp"
-			android:clickable="true"
-			android:ellipsize="end"
-			android:maxLines="2"
-			android:visibility="gone"/>
-
-	</LinearLayout>
-
-	<View
-		android:id="@+id/separator2"
-		android:layout_width="match_parent"
-		android:layout_height="1dp"
-		android:layout_below="@id/wizard_email_error_layout"
-		android:layout_marginTop="12dp"
-		android:background="@color/wizard_alpha_background"/>
-
-	<TextView
-		android:id="@+id/sync_contacts"
-		style="@style/WizardSummaryTitleText"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/separator2"
-		android:layout_marginTop="@dimen/wizard_summary_spacing"
-		android:text="@string/prefs_title_sync_contacts"/>
-
-	<LinearLayout
-		android:id="@+id/sync_layout"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/sync_contacts"
-		android:layout_marginTop="8dp"
-		android:orientation="horizontal">
-
-		<ProgressBar
-			android:id="@+id/wizard_contact_sync_progress"
-			android:layout_width="24dp"
-			android:layout_height="24dp"
-			android:layout_marginRight="8dp"
-			android:indeterminate="true"
-			android:maxHeight="24dp"
-			android:maxWidth="24dp"
-			android:visibility="gone"/>
-
-		<TextView
-			android:id="@+id/sync_contacts_preset"
-			style="@style/WizardSummaryBodyText"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_gravity="center_vertical"/>
-
-	</LinearLayout>
-
-	<View
-		android:id="@+id/separator3"
-		android:layout_width="match_parent"
-		android:layout_height="1dp"
-		android:layout_below="@id/sync_layout"
-		android:layout_marginTop="12dp"
-		android:background="@color/wizard_alpha_background"/>
-
-	<TextView
-		android:id="@+id/threema_safe"
-		style="@style/WizardSummaryTitleText"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/separator3"
-		android:layout_marginTop="@dimen/wizard_summary_spacing"
-		android:text="@string/threema_safe"/>
-
-	<LinearLayout
-		android:id="@+id/safe_layout"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:layout_below="@id/threema_safe"
-		android:layout_marginTop="8dp"
-		android:orientation="horizontal">
-
-		<ProgressBar
-			android:id="@+id/threema_safe_progress"
-			android:layout_width="24dp"
-			android:layout_height="24dp"
-			android:layout_marginRight="8dp"
-			android:indeterminate="true"
-			android:maxHeight="24dp"
-			android:maxWidth="24dp"
-			android:visibility="gone"/>
-
-		<TextView
-			android:id="@+id/threema_safe_preset"
-			style="@style/WizardSummaryBodyText"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:maxLines="1"
-			android:ellipsize="end"
-			android:layout_gravity="center_vertical"/>
-
-	</LinearLayout>
-
-	<androidx.appcompat.widget.AppCompatButton
-		android:id="@+id/wizard_finish"
-		style="@style/WizardButtonRegular"
-		android:layout_width="match_parent"
-		android:layout_alignParentBottom="true"
-		android:layout_marginBottom="16dp"
-		android:text="@string/finish"/>
-
-</RelativeLayout>

+ 2 - 1
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -2,4 +2,5 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/ic_launcher_background"/>
     <foreground android:drawable="@drawable/ic_launcher_foreground"/>
-</adaptive-icon>
+    <monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
+</adaptive-icon>

+ 16 - 2
app/src/main/res/values-be-rBY/strings.xml

@@ -112,6 +112,7 @@
     <string name="copy_message_action">Капіяваць</string>
     <string name="delete_contact_action">Выдаліць кантакт</string>
     <string name="scan_id">СканавацьID</string>
+    <string name="id_scanned">ID адсканаваны</string>
     <string name="id_mismatch">Адкрыты ключ, які вы адсканавалі, не адпавядае ключу, які захоўваецца на сэрвэры для гэтага ID. Гэта азначае, што нехта змяніў адсканаваны код і ключу нельга давяраць.</string>
     <string name="scan_successful">ID паспяхова адсканаваны, а кантакт правераны.</string>
     <string name="scan_duplicate">Гэты ID ужо быў адсканаваны і правераны.</string>
@@ -507,7 +508,6 @@
     <string name="file_placeholder">Файл</string>
     <string name="internal_storage">Унутранае сховішча</string>
     <string name="no_activity_for_mime_type">Не знайшлі праграму для адкрыцця гэтага файла.</string>
-    <string name="message_copied">Паведамл. скапіявана</string>
     <string name="open_from">Адкрыць з</string>
     <string name="file_one_contact_not_supported">%1$s не можа прымаць файлы.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Увага: %1$d кантакты(аў) не могуць прыняць ваш файл.</string>
@@ -630,6 +630,7 @@
     <string name="new_wizard_info_fingerprint">Соўваючы пальцам па экране, вы ствараеце выпадковыя даныя (званыя энтрапіяй), якія выкарыстоўваюцца для стварэння пары ключоў, звязаных з вашым новым унікальным Threema ID. Пара ключоў складаецца з <b>адчыненага ключа</b>, які рассылаецца вашым сябрам, і <b>зачыненага ключа</b>, які бяспечна захоўваецца ў вашым тэлефоне. Вашыя сябры будуць шыфраваць паведамленні пры дапамозе адчыненага ключа.  Толькі ўладальнік зачыненага ключа, і ніхто іншы, можа расшыфраваць гэтыя паведамленні.</string>
     <string name="new_wizard_info_id">Вы стварылі пару ключоў. Адчынены ключ па абароненым канале перададзены на нашыя сэрверы. Зачынены ключ заўсёды застаецца на вашай прыладзе. Гэта гарантуе, што ніхто іншы не зможа прачытаць вашыя паведамленні.</string>
     <string name="new_wizard_info_sync_contacts">Калі ўключыць гэтую опцыю, Threema шыфруе (хэшуе) адрасы электроннай пошты і нумары мабільных тэлефонаў перад адпраўкай іх на сэрвер, для пошуку адпаведных кантактаў. Мы не захоўваем даныя адраснай кнігі.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">Аўтаматычная сінхранізацыя кантактаў можа дапамагчы вам знайсці вашых сяброў аўтаматычна.  Калі вы згодныя, нумары тэлефонаў і адрасы электроннай пошты з вашай тэлефоннай кнігі будуць зашыфраваны перад адпраўкай на наш сервер для пошуку адпаведных кантактаў.  Абсалютна ніякія даныя не будуць захоўвацца або распаўсюджвацца.\n\n Вы хочаце ўключыць сінхранізацыю кантактаў?</string>
     <string name="new_wizard_info_link">Калі вы пакажаце свой нумар тэлефона і адрас электроннай пошты, Threema дапаможа вашым сябрам аўтаматычна знайсці вас, калі вы запісаны ў іх тэлефоннай кнізе.
 Адрасы электроннай пошты будуць захоўвацца ў зашыфраваным (хэшаваным) выглядзе на нашым сэрверы. Вы можаце прапусціць гэты крок, калі хочаце выкарыстоўваць Threema ананімна.</string>
     <string name="new_wizard_info_link_phone_only">Калі вы пакажаце свой нумар тэлефона, Threema дапаможа вашым сябрам аўтаматычна знайсці вас, калі вы запісаны ў іх тэлефоннай кнізе.
@@ -816,6 +817,7 @@
     <string name="unpin">Зняць</string>
     <string name="location_services_disabled">Службы вызначэння месцазнаходжання адключаны. Хочаце ўключыць іх зараз?</string>
     <string name="send_location">Адправіць месцазн.</string>
+    <string name="forward_location">Месцазнаходжанне</string>
     <string name="unknown_address">Невядомы адрас</string>
     <string name="your_location">Ваша месцазнаходж.</string>
     <string name="network_blocked_title">Фонавая перадача даных адключана</string>
@@ -1379,6 +1381,12 @@
     <string name="spam_report_short">Справаздача</string>
     <string name="wizard_incompatible_contact_sync_params">Устаноўлены несумяшчальныя параметры MDM.  Параметр Threema MDM th_contact_sync не можа мець значэнне true, калі ўсталявана абмежаванне карыстальніка DISALLOW_MODIFY_ACCOUNTS.  Звярніцеся да адміністратара вашай прылады.</string>
     <string name="messages_cannot_be_recovered">Вы не зможаце аднавіць паведамленні.</string>
+    <string name="contact_deleted">Кантакт выдалены</string>
+    <string name="last_added_contact">Апошні дададзены</string>
+    <string name="directory_explain_text">Шукайце ў каталогу кампаніі супрацоўнікаў, якіх яшчэ няма ў вашым спісе кантактаў.</string>
+    <string name="cannot_display_location">Гэта месца не можа быць паказана.</string>
+    <string name="unable_to_restore_identity_because">Немагчыма аднавіць ID. Прычына: %s</string>
+    <string name="share_with_app">Падзяліцеся з Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="few">%d кантактаў</item>
         <item quantity="many">%d кантакты</item>
@@ -1386,9 +1394,9 @@
         <item quantity="other">%d кантактаў</item>
     </plurals>
     <plurals name="really_delete_thread_message">
-        <item quantity="one">Вы сапраўды хочаце выдаліць %d чат?</item>
         <item quantity="few">Вы сапраўды хочаце выдаліць %d чат?</item>
         <item quantity="many">Вы сапраўды хочаце выдаліць %d чат?</item>
+        <item quantity="one">Вы сапраўды хочаце выдаліць %d чат?</item>
         <item quantity="other">Вы сапраўды хочаце выдаліць %d чат?</item>
     </plurals>
     <plurals name="sending_message_failed">
@@ -1403,4 +1411,10 @@
         <item quantity="one">Выбрана відарысаў %d</item>
         <item quantity="other">Выбрана %d відарысаў</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one" tools:ignore="ImpliedQuantity">Паведамленне скапіявана</item>
+        <item quantity="other">Паведамленні скапіяваны</item>
+        <item quantity="few">Паведамленні скапіяваны</item>
+        <item quantity="many">Паведамленні скапіяваны</item>
+    </plurals>
 </resources>

+ 1 - 1
app/src/main/res/values-be-rBY/voicemessage_strings.xml

@@ -2,7 +2,7 @@
 <resources>
     <string name="recording">Паведамленне запісваецца..</string>
     <string name="recording_stopped_title">Запіс спынены</string>
-    <string name="recording_stopped_message">Жадаеце адправіць запісанае галасавое паведамленне?</string>
+    <string name="recording_stopped_message">Хочаце адправіць запісанае галасавое паведамленне?</string>
     <string name="recording_canceled">Запіс адменены з-за невядомай памылкі.</string>
     <string name="cancel_recording">Адмяніць запіс</string>
     <string name="cancel_recording_message">Сапраўды адмяніць і выдаліць запіс?</string>

+ 1 - 1
app/src/main/res/values-be-rBY/voip_strings.xml

@@ -8,7 +8,7 @@
     <string name="voip_switch_cam_front">Пераключана на пярэднюю камеру</string>
     <string name="voip_switch_cam_rear">Пераключана на заднюю камеру</string>
     <string name="voip_toggle_video">Пераключыць рэжым відэа</string>
-    <string name="voip_call_confirm">Жадаеце патэлефанаваць карыстачу %1$s?</string>
+    <string name="voip_call_confirm">Хочаце патэлефанаваць карыстачу %1$s?</string>
     <string name="voip_error_call">Памылка падчас званка Threema</string>
     <string name="voip_error_init_call">Памылка ініцыялізацыі званка</string>
     <string name="voip_notification_title">Уваходны званок Threema</string>

+ 1 - 1
app/src/main/res/values-be-rBY/webclient_strings.xml

@@ -27,7 +27,7 @@
     <string name="webclient_protocol_version_too_new_selfhosted">Ваша праграма не падтрымлівае дадзеную версію праграмы для ПК / вэб-кліента. Загрузіце апошнюю версію праграмы для ПК ці папытаеце адміністратара вэб-кліента перайсці на апошнюю версію.</string>
     <string name="webclient_protocol_version_too_new_threema">Ваша праграма не падтрымлівае дадзеную версію праграмы для ПК / вэб-кліента. Выкарыстоўвайце навейшую версію праграмы для ПК / вэб-кліента.</string>
     <string name="webclient_session_already_exists">Сесія, якая адпавядае сканаванаму вамі QR-коду, ужо існуе.  Перазапусціце праграму для ПК / перазапусціце вэб-кліент і паспрабуйце яшчэ раз.</string>
-    <string name="webclient_really_start_webclient_by_payload_body">Жадаеце запусціць гэтую сесію?</string>
+    <string name="webclient_really_start_webclient_by_payload_body">Хочаце запусціць гэтую сесію?</string>
     <string name="webclient_cannot_restore">Не ўдаецца аднавіць сесію</string>
     <string name="webclient_disabled">Праграма для ПК/вэб-в. не актываваная</string>
     <string name="webclient_cannot_start">Не ўдаецца запусціць сесію</string>

+ 5 - 6
app/src/main/res/values-ca/strings.xml

@@ -227,8 +227,8 @@ de continuar.</string>
     <string name="masterkey_is_unlocked">La clau mestra està desbloquejada</string>
     <string name="file_too_large">El fitxer és més gran que el màxim de %1$d MB</string>
     <string name="deleting_thread">Esborrant el xat</string>
-    <string name="enter_serial_body">Entreu la vostra clau de llicència de la botiga per obtenr la vostra clau:
-https://shop.threema.ch/retrieve_keys</string>
+    <string name="enter_serial_body"><![CDATA[Entreu la vostra clau de llicència de la botiga per obtenr la vostra clau:
+https://shop.threema.ch/retrieve_keys]]></string>
     <string name="enter_serial_title">Desbloquejar Threema</string>
     <string name="serial_required_want_exit">La clau de llicència no és vàlida. Voleu intentar-ho de nou o tancar Threema?</string>
     <string name="checking_serial">Comprovant la llicència</string>
@@ -516,7 +516,6 @@ de contacte</string>
     <string name="file_placeholder">Fitxer</string>
     <string name="internal_storage">Emmagatzematge intern</string>
     <string name="no_activity_for_mime_type">No s\'ha trobat cap aplicació que obri el fitxer.</string>
-    <string name="message_copied">Missatge copiat</string>
     <string name="open_from">Obrir des de</string>
     <string name="file_one_contact_not_supported">%1$s no pot rebre fitxers.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Atenció: %1$d contactes no poden rebre el vostre fitxer.</string>
@@ -1027,7 +1026,7 @@ donar només el vostre nom o un pseudònim. Si no definiu un sobrenom utilitzare
     <string name="delete">Eliminar</string>
     <string name="num_archived_chats">%d xats arxivats</string>
     <string name="continue_recording">Continuar gravant</string>
-	<string name="tap_to_start">Toqueu aquí per iniciar %s ara.</string>
+    <string name="tap_to_start">Toqueu aquí per iniciar %s ara.</string>
     <string name="two_years">2 anys</string>
     <string name="invalid_backup_path">Camí de còpia no vàlid</string>
     <string name="backup_data_no_permission">No es pot escriure en aquest directori. Escolliu-ne un altre.</string>
@@ -1316,12 +1315,12 @@ donar només el vostre nom o un pseudònim. Si no definiu un sobrenom utilitzare
     <string name="web_link">Enllaç</string>
     <string name="link_copied">%s copiat</string>
     <string name="invalid_onprem_id_title">No es pot Afegir la ID</string>
-    <string name="full_name">Nom</string>
     <string name="name_given">Nom</string>
     <string name="name_family">Cognoms</string>
     <string name="name_prefix">Prefix del nom</string>
     <string name="name_middle">Segon nom</string>
     <string name="name_suffix">Sufix del nom</string>
+    <string name="full_name">Nom</string>
     <string name="phoneTypeCustom">Personalitzat</string>
     <string name="phoneTypeHome">Casa</string>
     <string name="phoneTypeMobile">Mòbil</string>
@@ -1349,7 +1348,7 @@ donar només el vostre nom o un pseudònim. Si no definiu un sobrenom utilitzare
     <string name="relationTypeSpouse">Cònjuge</string>
     <string name="contact_property_key">"Clau"</string>
     <string name="header_nickname_entry">"Àlies"</string>
-	<string name="organization_type">Organització</string>
+    <string name="organization_type">Organització</string>
     <string name="messages_cannot_be_recovered">No podreu recuperar els missatges.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contacte</item>

+ 12 - 3
app/src/main/res/values-cs/strings.xml

@@ -112,6 +112,7 @@
     <string name="copy_message_action">Zkopírovat</string>
     <string name="delete_contact_action">Odstranit kontakt</string>
     <string name="scan_id">Skenovat ID</string>
+    <string name="id_scanned">ID oskenováno</string>
     <string name="id_mismatch">Naskenovaný veřejný klíč se neshoduje s klíčem, který je uložen na serveru pro toto ID. To znamená, že někdo s naskenovaným kódem manipuloval, a klíč proto nelze považovat za důvěryhodný.</string>
     <string name="scan_successful">ID bylo úspěšně naskenováno a kontakt je nyní ověřen.</string>
     <string name="scan_duplicate">Toto ID již bylo naskenováno a ověřeno.</string>
@@ -510,7 +511,6 @@ https://myid.threema.ch/revoke</string>
     <string name="file_placeholder">Soubor</string>
     <string name="internal_storage">Vnitřní úložiště</string>
     <string name="no_activity_for_mime_type">Nebyla nalezena žádná aplikace schopná otevřít tento soubor.</string>
-    <string name="message_copied">Zpráva zkopírována</string>
     <string name="open_from">Otevřít z</string>
     <string name="file_one_contact_not_supported">Kontakt %1$s nemůže přijímat soubory.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Upozornění: Následující počet kontaktů: %1$d nemůže přijmout váš soubor.</string>
@@ -635,6 +635,7 @@ možné je obnovit.</string>
     <string name="new_wizard_info_id">Vytvořili jste dvojici šifrovacích klíčů. Veřejný klíč byl bezpečně přenesen na naše servery. Soukromý klíč nikdy neopustí vaše zařízení. Tím je zajištěno, že nikdo nepovolaný se nebude moci dostat k vašim zprávám.</string>
     <string name="new_wizard_info_sync_contacts">Pokud tuto možnost povolíte, odešlou se jednosměrně šifrované (hashované) e‑mailové adresy a telefonní čísla z vašich kontaktů na náš server. Zde se porovnají s kontakty ostatních uživatelů. V případě shody se u vás kontakt zobrazí v adresáři.
 Na našich serverech neukládáme žádná data z vašeho adresáře.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">Synchronizace kontaktů vám může pomoci najít vaše přátele automaticky. Pokud budete souhlasit, telefonní čísla a e‑mailové adresy z vašeho telefonního seznamu budou před odesláním na naše servery zašifrovány, aby mohly být vyhledány odpovídající kontakty. Žádná data nebudou uložena nebo sdílena.\n\nPřejete si povolit synchronizaci kontaktů?</string>
     <string name="new_wizard_info_link">Poskytnete‑li svoje telefonní číslo a e‑mailovou adresu, Threema může vašim kontaktům zajistit automatické přidání vašeho ID do jejich adresářů. Data budou uložena jednosměrně šifrovaná (hashovaná) na našem serveru. Tento krok můžete přeskočit, pokud chcete používat aplikaci Threema zcela anonymně. Toto nastavení lze později změnit.</string>
     <string name="new_wizard_info_link_phone_only">Poskytnete‑li aplikaci Threema své telefonní číslo, umožníte tak svým
 přátelům vás automaticky vyhledat, pokud vás mají v adresáři svého telefonu. Číslo bude na našem serveru uložené v jednosměrně šifrované podobě (hashované). Jestliže chcete používat aplikaci Threema zcela anonymně, můžete tento krok přeskočit.</string>
@@ -1202,7 +1203,7 @@ přátelům vás automaticky vyhledat, pokud vás mají v adresáři svého tel
     <string name="group_request_already_sent"><![CDATA[Požadavek o připojení do skupiny <b>%s</b> již byl pomocí tohoto odkazu odeslán a čeká se na odpověď správce skupiny. Klepněte na požadavek v seznamu, jestliže chcete zkusit odeslání zopakovat.]]></string>
     <string name="group_link_none">Zatím nebyl vygenerován žádný odkaz</string>
     <string name="group_request_confirm_send"><![CDATA[Chystáte se odeslat požadavek o připojení do skupiny <b>%1$s</b> správci <b>%2$s</b>. Jestliže tento odkaz nebyl zneplatněn, budete automaticky přidán(a) do skupiny ve chvíli, kdy zařízení správce obdrží váš požadavek.]]></string>
-    <string name="really_delete_outgoing_request">Skutečně si přejete odstranit následující počet požadavků o připojení do skupiny: %d? Mějte na paměti, že požadavek nebude odvolán a přesto můžete být přijat(a) nebo zamítnut(a), jestliže požadavek dosud nebyl vyřízen. Totéž platí i pro více požadavků.</string>
+    <string name="really_delete_outgoing_request">Skutečně si přejete odstranit následující počet požadavků o připojení do skupiny: %d? Mějte na paměti, že požadavek nebude odvolán a přesto můžete být přijat(a) nebo zamítnut(a), jestliže požadavek dosud nebyl vyřízen administrátorem skupiny. Totéž platí i pro více požadavků.</string>
     <string name="really_delete_group_request_title">Skutečně odstranit požadavek o připojení do skupiny?</string>
     <string name="sent_to">Odesláno: %s</string>
     <string name="sent_on">Odesláno: %s</string>
@@ -1389,6 +1390,8 @@ přátelům vás automaticky vyhledat, pokud vás mají v adresáři svého tel
     <string name="last_added_contact">Naposledy přidaný</string>
     <string name="directory_explain_text">Vyhledá v adresáři společnosti jakékoliv zaměstnance, kteří dosud nejsou ve vašem seznamu kontaktů.</string>
     <string name="cannot_display_location">Tato poloha nemůže být zobrazena.</string>
+    <string name="unable_to_restore_identity_because">ID nelze obnovit. Důvod: %s</string>
+    <string name="share_with_app">Sdílet s aplikací Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="few">%d kontakty</item>
         <item quantity="many">%d kontaktů</item>
@@ -1408,9 +1411,15 @@ přátelům vás automaticky vyhledat, pokud vás mají v adresáři svého tel
         <item quantity="other">Nezdařilo se odeslat následující počet zpráv: %1$d</item>
     </plurals>
     <plurals name="selection_counter_label">
-        <item quantity="one">Počet vybraných obrázků: %d</item>
         <item quantity="few">Počet vybraných obrázků: %d</item>
         <item quantity="many">Počet vybraných obrázků: %d</item>
+        <item quantity="one">Počet vybraných obrázků: %d</item>
         <item quantity="other">Počet vybraných obrázků: %d</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one">Zpráva zkopírována</item>
+        <item quantity="other">Zpráv zkopírováno</item>
+        <item quantity="few">Zprávy zkopírovány</item>
+        <item quantity="many">Zpráv zkopírováno</item>
+    </plurals>
 </resources>

+ 9 - 2
app/src/main/res/values-de/strings.xml

@@ -122,6 +122,7 @@
 	<string name="copy_message_action">Kopieren</string>
 	<string name="delete_contact_action">Kontakt löschen</string>
 	<string name="scan_id">ID scannen</string>
+	<string name="id_scanned">ID gescannt</string>
 	<string name="id_mismatch">Der öffentliche Schlüssel, den Sie eingescannt haben, stimmt nicht mit dem Schlüssel
 		überein, den der Server für diesen Kontakt verzeichnet hat. Dies deutet auf Manipulationen hin, welche die
 		Sicherheit der Kommunikation gefährden. Bitte melden Sie dieses Vorkommnis an security@threema.ch, wenn möglich
@@ -591,7 +592,6 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
 	<string name="file_placeholder">Datei</string>
 	<string name="internal_storage">Int. Speicher</string>
 	<string name="no_activity_for_mime_type">Keine passende App für diese Datei gefunden.</string>
-	<string name="message_copied">Nachricht kopiert</string>
 	<string name="open_from">Öffnen von</string>
 	<string name="file_one_contact_not_supported">%1$s kann noch keine Dateien erhalten.</string>
 	<string name="file_x_contact_not_supported">Warnung: %1$d Kontakte können keine Dateien erhalten.</string>
@@ -1391,7 +1391,7 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
 	<string name="forward_captions">Beschriftungen mitsenden</string>
 	<string name="importing_files_failed">Importieren der Backup-Datei fehlgeschlagen. Stellen Sie sicher, dass genügend freier Platz im internen Speicher vorhanden ist.</string>
 	<string name="label_continue">Weiter</string>
-	<string name="select_date">Datum auswälen</string>
+	<string name="select_date">Datum auswählen</string>
 	<string name="select_time">Zeit auswählen</string>
 	<string name="send_to">Senden an %s</string>
 	<string name="receipts_override_choice_send">Senden</string>
@@ -1494,6 +1494,9 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
 	<string name="last_added_contact">Zuletzt hinzugefügt</string>
 	<string name="directory_explain_text">Suchen Sie im Firmenverzeichnis nach beliebigen Mitarbeitern, die sich noch nicht in Ihrer Kontaktliste befinden.</string>
 	<string name="cannot_display_location">Dieser Ort kann nicht angezeigt werden.</string>
+    <string name="unable_to_restore_identity_because">Die ID konnte nicht wiederhergestellt werden. Grund: %s</string>
+	<string name="share_with_app">Mit Threema teilen</string>
+	<string name="new_wizard_info_sync_contacts_dialog">Die Kontakt-Synchronisation hilft Ihnen, Ihre Freunde automatisch zu finden. Wenn Sie zustimmen, werden Handynummern und E-Mail-Adressen aus Ihrem Telefonbuch verschlüsselt an unseren Server gesendet und dort verglichen, um passende Kontakte zu finden. Die Daten werden weder gespeichert noch weitergegeben.\n\nMöchten Sie die Kontakt-Synchronisation aktivieren?</string>
 	<plurals name="contacts_counter_label">
 		<item quantity="one">%d Kontakt</item>
 		<item quantity="other">%d Kontakte</item>
@@ -1510,4 +1513,8 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
 		<item quantity="one">%d Bild ausgewählt</item>
 		<item quantity="other">%d Bilder ausgewählt</item>
 	</plurals>
+	<plurals name="message_copied">
+		<item quantity="one">Nachricht kopiert</item>
+		<item quantity="other">Nachrichten kopiert</item>
+	</plurals>
 </resources>

+ 8 - 1
app/src/main/res/values-es/strings.xml

@@ -112,6 +112,7 @@
     <string name="copy_message_action">Copiar</string>
     <string name="delete_contact_action">Eliminar contacto</string>
     <string name="scan_id">Escanear ID</string>
+    <string name="id_scanned">ID escaneado</string>
     <string name="id_mismatch">«La clave pública que ha escaneado no coincide con la que tiene registrada el servidor para este ID». Eso significa que alguien ha modificado el código escaneado de forma malintencionada y que la clave no es segura.</string>
     <string name="scan_successful">El ID se ha escaneado correctamente. Ahora el contacto está verificado.</string>
     <string name="scan_duplicate">Este ID ya se ha escaneado y verificado.</string>
@@ -511,7 +512,6 @@ Introduzca una pregunta para su sondeo.</string>
     <string name="file_placeholder">Archivo</string>
     <string name="internal_storage">Almacenamiento interno</string>
     <string name="no_activity_for_mime_type">No hay aplicaciones que puedan abrir este archivo.</string>
-    <string name="message_copied">Mensaje copiado</string>
     <string name="open_from">Abrir desde</string>
     <string name="file_one_contact_not_supported">%1$s no puede recibir archivos.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Aviso: %1$d contactos no pueden recibir el archivo.</string>
@@ -637,6 +637,7 @@ almacenado.</string>
     <string name="new_wizard_info_fingerprint">Al mover los dedos, usted crea datos aleatorios (llamados entropía) que se utilizan para generar el par de claves asociado a su ID único de Threema.</string>
     <string name="new_wizard_info_id">También ha creado un par de claves. La clave pública se ha transmitido de forma segura a nuestros servidores. La clave privada nunca sale de su dispositivo, lo que garantiza que nadie más puede leer sus mensajes.</string>
     <string name="new_wizard_info_sync_contacts">Si activa esta opción, Threema aplica un cifrado unidireccional (hash) a las direcciones de correo electrónico y números de teléfono antes de enviarlos al servidor para buscar coincidencias de contactos. No almacenamos ningún dato de libretas de direcciones.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">La sincronización de contactos puede ayudarle a encontrar a sus amigos automáticamente. Si acepta, los números de teléfono y las direcciones de correo electrónico de la agenda de su teléfono se cifrarán antes de enviarse a nuestro servidor para buscar contactos coincidentes. No se almacenará ni compartirá absolutamente ningún dato.\n\n¿Quiere activar la sincronización de contactos?</string>
     <string name="new_wizard_info_link">Al facilitarnos su número de teléfono y dirección de correo electrónico, ayudamos a sus amigos a encontrarlo automáticamente en Threema. Esta información se almacenará de forma segura. Si se salta este paso, utilizará Threema de forma completamente anónima.</string>
     <string name="new_wizard_info_link_phone_only">Al proporcionar su número de teléfono, Threema podrá ayudar a sus amigos
 		a encontrarle automáticamente si lo tienen en los contactos de su teléfono. El número se guardará en un
@@ -1397,6 +1398,8 @@ almacenado.</string>
     <string name="last_added_contact">Último añadido</string>
     <string name="directory_explain_text">Buscar en el directorio de la compañía empleados que todavía no estén en su lista de contactos.</string>
     <string name="cannot_display_location">No se puede mostrar la ubicación.</string>
+    <string name="unable_to_restore_identity_because">No se puede restaurar el ID. Motivo: %s</string>
+    <string name="share_with_app">Compartir con Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contacto</item>
         <item quantity="other">%d contactos</item>
@@ -1413,4 +1416,8 @@ almacenado.</string>
         <item quantity="one">%d imagen seleccionada</item>
         <item quantity="other">%d imágenes seleccionadas</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one">Mensaje copiado</item>
+        <item quantity="other">Mensajes copiados</item>
+    </plurals>
 </resources>

+ 11 - 3
app/src/main/res/values-fr/strings.xml

@@ -112,6 +112,7 @@
     <string name="copy_message_action">Copier</string>
     <string name="delete_contact_action">Supprimer le contact</string>
     <string name="scan_id">Scanner un ID</string>
+    <string name="id_scanned">ID scanné</string>
     <string name="id_mismatch">La clé publique que vous avez scannée ne correspond pas à celle stockée par le serveur pour cet ID. Cela signifie que quelqu\'un a manipulé le code scanné, et que la clé n\'est pas fiable.</string>
     <string name="scan_successful">L\'ID a bien été scanné et le contact est vérifié.</string>
     <string name="scan_duplicate">L\'ID a déjà été scanné et vérifié.</string>
@@ -509,7 +510,6 @@ Veuillez saisir une question pour votre enquête.</string>
     <string name="file_placeholder">Fichier</string>
     <string name="internal_storage">Stockage interne</string>
     <string name="no_activity_for_mime_type">Aucune application trouvée pour ouvrir ce fichier.</string>
-    <string name="message_copied">Message copié</string>
     <string name="open_from">Ouvrir depuis</string>
     <string name="file_one_contact_not_supported">%1$s ne peut pas recevoir de fichiers.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Attention : %1$d contacts ne peuvent pas recevoir votre fichier.</string>
@@ -634,6 +634,7 @@ Veuillez saisir une question pour votre enquête.</string>
     <string name="new_wizard_info_fingerprint">En déplaçant vos doigt, vous créez des données aléatoires (appelées entropie), qui sont utilisées pour générer une paire de clés associées à votre ID Threema unique.</string>
     <string name="new_wizard_info_id">Vous avez également créé une paire de clés. La clé publique a été transmise de façon sécurisée à nos serveurs. La clé privée ne quitte jamais votre appareil. Ceci assure que personne d\'autre ne peut lire vos messages.</string>
     <string name="new_wizard_info_sync_contacts">Si vous activez cette option, Threema chiffrera de façon unidirectionnelle (hachage) les adresses e-mail et les numéros de téléphone avant de les envoyer au serveur pour chercher des contacts correspondants. Nous ne stockons pas les données du carnet d\'adresses.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">La synchronisation des contacts peut vous aider à retrouver automatiquement vos amis. Si vous acceptez, les numéros de téléphone et les adresses e-mail de votre carnet d\'adresses seront chiffrés avant d\'être envoyés à notre serveur pour rechercher des contacts correspondants. Absolument aucune donnée ne sera stockée ou partagée.\n\nVoulez-vous activer la synchronisation des contacts ?</string>
     <string name="new_wizard_info_link">En nous donnant votre numéro de téléphone et votre adresse e-mail, nous pouvons aider vos amis à vous trouver automatiquement sur Threema. Ces informations seront stockées de façon sécurisée et anonyme. Si vous ignorez cette étape, vous utiliserez Threema de façon complètement anonyme.</string>
     <string name="new_wizard_info_link_phone_only">En donnant votre numéro de téléphone, Theema peut aider vos amis à vous trouver automatiquement si vous vous trouvez dans leur carnet d’adresses. Le numéro sera stocké de manière chiffrée (hashée) sur notre serveur. Vous pouvez simplement passer cette étape si vous souhaitez utiliser Threema de manière complètement anonyme.</string>
     <string name="new_wizard_info_nickname">Le surnom est utilisé dans les notifications push sur certains appareils, ou comme moyen supplémentaire de vous identifier auprès des utilisateurs dont vous n\'êtes pas encore dans le carnet d\'adresse. Nous vous recommandons de ne donner que votre prénom ou un pseudo. Si vous ne définissez pas de surnom, nous utiliserons par défaut votre ID Threema.</string>
@@ -1387,14 +1388,16 @@ Veuillez saisir une question pour votre enquête.</string>
     <string name="last_added_contact">Dernier ajout</string>
     <string name="directory_explain_text">Recherchez dans le répertoire de l\'entreprise tout employé ne faisant pas encore partie de votre liste de contacts.</string>
     <string name="cannot_display_location">Impossible d\'afficher cet emplacement.</string>
+    <string name="unable_to_restore_identity_because">Impossible de restaurer l\'ID. Raison : %s</string>
+    <string name="share_with_app">Partager avec Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contact</item>
         <item quantity="many">%d contacts</item>
         <item quantity="other">%d contacts</item>
     </plurals>
     <plurals name="really_delete_thread_message">
-        <item quantity="one" tools:ignore="ImpliedQuantity">Souhaitez-vous vraiment supprimer ce fil ?</item>
-        <item quantity="many">Souhaitez-vous vraiment supprimer %d fils ?</item>
+        <item quantity="one" tools:ignore="ImpliedQuantity">Souhaitez-vous vraiment supprimer ce fil?</item>
+        <item quantity="many">Souhaitez-vous vraiment supprimer %d fils?</item>
         <item quantity="other">Souhaitez-vous vraiment supprimer %d fils ?</item>
     </plurals>
     <plurals name="sending_message_failed">
@@ -1407,4 +1410,9 @@ Veuillez saisir une question pour votre enquête.</string>
         <item quantity="many">%d images sélectionnées</item>
         <item quantity="other">%d images sélectionnées</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one" tools:ignore="ImpliedQuantity">Message copié</item>
+        <item quantity="many">Messages copiés</item>
+        <item quantity="other">Messages copiés</item>
+    </plurals>
 </resources>

+ 1355 - 1390
app/src/main/res/values-hu/strings.xml

@@ -1,1408 +1,1373 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<resources>
-	<string name="title_section2">Névjegyek</string>
-	<string name="title_section1">Csevegések</string>
-	<string name="title_compose_message">Csevegés indítása</string>
-	<string name="title_choose_recipient">Címzett kiválasztása</string>
-	<string name="title_keyfingerprint">Kulcs ujjlenyomat</string>
-	<string name="title_mythreemaid">Az én Threema ID-m</string>
-	<string name="title_threemaid">Threema-ID</string>
-	<string name="title_adduser">Névjegy hozzáadása</string>
-	<string name="title_enter_id">Adja meg az ID-d</string>
-	<string name="title_invite_friend">Barátok meghívása</string>
-	<string name="invite_via">Meghívás…</string>
-	<string name="invite_email_body">Szia!\n\nA %1$s-t használom, a biztonságos messengert, amely védi a privátszférát.\n\nA Threema azonosítóm: https://threema.id/%2$s\n\nBeszélgessünk a %1$s-n keresztül!\n\nÜdv!\n</string>
-	<string name="invite_sms_body">Szia! Beszéljünk biztonságosan és az adatvédelemnek megfelelően a %1$s-n keresztül! A Threema ID-m: https://threema.id/%2$s</string>
-	<string name="invite_email_subject">Threema. A biztonságos messenger, amely védi az én és a te privátszférádat.</string>
-	<string name="enter_id_hint">Threema-ID megadása</string>
-	<string name="account_links">Csatlakozások</string>
-	<string name="menu_settings">Beállítások</string>
-	<string name="menu_about">A Threema-ról</string>
-	<string name="menu_add_contact">Új névjegy</string>
-	<string name="menu_done">Kész</string>
-	<string name="compose_message_and_enter">Üzenet beírása</string>
-	<string name="send">Küldés</string>
-	<string name="prefs_privacy">Adatvédelem</string>
-	<string name="prefs_notifications">Hangok  &amp; értesítések</string>
-	<string name="prefs_chatdisplay">Csevegőablak</string>
-	<string name="prefs_security">Biztonság</string>
-	<string name="prefs_sum_privacy">Adatvédelemmel kapcsolatos beállítások</string>
-	<string name="prefs_sum_notifications">Hangok és rezgés</string>
-	<string name="prefs_sum_chatdisplay">Csevegőablak beállításai</string>
-	<string name="prefs_masterkey">A helyben tárolt adatok titkosítása</string>
-	<string name="prefs_header_contacts">Névjegyek</string>
-	<string name="prefs_header_chat">Csevegés</string>
-	<string name="prefs_header_reset">Visszaállítás</string>
-	<string name="prefs_header_keyboard">Billentyűzet</string>
-	<string name="prefs_sum_sync_contacts_on">%s-névjegyek csatlakoztatása a gép címjegyzékéhez</string>
-	<string name="prefs_sum_sync_contacts_off">Kapcsolat megszüntetve %s és a címjegyzék között</string>
-	<string name="prefs_title_sync_contacts">Névjegyek szinkronizálása</string>
-	<string name="prefs_sum_block_unknown_off">Bárki küldhet neked üzeneteket. Az új névjegyek automatikusan hozzáadódnak az első üzenetküldéskor.</string>
-	<string name="prefs_sum_block_unknown_on">Csak a névjegyzékben szereplő személyek küldhetnek üzeneteket.</string>
-	<string name="prefs_title_block_unknown">Az ismeretlenek blokkolása</string>
-	<string name="prefs_title_read_receipts">Olvasási visszaigazolások küldése</string>
-	<string name="prefs_title_typing_indicator">Jelezd, ha írok</string>
-	<string name="prefs_media_title">Média &amp; Tárolóhely</string>
-	<string name="prefs_sum_media_title">Média-, fájl- és tárolási beállítások</string>
-	<string name="prefs_image_size">Képméretek</string>
-	<string name="prefs_notification_sound">Értesítési hang</string>
-	<string name="prefs_sum_notification_sound">Rendszer alapértelmezett</string>
-	<string name="prefs_vibrate">Rezgés</string>
-	<string name="prefs_sum_vibrate">Rezgés bejövő üzenetre</string>
-	<string name="prefs_light">Értesítési lámpa</string>
-	<string name="prefs_sum_light">Fehér</string>
-	<string name="prefs_title_wallpaper">Háttérkép kiválasztása</string>
-	<string name="prefs_sum_wallpaper">Kép kiválasztása a háttérhez</string>
-	<string name="prefs_title_wallpaper_switch">Háttérkép</string>
-	<string name="prefs_title_enter">Közvetlen elküldés</string>
-	<string name="prefs_sum_enter_on">Az Enter billentyű azonnal elküldi az üzenetet</string>
-	<string name="prefs_sum_enter_off">Az Enter billentyű új sort ad hozzá</string>
-	<string name="prefs_system_notifications">Csevegés</string>
-	<string name="prefs_inapp">Az alkalmazásban</string>
-	<string name="prefs_inapp_sounds">Alkalmazáson belüli hangok</string>
-	<string name="prefs_inapp_sounds_on">Hang lejátszása üzenetek küldésekor/fogadásakor</string>
-	<string name="prefs_inapp_sounds_off">Üzenetek küldésekor/fogadásakor ne szólaljon meg hang</string>
-	<string name="prefs_inapp_vibrate">Alkalmazáson belüli rezgés</string>
-	<string name="prefs_inapp_vibrate_on">Rezgés üzenetek fogadásakor</string>
-	<string name="prefs_inapp_vibrate_off">Nincs rezgés az üzenetek fogadásakor</string>
-	<string name="prefs_troubleshooting">Hibaelhárítás</string>
-	<string name="prefs_sum_troubleshooting">Problémák elemzése és megoldása</string>
-	<string name="prefs_workarounds">Megoldások</string>
-	<string name="prefs_logging">Naplózás</string>
-	<string name="prefs_title_message_log_switch">Fájlba naplózás</string>
-	<string name="prefs_title_sum_message_log_on">Az események és a hálózati információk a debug_log.txt fájlba lesznek naplózva</string>
-	<string name="prefs_title_sum_message_log_off">Az események nem lesznek naplózva</string>
-	<string name="prefs_reset_push">Push-token visszaállítása</string>
-	<string name="prefs_sum_reset_push">Az egység újbóli regisztrálása az FCM//HMS-ben</string>
-	<string name="prefs_notification_preview">Előnézet</string>
-	<string name="image_size_small">Kicsi (640x640)</string>
-	<string name="image_size_medium">Közepes  (1024x1024)</string>
-	<string name="image_size_large">Nagy (1600x1600)</string>
-	<string name="image_size_xlarge">Óriási (2592x2592)</string>
-	<string name="image_size_original">Eredeti méret</string>
-	<string name="color_none">Nincs</string>
-	<string name="color_orange">Narancssárga</string>
-	<string name="color_red">Piros</string>
-	<string name="color_green">Zöld</string>
-	<string name="color_blue">Kék</string>
-	<string name="color_cyan">Cián</string>
-	<string name="color_magenta">Magenta</string>
-	<string name="color_yellow">Sárga</string>
-	<string name="color_white">Fehér</string>
-	<string name="next">Tovább</string>
-	<string name="finish">Befejezés</string>
-	<string name="please_wait">Kérjük, várjon…</string>
-	<string name="wizard_first_create_id">A kulcspár generálása…</string>
-	<string name="wizard1_sync_contacts">A névjegyek szinkronizálása…</string>
-	<string name="wizard2_email_hint">Az Ön e-mail címe</string>
-	<string name="wizard2_email_linking">Összekapcsolás e-mail címmel</string>
-	<string name="wizard2_phone_hint">Az Ön mobiltelefonszáma</string>
-	<string name="wizard2_phone_number_confirm_title">Mobiltelefonszám megerősítése</string>
-	<string name="wizard2_phone_number_confirm">SMS-t küldünk a következő számra:\n\n%1$s\n\nHelyes a szám?</string>
-	<string name="wizard2_phone_linking">Mobilszám összekapcsolása az azonosítóval</string>
-	<string name="wizard3_nickname_hint">Becenév megadása</string>
-	<string name="set_nickname_title">Becenév beállítása</string>
-	<string name="ok">OK</string>
-	<string name="cancel">Mégsem</string>
-	<string name="copy_message_action">Másolás</string>
-	<string name="delete_contact_action">Névjegy törlése</string>
-	<string name="scan_id">ID (azonosító) beolvasása</string>
-	<string name="id_mismatch">A beolvasott nyilvános kulcs nem egyezik a kiszolgáló által használt kulccsal, amelyet
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <string name="title_section2">Névjegyek</string>
+    <string name="title_section1">Csevegések</string>
+    <string name="title_compose_message">Csevegés indítása</string>
+    <string name="title_choose_recipient">Címzett kiválasztása</string>
+    <string name="title_keyfingerprint">Kulcs ujjlenyomat</string>
+    <string name="title_mythreemaid">Az én Threema ID-m</string>
+    <string name="title_threemaid">Threema-ID</string>
+    <string name="title_adduser">Névjegy hozzáadása</string>
+    <string name="title_enter_id">Adja meg az ID-d</string>
+    <string name="title_invite_friend">Barátok meghívása</string>
+    <string name="invite_via">Meghívás…</string>
+    <string name="invite_email_body">Szia!\n\nA %1$s-t használom, a biztonságos messengert, amely védi a privátszférát.\n\nA Threema azonosítóm: https://threema.id/%2$s\n\nBeszélgessünk a %1$s-n keresztül!\n\nÜdv!\n</string>
+    <string name="invite_sms_body">Szia! Beszéljünk biztonságosan és az adatvédelemnek megfelelően a %1$s-n keresztül! A Threema ID-m: https://threema.id/%2$s</string>
+    <string name="invite_email_subject">Threema. A biztonságos messenger, amely védi az én és a te privátszférádat.</string>
+    <string name="enter_id_hint">Threema-ID megadása</string>
+    <string name="account_links">Csatlakozások</string>
+    <string name="menu_settings">Beállítások</string>
+    <string name="menu_about">A Threema-ról</string>
+    <string name="menu_add_contact">Új névjegy</string>
+    <string name="menu_done">Kész</string>
+    <string name="compose_message_and_enter">Üzenet beírása</string>
+    <string name="send">Küldés</string>
+    <string name="prefs_privacy">Adatvédelem</string>
+    <string name="prefs_notifications">Hangok  &amp; értesítések</string>
+    <string name="prefs_chatdisplay">Csevegőablak</string>
+    <string name="prefs_security">Biztonság</string>
+    <string name="prefs_sum_privacy">Adatvédelemmel kapcsolatos beállítások</string>
+    <string name="prefs_sum_notifications">Hangok és rezgés</string>
+    <string name="prefs_sum_chatdisplay">Csevegőablak beállításai</string>
+    <string name="prefs_masterkey">A helyben tárolt adatok titkosítása</string>
+    <string name="prefs_header_contacts">Névjegyek</string>
+    <string name="prefs_header_chat">Csevegés</string>
+    <string name="prefs_header_reset">Visszaállítás</string>
+    <string name="prefs_header_keyboard">Billentyűzet</string>
+    <string name="prefs_sum_sync_contacts_on">%s-névjegyek csatlakoztatása a gép címjegyzékéhez</string>
+    <string name="prefs_sum_sync_contacts_off">Kapcsolat megszüntetve %s és a címjegyzék között</string>
+    <string name="prefs_title_sync_contacts">Névjegyek szinkronizálása</string>
+    <string name="prefs_sum_block_unknown_off">Bárki küldhet neked üzeneteket. Az új névjegyek automatikusan hozzáadódnak az első üzenetküldéskor.</string>
+    <string name="prefs_sum_block_unknown_on">Csak a névjegyzékben szereplő személyek küldhetnek üzeneteket.</string>
+    <string name="prefs_title_block_unknown">Az ismeretlenek blokkolása</string>
+    <string name="prefs_title_read_receipts">Olvasási visszaigazolások küldése</string>
+    <string name="prefs_title_typing_indicator">Jelezd, ha írok</string>
+    <string name="prefs_media_title">Média &amp; Tárolóhely</string>
+    <string name="prefs_sum_media_title">Média-, fájl- és tárolási beállítások</string>
+    <string name="prefs_image_size">Képméretek</string>
+    <string name="prefs_notification_sound">Értesítési hang</string>
+    <string name="prefs_sum_notification_sound">Rendszer alapértelmezett</string>
+    <string name="prefs_vibrate">Rezgés</string>
+    <string name="prefs_sum_vibrate">Rezgés bejövő üzenetre</string>
+    <string name="prefs_light">Értesítési lámpa</string>
+    <string name="prefs_sum_light">Fehér</string>
+    <string name="prefs_title_wallpaper">Háttérkép kiválasztása</string>
+    <string name="prefs_sum_wallpaper">Kép kiválasztása a háttérhez</string>
+    <string name="prefs_title_wallpaper_switch">Háttérkép</string>
+    <string name="prefs_title_enter">Közvetlen elküldés</string>
+    <string name="prefs_sum_enter_on">Az Enter billentyű azonnal elküldi az üzenetet</string>
+    <string name="prefs_sum_enter_off">Az Enter billentyű új sort ad hozzá</string>
+    <string name="prefs_system_notifications">Csevegés</string>
+    <string name="prefs_inapp">Az alkalmazásban</string>
+    <string name="prefs_inapp_sounds">Alkalmazáson belüli hangok</string>
+    <string name="prefs_inapp_sounds_on">Hang lejátszása üzenetek küldésekor/fogadásakor</string>
+    <string name="prefs_inapp_sounds_off">Üzenetek küldésekor/fogadásakor ne szólaljon meg hang</string>
+    <string name="prefs_inapp_vibrate">Alkalmazáson belüli rezgés</string>
+    <string name="prefs_inapp_vibrate_on">Rezgés üzenetek fogadásakor</string>
+    <string name="prefs_inapp_vibrate_off">Nincs rezgés az üzenetek fogadásakor</string>
+    <string name="prefs_troubleshooting">Hibaelhárítás</string>
+    <string name="prefs_sum_troubleshooting">Problémák elemzése és megoldása</string>
+    <string name="prefs_workarounds">Megoldások</string>
+    <string name="prefs_logging">Naplózás</string>
+    <string name="prefs_title_message_log_switch">Fájlba naplózás</string>
+    <string name="prefs_title_sum_message_log_on">Az események és a hálózati információk a debug_log.txt fájlba lesznek naplózva</string>
+    <string name="prefs_title_sum_message_log_off">Az események nem lesznek naplózva</string>
+    <string name="prefs_reset_push">Push-token visszaállítása</string>
+    <string name="prefs_sum_reset_push">Az egység újbóli regisztrálása az FCM//HMS-ben</string>
+    <string name="prefs_notification_preview">Előnézet</string>
+    <string name="prefs_sum_reset_ringtones">Gyári beállítások visszaállítása</string>
+    <string name="prefs_title_reset_ringtones">Értesítési hangok visszaállítása</string>
+    <string name="image_size_small">Kicsi (640x640)</string>
+    <string name="image_size_medium">Közepes  (1024x1024)</string>
+    <string name="image_size_large">Nagy (1600x1600)</string>
+    <string name="image_size_xlarge">Óriási (2592x2592)</string>
+    <string name="image_size_original">Eredeti méret</string>
+    <string name="color_none">Nincs</string>
+    <string name="color_orange">Narancssárga</string>
+    <string name="color_red">Piros</string>
+    <string name="color_green">Zöld</string>
+    <string name="color_blue">Kék</string>
+    <string name="color_cyan">Cián</string>
+    <string name="color_magenta">Magenta</string>
+    <string name="color_yellow">Sárga</string>
+    <string name="color_white">Fehér</string>
+    <string name="next">Tovább</string>
+    <string name="finish">Befejezés</string>
+    <string name="please_wait">Kérjük, várjon…</string>
+    <string name="wizard_first_create_id">A kulcspár generálása…</string>
+    <string name="wizard1_sync_contacts">A névjegyek szinkronizálása…</string>
+    <string name="wizard2_email_hint">Az Ön e-mail címe</string>
+    <string name="wizard2_email_linking">Összekapcsolás e-mail címmel</string>
+    <string name="wizard2_phone_hint">Az Ön mobiltelefonszáma</string>
+    <string name="wizard2_phone_number_confirm_title">Mobiltelefonszám megerősítése</string>
+    <string name="wizard2_phone_number_confirm">SMS-t küldünk a következő számra:\n\n%1$s\n\nHelyes a szám?</string>
+    <string name="wizard2_phone_linking">Mobilszám összekapcsolása az azonosítóval</string>
+    <string name="wizard3_nickname_hint">Becenév megadása</string>
+    <string name="set_nickname_title">Becenév beállítása</string>
+    <string name="ok">OK</string>
+    <string name="cancel">Mégsem</string>
+    <string name="copy_message_action">Másolás</string>
+    <string name="delete_contact_action">Névjegy törlése</string>
+    <string name="scan_id">ID (azonosító) beolvasása</string>
+    <string name="id_mismatch">A beolvasott nyilvános kulcs nem egyezik a kiszolgáló által használt kulccsal, amelyet
 		a kiszolgáló a névjegyhez rögzített. Ez olyan manipulációra utal, amely veszélyeztetheti a kommunikáció biztonságát.
-		Kérjük, ha lehetséges, jelezze ezt az esetet a security@threema.ch címen az ID és a körülmények feltüntetésével.
-	</string>
-	<string name="scan_successful">Az ID sikeresen beolvasva. A kapcsolat ellenőrzött.</string>
-	<string name="scan_duplicate">Ez az ID már be lett olvasva és ellenőrizve.</string>
-	<string name="linked_email">E-mail</string>
-	<string name="linked_mobile">Mobiltelefonszám</string>
-	<string name="public_nickname">Becenév</string>
-	<string name="share_via">Megosztás…</string>
-	<string name="share_subject">%s-csevegés</string>
-	<string name="message_delete_undo">Visszavonás</string>
-	<string name="message_deleted">Üzenet törölve</string>
-	<string name="mobile_already_linked">Az Ön Threema ID-je már társítva van ehhez a mobilszámhoz.</string>
-	<string name="email_already_linked">Az Ön Threema ID-je már társítva van ehhez az e-mail címhez.</string>
-	<string name="whoaaa">Megjegyzés</string>
-	<string name="really_delete_message_title">Üzenet(ek) törlése</string>
-	<string name="really_delete_thread">Csevegés törlése</string>
-	<string name="really_delete_contact">Tényleg törölni szeretné ezt a névjegyet és az összes kapcsolódó csevegést?</string>
-	<string name="image_placeholder">Kép</string>
-	<string name="invalid_threema_id">Érvénytelen Threema-ID</string>
-	<string name="contact_already_exists">A névjegy már létezik</string>
-	<string name="close">Bezárás</string>
-	<string name="creating_contact">Új névjegy hozzáadása</string>
-	<string name="creating_contact_successful">Névjegy sikeresen hozzáadva</string>
-	<string name="invalid_threema_qr_code">Érvénytelen QR-kód</string>
-	<string name="threema_contact">Threema-Névjegy</string>
-	<string name="first_name">Keresztnév</string>
-	<string name="last_name">Vezetéknév</string>
-	<string name="os_licenses">Szoftverlicencek</string>
-	<string name="verify_title">Mobilszám ellenőrzése</string>
-	<string name="verify_success_text">A mobiltelefonszámát sikeresen ellenőriztük.</string>
-	<string name="verify_failed">Sikertelen</string>
-	<string name="verify_failed_summary">A mobilszám ellenőrzése sikertelen volt. Kérjük, ellenőrizze a szám
-		helyességét és a mobilhálózat kapcsolatot, mielőtt újra megpróbálná.
-	</string>
-	<string name="verify_failed_not_linked">A mobilszám ellenőrzése nem lehetséges, mert a folyamatot megszakította.</string>
-	<string name="check_incoming_sms">Bejövő SMS-re várás</string>
-	<string name="backup_title">ID exportálása</string>
-	<string name="backup_sum">Exportálja a Threema ID-t</string>
-	<string name="backup_and_delete">Mentés és törlés</string>
-	<string name="delete_id_title">ID törlése</string>
-	<string name="delete_id_message">Hacsak nem készített biztonsági másolatot az azonosítóról, akkor soha többé nem lesz
+		Kérjük, ha lehetséges, jelezze ezt az esetet a security@threema.ch címen az ID és a körülmények feltüntetésével.</string>
+    <string name="scan_successful">Az ID sikeresen beolvasva. A kapcsolat ellenőrzött.</string>
+    <string name="scan_duplicate">Ez az ID már be lett olvasva és ellenőrizve.</string>
+    <string name="linked_email">E-mail</string>
+    <string name="linked_mobile">Mobiltelefonszám</string>
+    <string name="public_nickname">Becenév</string>
+    <string name="share_via">Megosztás…</string>
+    <string name="share_subject">%s-csevegés</string>
+    <string name="message_delete_undo">Visszavonás</string>
+    <string name="message_deleted">Üzenet törölve</string>
+    <string name="mobile_already_linked">Az Ön Threema ID-je már társítva van ehhez a mobilszámhoz.</string>
+    <string name="email_already_linked">Az Ön Threema ID-je már társítva van ehhez az e-mail címhez.</string>
+    <string name="whoaaa">Megjegyzés</string>
+    <string name="really_delete_message_title">Üzenet(ek) törlése</string>
+    <string name="really_delete_thread">Csevegés törlése</string>
+    <string name="really_delete_contact">Tényleg törölni szeretné ezt a névjegyet és az összes kapcsolódó csevegést?</string>
+    <string name="image_placeholder">Kép</string>
+    <string name="invalid_threema_id">Érvénytelen Threema-ID</string>
+    <string name="contact_already_exists">A névjegy már létezik</string>
+    <string name="close">Bezárás</string>
+    <string name="creating_contact">Új névjegy hozzáadása</string>
+    <string name="creating_contact_successful">Névjegy sikeresen hozzáadva</string>
+    <string name="invalid_threema_qr_code">Érvénytelen QR-kód</string>
+    <string name="threema_contact">Threema-Névjegy</string>
+    <string name="first_name">Keresztnév</string>
+    <string name="last_name">Vezetéknév</string>
+    <string name="os_licenses">Szoftverlicencek</string>
+    <string name="verify_title">Mobilszám ellenőrzése</string>
+    <string name="verify_success_text">A mobiltelefonszámát sikeresen ellenőriztük.</string>
+    <string name="verify_failed">Sikertelen</string>
+    <string name="verify_failed_summary">A mobilszám ellenőrzése sikertelen volt. Kérjük, ellenőrizze a szám
+		helyességét és a mobilhálózat kapcsolatot, mielőtt újra megpróbálná.</string>
+    <string name="verify_failed_not_linked">A mobilszám ellenőrzése nem lehetséges, mert a folyamatot megszakította.</string>
+    <string name="check_incoming_sms">Bejövő SMS-re várás</string>
+    <string name="backup_title">ID exportálása</string>
+    <string name="backup_sum">Exportálja a Threema ID-t</string>
+    <string name="backup_and_delete">Mentés és törlés</string>
+    <string name="delete_id_title">ID törlése</string>
+    <string name="delete_id_message">Hacsak nem készített biztonsági másolatot az azonosítóról, akkor soha többé nem lesz
 		képes üzenetek küldése vagy fogadása ezzel az azonosítóval.\n\nHa nem kívánja tovább használni ezt az azonosítót,
-		törlés előtt távolítsa el a hivatkozásokat (e-mail/telefonszám).
-	</string>
-	<string name="delete_id_message2">Utolsó figyelmeztetés: valóban törölni szeretné az azonosítóját erről az eszközről?</string>
-	<string name="delete_id_sum">A Threema ID és a csevegések törlése ezen az eszközön.</string>
-	<string name="backup_password_summary">Az Ön azonosítója jelszóval lesz titkosítva. Használjon betűk, számok és szimbólumok kombinációját. Ne feledje el mit írt be ide!</string>
-	<string name="backup_password_again_summary">Jelszó megismétlése</string>
-	<string name="password_hint">Jelszó</string>
-	<string name="generating_backup_data">Az ID titkosítása</string>
-	<string name="backup_id_title">Az Ön ID exportja</string>
-	<string name="backup_id_summary">A karakterlánc vagy a QR-kód a választott jelszóval együtt használható az ID
+		törlés előtt távolítsa el a hivatkozásokat (e-mail/telefonszám).</string>
+    <string name="delete_id_message2">Utolsó figyelmeztetés: valóban törölni szeretné az azonosítóját erről az eszközről?</string>
+    <string name="delete_id_sum">A Threema ID és a csevegések törlése ezen az eszközön.</string>
+    <string name="backup_password_summary">Az Ön azonosítója jelszóval lesz titkosítva. Használjon betűk, számok és szimbólumok kombinációját. Ne feledje el mit írt be ide!</string>
+    <string name="backup_password_again_summary">Jelszó megismétlése</string>
+    <string name="password_hint">Jelszó</string>
+    <string name="generating_backup_data">Az ID titkosítása</string>
+    <string name="backup_id_title">Az Ön ID exportja</string>
+    <string name="backup_id_summary">A karakterlánc vagy a QR-kód a választott jelszóval együtt használható az ID
 		helyreállítására egy másik eszközön. Másolja &amp; és illessze be az adatokat egy megfelelő helyre, nyomtassa
-		ki, küldje el magának e-mailben a Megosztás funkció segítségével, vagy olvassa be a QR-kódot egy másik eszközzel.
-	</string>
-	<string name="support">Súgó</string>
-	<string name="support_url">https://threema.ch/android/support/</string>
-	<string name="backup_share_content">A következő karakterláncot a kiválasztott jelszóval együtt használja a
-		Threema azonosító visszaszerzéséhez.
-	</string>
-	<string name="backup_share_subject">Threema ID export a következőkhöz</string>
-	<string name="add_attachment">Beillesztés</string>
-	<string name="attach_picture">Kép</string>
-	<string name="attach_video">Videó</string>
-	<string name="attach_location">Helyszín</string>
-	<string name="invalid_passphrase">Érvénytelen jelszó</string>
-	<string name="master_key_locked">A főkulcs zárolva van</string>
-	<string name="master_key_locked_notify_description">Jelszó megadása</string>
-	<string name="prefs_masterkey_passphrase">Nincs megadva jelszó</string>
-	<string name="prefs_title_masterkey_passphrase">Jelszó</string>
-	<string name="setting_masterkey_passphrase">Jelszó megadása a főkulcshoz</string>
-	<string name="masterkey_passphrase_title">Jelszó a főkulcshoz</string>
-	<string name="masterkey_passphrase_summary">A főkulcsot egy Ön által választott jelszóval tudja védeni.
-		Ha az alkalmazás be lett zárva, újra meg kell adnia a jelszót.
-	</string>
-	<string name="masterkey_passphrase_again_summary">Jelszó ismétlése</string>
-	<string name="masterkey_passphrase_hint">Jelszó</string>
-	<string name="master_key_locked_want_exit">A főkulcs még mindig zárva van. Szeretné újra megpróbálni?</string>
-	<string name="click_here_to_change_passphrase">Kattintson ide a jelszó módosításához</string>
-	<string name="attach_camera">Rendszerkamera</string>
-	<string name="menu_restore">Biztonsági mentés visszaállítása</string>
-	<string name="restore_id_hint">Ide írja be az ID export karakterláncát</string>
-	<string name="location_placeholder">Helyszín</string>
-	<string name="video_placeholder">Videó</string>
-	<string name="audio_placeholder">Hang</string>
-	<string name="restoring_backup">Biztonsági mentés visszaállítása</string>
-	<string name="server_message_title">Üzenet a Threema szerverről</string>
-	<string name="error">Hiba</string>
-	<string name="no_contacts">Önnek még nincsenek kapcsolatai. Szinkronizálás bekapcsolása (Beállítások -
-		Adatvédelem), vagy adjon hozzá manuálisan névjegyeket.
-	</string>
-	<string name="masterkey_title">Jelszó megadása</string>
-	<string name="masterkey_body">A főkulcsot egy jelszó védi. A feloldáshoz adja meg a jelszót.
-	</string>
-	<string name="masterkey_unlocking">A főkulcs kinyitása</string>
-	<string name="verify_phonecall_text">Híváskérés</string>
-	<string name="prepare_call_message">Ha folytatja, azonnal megpróbáljuk felhívni Önt. Az ellenőrző kódot ezután
-		kétszer is felolvassák Önnek. Kérjük, vegye figyelembe: csak egy próbálkozása van.
-	</string>
-	<string name="enter_code_hint">Adja meg a kódot</string>
-	<string name="enter_code_sum">Kérjük, adja meg az SMS-ben vagy telefonhívásban kapott kódot.</string>
-	<string name="no_matching_contacts">Nem találtunk névjegyet.</string>
-	<string name="code_invalid">A megadott kód érvénytelen.</string>
-	<string name="try_again">Próbálja újra</string>
-	<string name="decoding_message">Az üzenet dekódolása</string>
-	<string name="invalid_barcode">Érvénytelen vonalkód</string>
-	<string name="expired_barcode">Ez a kód lejárt. Kérjük, olvassa be újra közvetlenül a másik felhasználó alkalmazásából.</string>
-	<string name="pending">Felülvizsgálat alatt</string>
-	<string name="unlinking_email">Az összekapcsolás bontása</string>
-	<string name="unlink">Bontás</string>
-	<string name="threema_version">Verzió</string>
-	<string name="wrong_backupid_or_password_or_no_internet_connection">Nincs internetkapcsolat, érvénytelen azonosító exportálási karakterlánc
-		vagy rossz jelszó
-	</string>
-	<string name="prefs_header_other">További</string>
-	<string name="an_error_occurred">Hiba történt</string>
-	<string name="an_error_occurred_more">Hiba történt: «%1$s»</string>
-	<string name="acknowledge">Megerősítés</string>
-	<string name="decline">Visszautasítás</string>
-	<string name="forward_message">Előre</string>
-	<string name="file_is_not_a_image">A kiválasztott fájl nem képfájl.</string>
-	<string name="connection_error">Kapcsolati hiba, kérjük, próbálja meg később újra.</string>
-	<string name="me_myself_and_i">Én</string>
-	<string name="really_forward">Továbbítás a «%1$s» címre?</string>
-	<string name="really_send">Küldés a «%1$s» címre?</string>
-	<string name="ringtone_none">Néma</string>
-	<string name="no_camera_installed">Nincs megfelelő kamera</string>
-	<string name="save_message_action">Mentés</string>
-	<string name="saving_media">A média mentése folyamatban van</string>
-	<string name="file_is_not_a_video">A kiválasztott fájl nem videó</string>
-	<string name="masterkey_is_unlocked">A főkulcs nyitva van</string>
-	<string name="file_too_large">A fájl nagyobb, mint a megengedett %1$d MB</string>
-	<string name="deleting_thread">A csevegés törlődik</string>
-	<string name="enter_serial_body">Kérjük, adja meg a boltban kapott licenckulcsát. Ha elfelejtette, kattintson ide:
-		https://shop.threema.ch/retrieve_keys
-	</string>
-	<string name="enter_serial_title">Threema feloldása</string>
-	<string name="serial_required_want_exit">A licenckulcs érvénytelen. Újra akarod próbálni, vagy kilépsz a Threemából?</string>
-	<string name="checking_serial">Az licenc ellenőrzése</string>
-	<string name="update_available">Frissítés elérhető</string>
-	<string name="no_update_available">Nincs frissítés</string>
-	<string name="download">Letöltés</string>
-	<string name="not_now">Emlékeztess később</string>
-	<string name="preparing_messages">Üzenetek összeállítása</string>
-	<string name="select_emoji">emojik</string>
-	<string name="search_contact">Névjegy keresés</string>
-	<string name="push_reset_title">Új push token készítése</string>
-	<string name="push_reset_text">Új push tokent készítettünk</string>
-	<string name="emoji_things">Tárgyak</string>
-	<string name="emoji_traffic">Forgalom</string>
-	<string name="emoji_symbols">Szimbólumok</string>
-	<string name="emoji_food">Étel és ital</string>
-	<string name="emoji_nature">Természet</string>
-	<string name="emoji_recent">Legutóbbi</string>
-	<string name="emoji_emotions">Érzelmek</string>
-	<string name="emoji_activities">Tevékenységek</string>
-	<string name="title_lock">Zárolás</string>
-	<string name="new_messages_locked">Új üzenetek elérhetők</string>
-	<string name="new_messages_locked_description">Érintse meg a megjelenítéshez</string>
-	<string name="new_unprocessed_messages">Új üzenetek elérhetők</string>
-	<string name="new_unprocessed_messages_description">Érintse meg a letöltéshez és megtekintéshez</string>
-	<string name="prefs_title_masterkey_notification_newmsg">Új üzenetek megjelenítése</string>
-	<string name="prefs_masterkey_notification_newmsg_off">Nincs értesítés új üzenetekről, ha a főkulcs zárolva van</string>
-	<string name="prefs_masterkey_notification_newmsg_on">Értesítés (részletek nélkül) új üzenetekről, ha a főkulcs zárolva van</string>
-	<string name="chat_history_attached">A csevegési naplót csatoltuk.</string>
-	<string name="new_message">1 új üzenet</string>
-	<string name="new_messages">új üzenetek</string>
-	<string name="backup_data_title">Adatmentés</string>
-	<string name="backup_data_password_msg">Az azonosító, a csevegések, a kapcsolatok és a beállítások az USB-meghajtón egy
-		ZIP-fájlban tárolódnak, és egy másik Android-eszközön visszaállíthatók. Adjon meg egy jelszót az adatmentéshez.
-	</string>
-	<string name="restore_data_password_msg">Itt adja meg a biztonsági mentés létrehozásakor beállított jelszót.
-	</string>
-	<string name="backup_data_media">Nagyméretű médiák (videók, fájlok, képek) mentése</string>
-	<string name="backup_data_new">Adatmentés létrehozása</string>
-	<string name="pinentry_enter_pin">A folytatáshoz adja meg a %s-PIN-kódot</string>
-	<string name="pinentry_wrong_pin">Rossz PIN-kód</string>
-	<string name="prefs_sum_security_pin">Az alkalmazáshoz való hozzáférés védelme</string>
-	<string name="prefs_title_pin_switch">Alkalmazás zárolása</string>
-	<string name="prefs_title_pin_code">PIN-kód beállítása</string>
-	<string name="prefs_pin_grace">Idő a zárásig</string>
-	<string name="prefs_sum_pin_grace">Időtartam kiválasztása</string>
-	<string name="click_here_to_change_pin">PIN-kód beállítva. Kattintson ide a módosításhoz</string>
-	<string name="set_pin_menu_title">Új PIN-kód beállítása</string>
-	<string name="set_pin_summary_intro">Védje magánéletét az alkalmazás PIN-zárának beállításával. A zár
+		ki, küldje el magának e-mailben a Megosztás funkció segítségével, vagy olvassa be a QR-kódot egy másik eszközzel.</string>
+    <string name="support">Súgó</string>
+    <string name="support_url">https://threema.ch/android/support/</string>
+    <string name="backup_share_content">A következő karakterláncot a kiválasztott jelszóval együtt használja a
+		Threema azonosító visszaszerzéséhez.</string>
+    <string name="backup_share_subject">Threema ID export a következőkhöz</string>
+    <string name="add_attachment">Beillesztés</string>
+    <string name="invalid_passphrase">Érvénytelen jelszó</string>
+    <string name="master_key_locked">A főkulcs zárolva van</string>
+    <string name="master_key_locked_notify_description">Jelszó megadása</string>
+    <string name="prefs_masterkey_passphrase">Nincs megadva jelszó</string>
+    <string name="prefs_title_masterkey_passphrase">Jelszó</string>
+    <string name="setting_masterkey_passphrase">Jelszó megadása a főkulcshoz</string>
+    <string name="masterkey_passphrase_title">Jelszó a főkulcshoz</string>
+    <string name="masterkey_passphrase_summary">A főkulcsot egy Ön által választott jelszóval tudja védeni.
+		Ha az alkalmazás be lett zárva, újra meg kell adnia a jelszót.</string>
+    <string name="masterkey_passphrase_again_summary">Jelszó ismétlése</string>
+    <string name="masterkey_passphrase_hint">Jelszó</string>
+    <string name="master_key_locked_want_exit">A főkulcs még mindig zárva van. Szeretné újra megpróbálni?</string>
+    <string name="click_here_to_change_passphrase">Kattintson ide a jelszó módosításához</string>
+    <string name="attach_camera">Rendszerkamera</string>
+    <string name="menu_restore">Biztonsági mentés visszaállítása</string>
+    <string name="restore_id_hint">Ide írja be az ID export karakterláncát</string>
+    <string name="location_placeholder">Helyszín</string>
+    <string name="video_placeholder">Videó</string>
+    <string name="audio_placeholder">Hang</string>
+    <string name="restoring_backup">Biztonsági mentés visszaállítása</string>
+    <string name="server_message_title">Üzenet a Threema szerverről</string>
+    <string name="error">Hiba</string>
+    <string name="no_contacts"><![CDATA[Önnek még nincsenek kapcsolatai. Szinkronizálás bekapcsolása (Beállítások -
+		Adatvédelem), vagy adjon hozzá manuálisan névjegyeket.]]></string>
+    <string name="masterkey_title">Jelszó megadása</string>
+    <string name="masterkey_body">A főkulcsot egy jelszó védi. A feloldáshoz adja meg a jelszót.</string>
+    <string name="masterkey_unlocking">A főkulcs kinyitása</string>
+    <string name="verify_phonecall_text">Híváskérés</string>
+    <string name="prepare_call_message">Ha folytatja, azonnal megpróbáljuk felhívni Önt. Az ellenőrző kódot ezután
+		kétszer is felolvassák Önnek. Kérjük, vegye figyelembe: csak egy próbálkozása van.</string>
+    <string name="enter_code_hint">Adja meg a kódot</string>
+    <string name="enter_code_sum">Kérjük, adja meg az SMS-ben vagy telefonhívásban kapott kódot.</string>
+    <string name="no_matching_contacts">Nem találtunk névjegyet.</string>
+    <string name="code_invalid">A megadott kód érvénytelen.</string>
+    <string name="try_again">Próbálja újra</string>
+    <string name="decoding_message">Az üzenet dekódolása</string>
+    <string name="invalid_barcode">Érvénytelen vonalkód</string>
+    <string name="expired_barcode">Ez a kód lejárt. Kérjük, olvassa be újra közvetlenül a másik felhasználó alkalmazásából.</string>
+    <string name="pending">Felülvizsgálat alatt</string>
+    <string name="unlinking_email">Az összekapcsolás bontása</string>
+    <string name="unlink">Bontás</string>
+    <string name="threema_version">Verzió</string>
+    <string name="wrong_backupid_or_password_or_no_internet_connection">Nincs internetkapcsolat, érvénytelen azonosító exportálási karakterlánc
+		vagy rossz jelszó</string>
+    <string name="prefs_header_other">További</string>
+    <string name="an_error_occurred">Hiba történt</string>
+    <string name="an_error_occurred_more">Hiba történt: «%1$s»</string>
+    <string name="acknowledge">Megerősítés</string>
+    <string name="decline">Visszautasítás</string>
+    <string name="forward_message">Előre</string>
+    <string name="file_is_not_a_image">A kiválasztott fájl nem képfájl.</string>
+    <string name="connection_error">Kapcsolati hiba, kérjük, próbálja meg később újra.</string>
+    <string name="me_myself_and_i">Én</string>
+    <string name="really_forward">Továbbítás a «%1$s» címre?</string>
+    <string name="really_send">Küldés a «%1$s» címre?</string>
+    <string name="ringtone_none">Néma</string>
+    <string name="no_camera_installed">Nincs megfelelő kamera</string>
+    <string name="save_message_action">Mentés</string>
+    <string name="saving_media">A média mentése folyamatban van</string>
+    <string name="file_is_not_a_video">A kiválasztott fájl nem videó</string>
+    <string name="masterkey_is_unlocked">A főkulcs nyitva van</string>
+    <string name="file_too_large">A fájl nagyobb, mint a megengedett %1$d MB</string>
+    <string name="deleting_thread">A csevegés törlődik</string>
+    <string name="enter_serial_body"><![CDATA[Kérjük, adja meg a boltban kapott licenckulcsát. Ha elfelejtette, kattintson ide:
+		https://shop.threema.ch/retrieve_keys]]></string>
+    <string name="enter_serial_title">Threema feloldása</string>
+    <string name="serial_required_want_exit">A licenckulcs érvénytelen. Újra akarod próbálni, vagy kilépsz a Threemából?</string>
+    <string name="checking_serial">Az licenc ellenőrzése</string>
+    <string name="update_available">Frissítés elérhető</string>
+    <string name="no_update_available">Nincs frissítés</string>
+    <string name="download">Letöltés</string>
+    <string name="not_now">Emlékeztess később</string>
+    <string name="preparing_messages">Üzenetek összeállítása</string>
+    <string name="select_emoji">emojik</string>
+    <string name="search_contact">Névjegy keresés</string>
+    <string name="push_reset_title">Új push token készítése</string>
+    <string name="push_reset_text">Új push tokent készítettünk</string>
+    <string name="emoji_things">Tárgyak</string>
+    <string name="emoji_traffic">Forgalom</string>
+    <string name="emoji_symbols">Szimbólumok</string>
+    <string name="emoji_nature">Természet</string>
+    <string name="emoji_food">Étel és ital</string>
+    <string name="emoji_recent">Legutóbbi</string>
+    <string name="emoji_emotions">Érzelmek</string>
+    <string name="emoji_activities">Tevékenységek</string>
+    <string name="emoji_flags">Zászlók</string>
+    <string name="title_lock">Zárolás</string>
+    <string name="new_messages_locked">Új üzenetek elérhetők</string>
+    <string name="new_messages_locked_description">Érintse meg a megjelenítéshez</string>
+    <string name="new_unprocessed_messages">Új üzenetek elérhetők</string>
+    <string name="new_unprocessed_messages_description">Érintse meg a letöltéshez és megtekintéshez</string>
+    <string name="prefs_title_masterkey_notification_newmsg">Új üzenetek megjelenítése</string>
+    <string name="prefs_masterkey_notification_newmsg_off">Nincs értesítés új üzenetekről, ha a főkulcs zárolva van</string>
+    <string name="prefs_masterkey_notification_newmsg_on">Értesítés (részletek nélkül) új üzenetekről, ha a főkulcs zárolva van</string>
+    <string name="chat_history_attached">A csevegési naplót csatoltuk.</string>
+    <string name="new_message">1 új üzenet</string>
+    <string name="new_messages">új üzenetek</string>
+    <string name="backup_data_title">Adatmentés</string>
+    <string name="backup_data_password_msg">Az azonosító, a csevegések, a kapcsolatok és a beállítások az USB-meghajtón egy
+		ZIP-fájlban tárolódnak, és egy másik Android-eszközön visszaállíthatók. Adjon meg egy jelszót az adatmentéshez.</string>
+    <string name="restore_data_password_msg">Itt adja meg a biztonsági mentés létrehozásakor beállított jelszót.</string>
+    <string name="backup_data_media">Nagyméretű médiák (videók, fájlok, képek) mentése</string>
+    <string name="backup_data_new">Adatmentés létrehozása</string>
+    <string name="pinentry_enter_pin">A folytatáshoz adja meg a %s-PIN-kódot</string>
+    <string name="pinentry_wrong_pin">Rossz PIN-kód</string>
+    <string name="prefs_sum_security_pin">Az alkalmazáshoz való hozzáférés védelme</string>
+    <string name="prefs_title_pin_switch">Alkalmazás zárolása</string>
+    <string name="prefs_title_pin_code">PIN-kód beállítása</string>
+    <string name="prefs_pin_grace">Idő a zárásig</string>
+    <string name="prefs_sum_pin_grace">Időtartam kiválasztása</string>
+    <string name="click_here_to_change_pin">PIN-kód beállítva. Kattintson ide a módosításhoz</string>
+    <string name="set_pin_menu_title">Új PIN-kód beállítása</string>
+    <string name="set_pin_summary_intro">Védje magánéletét az alkalmazás PIN-zárának beállításával. A zár
 		automatikusan aktiválódik a beállított várakozási idő után (csak számjegyek engedélyezettek).</string>
-	<string name="set_pin_again_summary">Ismételje meg a PIN-kódot</string>
-	<string name="set_pin_hint">PIN-kód</string>
-	<string name="title_addgroup">Új csoport</string>
-	<string name="search_group">Csoport keresése</string>
-	<string name="updating_system">Rendszerfrissítés</string>
-	<string name="title_select_contacts">Válassza ki a tagokat</string>
-	<string name="pin_invalid_not_set">PIN-kód érvénytelen</string>
-	<string name="prefs_group_notifications">Csoportos csevegés</string>
-	<string name="add_group_members_list">Csoporttagok</string>
-	<string name="group_select_at_least_two">Kérjük, válasszon legalább egy tagot</string>
-	<string name="group_select_max">A csoporthoz legfeljebb %1$d tag adható hozzá.</string>
-	<string name="search">Keresés</string>
-	<string name="hint_search_keyword">Keresési kifejezés</string>
-	<string name="add_group_owner">Létrehozó</string>
-	<string name="title_tab_users">Névjegyek</string>
-	<string name="title_tab_groups">Csoportok</string>
-	<string name="no_matching_groups">Nem találtunk csoportot</string>
-	<string name="action_leave_group">Csoport elhagyása</string>
-	<string name="group_edit_title">Csoport szerkesztése</string>
-	<string name="really_leave_group_message">Biztos, hogy el akarod hagyni ezt a csoportot?</string>
-	<string name="search_no_matches">Keresési kifejezés nem található</string>
-	<string name="search_no_more_matches">Nincs több találat</string>
-	<string name="backup_share">Biztonsági mentés továbbítása</string>
-	<string name="my_backups_title">Biztonsági mentések</string>
-	<string name="backup_delete_confirm">Biztonsági mentés fájl törölve</string>
-	<string name="message_log_title">Üzenet részletei</string>
-	<string name="state_read">elolvasva</string>
-	<string name="state_ack">megerősítve</string>
-	<string name="state_delivered">megkapva</string>
-	<string name="state_sending">küldés</string>
-	<string name="state_pending">várakozás</string>
-	<string name="state_failed">sikertelen</string>
-	<string name="state_sent">elküldve</string>
-	<string name="state_dialog_created">Létrehozva</string>
-	<string name="state_dialog_posted">Elküldve</string>
-	<string name="state_dialog_modified">Frissítve</string>
-	<string name="state_dialog_status">Állapot</string>
-	<string name="title_tab_recent">Legutóbbi</string>
-	<string name="no_recent_conversations">Nem találtunk csevegést</string>
-	<string name="save_changes">Mentés</string>
-	<string name="group_created_confirm">Csoport sikeresen létrehozva</string>
-	<string name="creating_group">Csoport létrehozása folyamatban</string>
-	<string name="updating_group">Csoport frissítése</string>
-	<string name="status_create_group">Csoport létrehozva.</string>
-	<string name="status_rename_group">Csoport átnevezve: «%1$s»</string>
-	<string name="status_group_new_photo">Csoport frissítve.</string>
-	<string name="status_group_new_member">«%1$s» hozzá lett adva a csoporthoz.</string>
-	<string name="status_group_member_left">«%1$s» elhagyta a csoportot.</string>
-	<string name="status_group_member_kicked">«%1$s» eltávolításra került a csoportból.</string>
-	<string name="can_not_send_no_group_members">Üres csoportnak nem küldhető üzenet.
-	</string>
-	<string name="you_are_not_a_member_of_this_group">Ön nem tagja ennek a csoportnak.</string>
-	<string name="can_not_delete_not_valid">Egy érvénytelen objektum nem távolítható el</string>
-	<string name="can_not_delete_contact_until_in_group">A névjegy nem törölhető, amíg még egy csoportban van.</string>
-	<string name="can_not_delete_contact">A névjegy nem törölhető</string>
-	<string name="title_public_nickname">Becenév</string>
-	<string name="prefs_sum_excluded_sync_identities">Az itt felsorolt ID-kat a kapcsolatok szinkronizálásakor figyelmen kívül hagyjuk.</string>
-	<string name="prefs_title_excluded_sync_identities">Kizárási lista</string>
-	<string name="synchronize_contact">Címjegyzék szinkronizálása</string>
-	<string name="exclude_contact">Szinkronizálásból kizárás.</string>
-	<string name="prefs_header_lists">Listák</string>
-	<string name="prefs_title_black_list">Blokkolt névjegyek</string>
-	<string name="prefs_sum_black_list">Az itt felsorolt ID-k üzeneteit a rendszer figyelmen kívül hagyja.</string>
-	<string name="verified">Ellenőrizve</string>
-	<string name="want_to_add_to_exclude_list">Ez a kapcsolat egy a telefonos címjegyzék bejegyzéséhez kapcsolódik.
+    <string name="set_pin_again_summary">Ismételje meg a PIN-kódot</string>
+    <string name="set_pin_hint">PIN-kód</string>
+    <string name="title_addgroup">Új csoport</string>
+    <string name="search_group">Csoport keresése</string>
+    <string name="updating_system">Rendszerfrissítés</string>
+    <string name="title_select_contacts">Válassza ki a tagokat</string>
+    <string name="pin_invalid_not_set">PIN-kód érvénytelen</string>
+    <string name="prefs_group_notifications">Csoportos csevegés</string>
+    <string name="add_group_members_list">Csoporttagok</string>
+    <string name="group_select_at_least_two">Kérjük, válasszon legalább egy tagot</string>
+    <string name="group_select_max" tools:ignore="PluralsCandidate">A csoporthoz legfeljebb %1$d tag adható hozzá.</string>
+    <string name="search">Keresés</string>
+    <string name="hint_search_keyword">Keresési kifejezés</string>
+    <string name="add_group_owner">Létrehozó</string>
+    <string name="title_tab_users">Névjegyek</string>
+    <string name="title_tab_groups">Csoportok</string>
+    <string name="no_matching_groups">Nem találtunk csoportot</string>
+    <string name="action_leave_group">Csoport elhagyása</string>
+    <string name="group_edit_title">Csoport szerkesztése</string>
+    <string name="really_leave_group_message">Biztos, hogy el akarod hagyni ezt a csoportot?</string>
+    <string name="search_no_matches">Keresési kifejezés nem található</string>
+    <string name="search_no_more_matches">Nincs több találat</string>
+    <string name="backup_share">Biztonsági mentés továbbítása</string>
+    <string name="my_backups_title">Biztonsági mentések</string>
+    <string name="backup_delete_confirm">Biztonsági mentés fájl törölve</string>
+    <string name="message_log_title">Üzenet részletei</string>
+    <string name="state_read">elolvasva</string>
+    <string name="state_ack">megerősítve</string>
+    <string name="state_dec">visszautasítva</string>
+    <string name="state_delivered">megkapva</string>
+    <string name="state_sending">küldés</string>
+    <string name="state_pending">várakozás</string>
+    <string name="state_failed">sikertelen</string>
+    <string name="state_sent">elküldve</string>
+    <string name="state_dialog_created">Létrehozva</string>
+    <string name="state_dialog_posted">Elküldve</string>
+    <string name="state_dialog_modified">Frissítve</string>
+    <string name="state_dialog_status">Állapot</string>
+    <string name="title_tab_recent">Legutóbbi</string>
+    <string name="no_recent_conversations">Nem találtunk csevegést</string>
+    <string name="save_changes">Mentés</string>
+    <string name="group_created_confirm">Csoport sikeresen létrehozva</string>
+    <string name="creating_group">Csoport létrehozása folyamatban</string>
+    <string name="updating_group">Csoport frissítése</string>
+    <string name="status_create_group">Csoport létrehozva.</string>
+    <string name="status_rename_group">Csoport átnevezve: «%1$s»</string>
+    <string name="status_group_new_photo">Csoport frissítve.</string>
+    <string name="status_group_new_member">«%1$s» hozzá lett adva a csoporthoz.</string>
+    <string name="status_group_member_left">«%1$s» elhagyta a csoportot.</string>
+    <string name="status_group_member_kicked">«%1$s» eltávolításra került a csoportból.</string>
+    <string name="can_not_send_no_group_members">Üres csoportnak nem küldhető üzenet.</string>
+    <string name="you_are_not_a_member_of_this_group">Ön nem tagja ennek a csoportnak.</string>
+    <string name="can_not_delete_not_valid">Egy érvénytelen objektum nem távolítható el</string>
+    <string name="can_not_delete_contact_until_in_group">A névjegy nem törölhető, amíg még egy csoportban van.</string>
+    <string name="can_not_delete_contact">A névjegy nem törölhető</string>
+    <string name="title_public_nickname">Becenév</string>
+    <string name="prefs_sum_excluded_sync_identities">Az itt felsorolt ID-kat a kapcsolatok szinkronizálásakor figyelmen kívül hagyjuk.</string>
+    <string name="prefs_title_excluded_sync_identities">Kizárási lista</string>
+    <string name="synchronize_contact">Címjegyzék szinkronizálása</string>
+    <string name="exclude_contact">Szinkronizálásból kizárás.</string>
+    <string name="prefs_header_lists">Listák</string>
+    <string name="prefs_title_black_list">Blokkolt névjegyek</string>
+    <string name="prefs_sum_black_list">Az itt felsorolt ID-k üzeneteit a rendszer figyelmen kívül hagyja.</string>
+    <string name="verified">Ellenőrizve</string>
+    <string name="want_to_add_to_exclude_list">Ez a kapcsolat egy a telefonos címjegyzék bejegyzéséhez kapcsolódik.
 		Ha törli a Threema rendszerben, akkor kapcsolat szinkronizálás után újra megjelenik.\nKívánja a jövőben
 		ezt az azonosítót kizárni a szinkronizálásból?</string>
-	<string name="no">Nem</string>
-	<string name="yes">Igen</string>
-	<string name="deleting_contact">A névjegy törlésre kerül</string>
-	<string name="prefs_contact_soring">Rendezés</string>
-	<string name="prefs_sum_contact_soring">A névjegyzék rendezésének beállítása</string>
-	<string name="prefs_contact_format">Névjegy nevének megjelenítése</string>
-	<string name="prefs_sum_contact_format">A névjegylista nevének megjelenítésére vonatkozó beállítás</string>
-	<string name="prefs_contact_list_title">Névjegylista</string>
-	<string name="prefs_default_contact_picture_colored">Színes kontaktképek</string>
-	<string name="prefs_show_inactive_contacts">Inaktív azonosítók megjelenítése</string>
-	<string name="prefs_sum_default_contact_picture_colored_on">Különböző színű helytartók megjelenítése, ha nincs kapcsolati kép.</string>
-	<string name="prefs_sum_default_contact_picture_colored_off">Szürke helytartók megjelenítése, ha nincs kapcsolati kép.</string>
-	<string name="prefs_sum_show_inactive_contacts_on">Az összes Threema azonosító megjelenítése a névjegyzékben.</string>
-	<string name="prefs_sum_show_inactive_contacts_off">Inaktív/visszavont Threema azonosítók elrejtése</string>
-	<string name="contact_sorting_first_name">Keresztnév - Vezetéknév</string>
-	<string name="contact_sorting_last_name">Vezetéknév - Keresztnév</string>
-	<string name="contact_format_first_name_last_name">Keresztnév Vezetéknév</string>
-	<string name="contact_format_last_name_first_name">Vezetéknév Keresztnév</string>
-	<string name="block_contact">Névjegy blokkolása</string>
-	<string name="unblock_contact">Névjegy feloldása</string>
-	<string name="unread_messages">%d olvasatlan üzenet</string>
-	<string name="one_unread_message">1 olvasatlan üzenet</string>
-	<string name="really_unlink_contact_title">Kapcsolat összecsatolás feloldása</string>
-	<string name="really_unlink_contact">Biztos, hogy el akarja távolítani a címjegyzéki kapcsolat összecsatolását?</string>
-	<string name="do_unlink_contact">Összecsatolás eltávolítása</string>
-	<string name="do_choose_other_contact">Válasszon ki egy másik névjegyet</string>
-	<string name="touch_to_link">(nincs)</string>
-	<string name="prefs_validate_contacts">Névjegy kapcsolat felülvizsgálása</string>
-	<string name="prefs_validate_contacts_loading">Névjegy kapcsolat felülvizsgálat alatt</string>
-	<string name="prefs_title_fullscreen_ime">Teljes képernyős billentyűzet</string>
-	<string name="prefs_sum_fullscreen_ime_on">A billentyűzet a teljes képernyőt kitölti fekvő módban</string>
-	<string name="prefs_sum_fullscreen_ime_off">A billentyűzet felett megjelenik a csevegés egy szakasza</string>
-	<string name="add_acount_from_within_threema">Hozzon létre egy új ID-t a Threema alkalmazásból.</string>
-	<string name="save_image">Kép mentése</string>
-	<string name="share_image">Kép megosztása</string>
-	<string name="view_in_gallery">Megtekintés a galériában</string>
-	<string name="file_saved">%d fájl(ok) mentve.</string>
-	<string name="token_register_failed">A push tokent nem sikerült frissíteni. Kérjük, próbálja meg később újra.</string>
-	<string name="internet_connection_required">Nincs internetkapcsolat.</string>
-	<string name="prefs_sum_save_media">A bejövő képek és videók, valamint a kimenő kameraképek titkosítás nélküli mentése</string>
-	<string name="prefs_save_media">Mentés a galériába</string>
-	<string name="title_add_distribution_list">Új elosztási lista</string>
-	<string name="title_edit_distribution_list">Elosztási lista szerkesztése</string>
-	<string name="really_delete_distribution_list">Elosztási lista törlése</string>
-	<string name="really_delete_distribution_list_message">Biztos, hogy törölni szeretné ezt az elosztási listát?</string>
-	<string name="enter_distribution_list_name">Válasszon nevet a listának</string>
-	<string name="distribution_list">Elosztási lista</string>
-	<string name="title_tab_distribution_list">Elosztási listák</string>
-	<string name="no_matching_distribution_lists">Még nincsenek elosztási listák meghatározva.</string>
-	<string name="is_typing">írja…</string>
-	<string name="backup_in_progress">Biztonsági mentés készítése</string>
-	<string name="backup_or_restore_success_body">Sikeresen létrehozott biztonsági mentés</string>
-	<string name="backup_or_restore_error">Threema biztonsági mentés</string>
-	<string name="backup_or_restore_error_body">A biztonsági mentés sikertelen</string>
-	<string name="could_not_download_message">Az üzenetet nem lehetett letölteni</string>
-	<string name="info">Információk</string>
-	<string name="resync_group">Csoport újraszinkronizálás</string>
-	<string name="edit_name">Név és kép beállítása</string>
-	<string name="group_was_synchronized">Csoport újraszinkronizálva</string>
-	<string name="verification_level2_work_explain">A szervezet által meghatározott belső kapcsolat.</string>
-	<string name="verification_level3_work_explain">Belső kapcsolat, akinek személyazonosságát és nyilvános kulcsát személyesen ellenőrizte a QR-kód beolvasásával.</string>
-	<string name="verification_level3_explain">Kapcsolat, amelynek személyazonosságát és nyilvános kulcsát személyesen ellenőrizte a QR-kód beolvasásával.
-	</string>
-	<string name="verification_level2_explain">Olyan kapcsolat, amelynek telefonszáma és/vagy e-mail címe szerepel az Ön címjegyzékében.
-	</string>
-	<string name="verification_level1_explain">Ismeretlen kapcsolat; a kapcsolat ID-jéhez nem tartozik se telefonszám, se e-mail cím,
+    <string name="no">Nem</string>
+    <string name="yes">Igen</string>
+    <string name="deleting_contact">A névjegy törlésre kerül</string>
+    <string name="prefs_contact_soring">Rendezés</string>
+    <string name="prefs_sum_contact_soring">A névjegyzék rendezésének beállítása</string>
+    <string name="prefs_contact_format">Névjegy nevének megjelenítése</string>
+    <string name="prefs_sum_contact_format">A névjegylista nevének megjelenítésére vonatkozó beállítás</string>
+    <string name="prefs_contact_list_title">Névjegylista</string>
+    <string name="prefs_default_contact_picture_colored">Színes kontaktképek</string>
+    <string name="prefs_show_inactive_contacts">Inaktív azonosítók megjelenítése</string>
+    <string name="prefs_sum_default_contact_picture_colored_on">Különböző színű helytartók megjelenítése, ha nincs kapcsolati kép.</string>
+    <string name="prefs_sum_default_contact_picture_colored_off">Szürke helytartók megjelenítése, ha nincs kapcsolati kép.</string>
+    <string name="prefs_sum_show_inactive_contacts_on">Az összes Threema azonosító megjelenítése a névjegyzékben.</string>
+    <string name="prefs_sum_show_inactive_contacts_off">Inaktív/visszavont Threema azonosítók elrejtése</string>
+    <string name="contact_sorting_first_name">Keresztnév - Vezetéknév</string>
+    <string name="contact_sorting_last_name">Vezetéknév - Keresztnév</string>
+    <string name="contact_format_first_name_last_name">Keresztnév Vezetéknév</string>
+    <string name="contact_format_last_name_first_name">Vezetéknév Keresztnév</string>
+    <string name="block_contact">Névjegy blokkolása</string>
+    <string name="unblock_contact">Névjegy feloldása</string>
+    <string name="unread_messages">%d olvasatlan üzenet</string>
+    <string name="one_unread_message">1 olvasatlan üzenet</string>
+    <string name="really_unlink_contact_title">Kapcsolat összecsatolás feloldása</string>
+    <string name="really_unlink_contact">Biztos, hogy el akarja távolítani a címjegyzéki kapcsolat összecsatolását?</string>
+    <string name="do_unlink_contact">Összecsatolás eltávolítása</string>
+    <string name="do_choose_other_contact">Válasszon ki egy másik névjegyet</string>
+    <string name="touch_to_link">(nincs)</string>
+    <string name="prefs_validate_contacts">Névjegy kapcsolat felülvizsgálása</string>
+    <string name="prefs_validate_contacts_loading">Névjegy kapcsolat felülvizsgálat alatt</string>
+    <string name="prefs_title_fullscreen_ime">Teljes képernyős billentyűzet</string>
+    <string name="prefs_sum_fullscreen_ime_on">A billentyűzet a teljes képernyőt kitölti fekvő módban</string>
+    <string name="prefs_sum_fullscreen_ime_off">A billentyűzet felett megjelenik a csevegés egy szakasza</string>
+    <string name="add_acount_from_within_threema">Hozzon létre egy új ID-t a Threema alkalmazásból.</string>
+    <string name="save_image">Kép mentése</string>
+    <string name="share_image">Kép megosztása</string>
+    <string name="view_in_gallery">Megtekintés a galériában</string>
+    <string name="file_saved">%d fájl(ok) mentve.</string>
+    <string name="token_register_failed">A push tokent nem sikerült frissíteni. Kérjük, próbálja meg később újra.</string>
+    <string name="internet_connection_required">Nincs internetkapcsolat.</string>
+    <string name="prefs_sum_save_media">A bejövő képek és videók, valamint a kimenő kameraképek titkosítás nélküli mentése</string>
+    <string name="prefs_save_media">Mentés a galériába</string>
+    <string name="title_add_distribution_list">Új elosztási lista</string>
+    <string name="title_edit_distribution_list">Elosztási lista szerkesztése</string>
+    <string name="really_delete_distribution_list">Elosztási lista törlése</string>
+    <string name="really_delete_distribution_list_message">Biztos, hogy törölni szeretné ezt az elosztási listát?</string>
+    <string name="enter_distribution_list_name">Válasszon nevet a listának</string>
+    <string name="distribution_list">Elosztási lista</string>
+    <string name="title_tab_distribution_list">Elosztási listák</string>
+    <string name="no_matching_distribution_lists">Még nincsenek elosztási listák meghatározva.</string>
+    <string name="is_typing">írja…</string>
+    <string name="push_not_available_title">Push szolgáltatás nem elérhető</string>
+    <string name="backup_in_progress">Biztonsági mentés készítése</string>
+    <string name="backup_or_restore_success_body">Sikeresen létrehozott biztonsági mentés</string>
+    <string name="backup_or_restore_error">Threema biztonsági mentés</string>
+    <string name="backup_or_restore_error_body">A biztonsági mentés sikertelen</string>
+    <string name="could_not_download_message">Az üzenetet nem lehetett letölteni</string>
+    <string name="info">Információk</string>
+    <string name="resync_group">Csoport újraszinkronizálás</string>
+    <string name="edit_name">Név és kép beállítása</string>
+    <string name="edit_name_only">Névváltoztatás</string>
+    <string name="group_was_synchronized">Csoport újraszinkronizálva</string>
+    <string name="verification_level2_work_explain">A szervezet által meghatározott belső kapcsolat.</string>
+    <string name="verification_level3_work_explain">Belső kapcsolat, akinek személyazonosságát és nyilvános kulcsát személyesen ellenőrizte a QR-kód beolvasásával.</string>
+    <string name="verification_level3_explain">Kapcsolat, amelynek személyazonosságát és nyilvános kulcsát személyesen ellenőrizte a QR-kód beolvasásával.</string>
+    <string name="verification_level2_explain">Olyan kapcsolat, amelynek telefonszáma és/vagy e-mail címe szerepel az Ön címjegyzékében.</string>
+    <string name="verification_level1_explain">Ismeretlen kapcsolat; a kapcsolat ID-jéhez nem tartozik se telefonszám, se e-mail cím,
 		vagy a címjegyzék nem tartalmazza ezeket az információkat.</string>
-	<string name="state_dialog_received">Fogadva</string>
-	<string name="prefs_title_hide_screenshots">Miniatűrök és képernyőképek rejt.</string>
-	<string name="prefs_summary_hide_screenshots">A miniatűrök elrejtése az alkalmazásváltóban és a képernyőképek készítésének megakadályozása</string>
-	<string name="media_gallery">Média galéria</string>
-	<string name="media_file_not_found">A médiafájl nem nyitható meg. Törölték vagy nem töltötte le a szerverről.</string>
-	<string name="no_media_found">Ebben a csevegésben nem találtunk %s-t.</string>
-	<string name="media_gallery_all">Minden</string>
-	<string name="media_gallery_pictures">Képek</string>
-	<string name="media_gallery_videos">Videók</string>
-	<string name="group_membership_title">Ezeknek a csoportoknak a tagja</string>
-	<string name="num_items_sected">%s kiválasztott</string>
-	<string name="really_delete_media">Tényleg törölni szeretné ezt a(z) %d médiaüzenetet?</string>
-	<string name="check_updates">Frissítések keresése</string>
-	<string name="masterkey_lock_explain">A Threema a jelszót a RAM memóriában tartja. Ha gyakran kéri a jelszót,
-		az lehet, hogy egy taskkiller vagy akkumulátorkímélő alkalmazás miatt van, amely eltávolítja a jelszót a memóriából.
-	</string>
-	<string name="identity_already_exists">Ez az ID már szerepel a névjegyzékében</string>
-	<string name="share_contact">Kapcsolat megosztása</string>
-	<string name="add_shortcut">Parancsikon létrehozása</string>
-	<string name="group_not_found">A csoport nem található.</string>
-	<string name="contact_not_found">Névjegy nem található</string>
-	<string name="contact_now_blocked">Névjegy blokkolva</string>
-	<string name="contact_now_unblocked">Névjegy feloldva</string>
-	<string name="not_enough_disk_space_title">Túl kevés tárolóhely</string>
-	<string name="not_enough_disk_space_text">Legalább %1$s szükséges az üzenet fogadásához</string>
-	<string name="sending_images">Képek küldése</string>
-	<string name="share_conversation_body">A fájl megnyitásához egy modern, AES-támogatással rendelkező ZIP-programra
-		van szükség. pl. http://www.7-zip.org vagy https://itunes.apple.com/de/app/the-unarchiver/id425424353
-	</string>
-	<string name="enter_zip_password_body">A csevegés titkosított zip-fájlként kerül elküldésre. Kérjük, válasszon egy jelszót:</string>
-	<string name="new_messages_in_chats">%1$d új üzenet %2$d csevegésben</string>
-	<string name="ballot_create">Szavazás létrehozása</string>
-	<string name="ballot_choice_add">válasz szövege</string>
-	<string name="ballot_state_closed">zárva</string>
-	<string name="ballot_vote">Szavaz</string>
-	<string name="ballot_placeholder">Szavazás</string>
-	<string name="ballot_close">A szavazás lezárása</string>
-	<string name="ballot_really_close">Szeretné lezárni ezt a szavazást, és elérhetővé tenni az eredményeket?</string>
-	<string name="ballot_multiple_choice">Többszörös választás</string>
-	<string name="ballot_result_intermediate">Közbenső eredmények</string>
-	<string name="ballot_error_more_than_x_choices">Legalább két választási lehetőséget kell létrehoznia</string>
-	<string name="ballot_message_closed">Az eredmények készen állnak</string>
-	<string name="ballot_vote_posted_successfully">Sikeresen leadott szavazat</string>
-	<string name="ballot_vote_posted_failed">A szavazás sikertelen</string>
-	<string name="attach_ballot">Szavazás</string>
-	<string name="ballot_overview">Összes szavazás</string>
-	<string name="ballot_copy">Szavazás másolása</string>
-	<string name="ballot_remove">Szavazás eltávolítása</string>
-	<string name="ballot_really_delete">Szavazás törlése</string>
-	<string name="ballot_really_delete_text">Tényleg törölni akarja a %1$d szavazatot? A szavazatokat nem lehet visszaállítani.
-	</string>
-	<string name="ballot_not_exist">A szavazás nem létezik</string>
-	<string name="ballot_tap_to_vote">Szavazás megérintéssel</string>
-	<string name="ballot_tap_to_view_results">Szavazás lezárva. Érintse meg az eredményekért</string>
-	<string name="ballot_subject_hint">Szavazás címének megadása</string>
-	<string name="ballot_no_ballots_yet">Még nincsenek szavazások.</string>
-	<string name="print">Nyomtatás</string>
-	<string name="ballot_wizard0_explain">Gyorsan és egyszerűen hozhat létre szavazást közvetlenül a Threema programban.
-		Szervezzen időpontot, vagy végezzen szavazást barátai körében.
-	</string>
-	<string name="ballot_add_choices">Válaszlehetőségek megadása</string>
-	<string name="blocked_cannot_send">Nem küldhet üzeneteket blokkolt névjegytől</string>
-	<string name="really_block_contact">Többé nem fog üzeneteket kapni ettől a névjegytől. Folytatja?
-	</string>
-	<string name="ballot_result_final">Végeredmény</string>
-	<string name="invalid_cannot_send">Nem küldhet üzenetet érvénytelen kapcsolatnak</string>
-	<string name="ballot_answer_count_error">Kérjük, legalább két választ adjon meg.</string>
-	<string name="ballot_one_contact_not_supported">Figyelem: %1$s még nem tud részt venni a szavazásokban.</string>
-	<string name="ballot_x_contact_not_supported">Figyelem: %1$d kapcsolat még nem tud részt venni a szavazásokban.
-	</string>
-	<string name="contact_state_inactive">Inaktív</string>
-	<string name="contact_state_invalid">Érvénytelen</string>
-	<string name="back">Vissza</string>
-	<string name="wearable_reply">Válasz</string>
-	<string name="wearable_reply_label">Válasz %s-nak</string>
-	<string name="message_acknowledged">Üzenet megerősítve</string>
-	<string name="push_disable_text">Ha folytatja, a push üzenetek letiltásra kerülnek, és
-		a Threema 15 percenként ellenőrzi az új üzeneteket.
-	</string>
-	<string name="ballot_intermediate_results_show">Közbenső eredmények megjelenítése</string>
-	<string name="converting_video">A videó feldolgozása folyamatban van</string>
-	<string name="video_size_small">Magas (kis mennyiségű adat)</string>
-	<string name="video_size_large">Alacsony (közepes adatmennyiség)</string>
-	<string name="video_size_original">Nincs (nagy mennyiségű adat)</string>
-	<string name="prefs_video_size">Videó tömörítés</string>
-	<string name="show_contact">Névjegy megjelenítése</string>
-	<string name="chat_with">Csevegés %1$s</string>
-	<string name="kick_user_from_group">%1$s eltávolítása a csoportból</string>
-	<string name="show_as_qrcode">QR-kódként megjeleníteni</string>
-	<string name="qr_code">QR-kód</string>
-	<string name="really_leave_id_export">Győződjön meg róla, hogy az ID exportálási karakterláncot vagy
+    <string name="state_dialog_received">Fogadva</string>
+    <string name="prefs_title_hide_screenshots">Miniatűrök és képernyőképek rejt.</string>
+    <string name="prefs_summary_hide_screenshots">A miniatűrök elrejtése az alkalmazásváltóban és a képernyőképek készítésének megakadályozása</string>
+    <string name="media_gallery">Média galéria</string>
+    <string name="media_file_not_found">A médiafájl nem nyitható meg. Törölték vagy nem töltötte le a szerverről.</string>
+    <string name="no_media_found">Ebben a csevegésben nem találtunk %s-t.</string>
+    <string name="media_gallery_all">Minden</string>
+    <string name="media_gallery_pictures">Képek</string>
+    <string name="media_gallery_videos">Videók</string>
+    <string name="group_membership_title">Ezeknek a csoportoknak a tagja</string>
+    <string name="num_items_sected">%s kiválasztott</string>
+    <string name="really_delete_media" tools:ignore="PluralsCandidate">Tényleg törölni szeretné ezt a(z) %d médiaüzenetet?</string>
+    <string name="check_updates">Frissítések keresése</string>
+    <string name="masterkey_lock_explain">A Threema a jelszót a RAM memóriában tartja. Ha gyakran kéri a jelszót,
+		az lehet, hogy egy taskkiller vagy akkumulátorkímélő alkalmazás miatt van, amely eltávolítja a jelszót a memóriából.</string>
+    <string name="identity_already_exists">Ez az ID már szerepel a névjegyzékében</string>
+    <string name="share_contact">Kapcsolat megosztása</string>
+    <string name="add_shortcut">Parancsikon létrehozása</string>
+    <string name="group_not_found">A csoport nem található.</string>
+    <string name="contact_not_found">Névjegy nem található</string>
+    <string name="contact_now_blocked">Névjegy blokkolva</string>
+    <string name="contact_now_unblocked">Névjegy feloldva</string>
+    <string name="not_enough_disk_space_title">Túl kevés tárolóhely</string>
+    <string name="not_enough_disk_space_text">Legalább %1$s szükséges az üzenet fogadásához</string>
+    <string name="sending_images">Képek küldése</string>
+    <string name="share_conversation_body">A fájl megnyitásához egy modern, AES-támogatással rendelkező ZIP-programra
+		van szükség. pl. http://www.7-zip.org vagy https://itunes.apple.com/de/app/the-unarchiver/id425424353</string>
+    <string name="enter_zip_password_body">A csevegés titkosított zip-fájlként kerül elküldésre. Kérjük, válasszon egy jelszót:</string>
+    <string name="new_messages_in_chats" tools:ignore="PluralsCandidate">%1$d új üzenet %2$d csevegésben</string>
+    <string name="ballot_create">Szavazás létrehozása</string>
+    <string name="ballot_choice_add">válasz szövege</string>
+    <string name="ballot_state_closed">zárva</string>
+    <string name="ballot_vote">Szavaz</string>
+    <string name="ballot_placeholder">Szavazás</string>
+    <string name="ballot_close">A szavazás lezárása</string>
+    <string name="ballot_really_close">Szeretné lezárni ezt a szavazást, és elérhetővé tenni az eredményeket?</string>
+    <string name="ballot_multiple_choice">Többszörös választás</string>
+    <string name="ballot_result_intermediate">Közbenső eredmények</string>
+    <string name="ballot_error_more_than_x_choices">Legalább két választási lehetőséget kell létrehoznia</string>
+    <string name="ballot_message_closed">Az eredmények készen állnak</string>
+    <string name="ballot_vote_posted_successfully">Sikeresen leadott szavazat</string>
+    <string name="ballot_vote_posted_failed">A szavazás sikertelen</string>
+    <string name="attach_ballot">Szavazás</string>
+    <string name="ballot_overview">Összes szavazás</string>
+    <string name="ballot_copy">Szavazás másolása</string>
+    <string name="ballot_remove">Szavazás eltávolítása</string>
+    <string name="ballot_really_delete">Szavazás törlése</string>
+    <string name="ballot_really_delete_text" tools:ignore="PluralsCandidate">Tényleg törölni akarja a %1$d szavazatot? A szavazatokat nem lehet visszaállítani.</string>
+    <string name="ballot_not_exist">A szavazás nem létezik</string>
+    <string name="ballot_tap_to_vote">Szavazás megérintéssel</string>
+    <string name="ballot_tap_to_view_results">Szavazás lezárva. Érintse meg az eredményekért</string>
+    <string name="ballot_subject_hint">Szavazás címének megadása</string>
+    <string name="ballot_no_ballots_yet">Még nincsenek szavazások.</string>
+    <string name="print">Nyomtatás</string>
+    <string name="ballot_wizard0_explain">Gyorsan és egyszerűen hozhat létre szavazást közvetlenül a Threema programban.
+		Szervezzen időpontot, vagy végezzen szavazást barátai körében.</string>
+    <string name="ballot_add_choices">Válaszlehetőségek megadása</string>
+    <string name="blocked_cannot_send">Nem küldhet üzeneteket blokkolt névjegytől</string>
+    <string name="really_block_contact">Többé nem fog üzeneteket kapni ettől a névjegytől. Folytatja?</string>
+    <string name="ballot_result_final">Végeredmény</string>
+    <string name="invalid_cannot_send">Nem küldhet üzenetet érvénytelen kapcsolatnak</string>
+    <string name="ballot_answer_count_error">Kérjük, legalább két választ adjon meg.</string>
+    <string name="ballot_one_contact_not_supported">Figyelem: %1$s még nem tud részt venni a szavazásokban.</string>
+    <string name="ballot_x_contact_not_supported" tools:ignore="PluralsCandidate">Figyelem: %1$d kapcsolat még nem tud részt venni a szavazásokban.</string>
+    <string name="contact_state_inactive">Inaktív</string>
+    <string name="contact_state_invalid">Érvénytelen</string>
+    <string name="back">Vissza</string>
+    <string name="wearable_reply">Válasz</string>
+    <string name="wearable_reply_label">Válasz %s-nak</string>
+    <string name="message_acknowledged">Üzenet megerősítve</string>
+    <string name="push_disable_text">Ha folytatja, a push üzenetek letiltásra kerülnek, és
+		a Threema 15 percenként ellenőrzi az új üzeneteket.</string>
+    <string name="ballot_intermediate_results_show">Közbenső eredmények megjelenítése</string>
+    <string name="converting_video">A videó feldolgozása folyamatban van</string>
+    <string name="video_size_small">Magas (kis mennyiségű adat)</string>
+    <string name="video_size_large">Alacsony (közepes adatmennyiség)</string>
+    <string name="video_size_original">Nincs (nagy mennyiségű adat)</string>
+    <string name="prefs_video_size">Videó tömörítés</string>
+    <string name="show_contact">Névjegy megjelenítése</string>
+    <string name="chat_with">Csevegés %1$s</string>
+    <string name="kick_user_from_group">%1$s eltávolítása a csoportból</string>
+    <string name="show_as_qrcode">QR-kódként megjeleníteni</string>
+    <string name="qr_code">QR-kód</string>
+    <string name="really_leave_id_export">Győződjön meg róla, hogy az ID exportálási karakterláncot vagy
 		a QR-kódot elmentette egy biztonságos helyre vagy kinyomtatta.</string>
-	<string name="prefs_sum_remove_wallpapers">Az összes egyedi háttérkép eltávolítása</string>
-	<string name="prefs_title_remove_wallpapers">Minden háttérkép eltávolítása</string>
-	<string name="really_remove_wallpapers">Biztos, hogy az összes háttérképet el akarja távolítani?</string>
-	<string name="wallpapers_removed">Háttérképek eltávolítva</string>
-	<string name="invalid_backup">A biztonsági másolat adatai érvénytelenek. Visszaállítás nem lehetséges.</string>
-	<string name="revocation_key_title">ID visszavonása</string>
-	<string name="revocation_key_not_set">Nincs visszavonási jelszó beállítva</string>
-	<string name="revocation_key_set_at">Jelszó megadva %1$s</string>
-	<string name="revocation_explain">Az itt megadott jelszóval visszavonhatja ID-jét a
-		https://myid.threema.ch/revoke címen, ha elveszítette vagy ellopták.
-	</string>
-	<string name="no_unread_messages">Nincsenek olvasatlan üzenetek vagy a PIN-zár aktív</string>
-	<string name="send_media">Média küldése</string>
-	<string name="rotate">Elforgatni</string>
-	<string name="remove">Eltávolítani</string>
-	<string name="image_already_added">Ez a kép már ki van választva.</string>
-	<string name="password_too_short">Legalább %d karakter</string>
-	<string name="mark_read">Elolvasottként megjelölés</string>
-	<string name="emoji_flags">Zászlók</string>
-	<string name="attach_document">Fájl</string>
-	<string name="parent_directory">Felső könyvtár</string>
-	<string name="file_placeholder">Fájl</string>
-	<string name="internal_storage">Tárhely</string>
-	<string name="no_activity_for_mime_type">Nem találtunk megfelelő alkalmazást ehhez a fájlhoz.</string>
-	<string name="message_copied">Üzenet másolva</string>
-	<string name="open_from">Megnyitás</string>
-	<string name="file_one_contact_not_supported">%1$s még nem tud fájlokat fogadni.</string>
-	<string name="file_x_contact_not_supported">Figyelmeztetés: %1$d kapcsolat nem tud fájlokat fogadni.</string>
-	<string name="mime_android_apk">Android csomag</string>
-	<string name="mime_audio">Hangfájl</string>
-	<string name="mime_certificate">Digitális tanúsítvány</string>
-	<string name="mime_codes">Programkód</string>
-	<string name="mime_compressed">Tömörített fájl</string>
-	<string name="mime_contact">Névjegy</string>
-	<string name="mime_event">Meghívó</string>
-	<string name="mime_font">Betűtípus fájl</string>
-	<string name="mime_image">Kép</string>
-	<string name="mime_pdf">PDF dokumentum</string>
-	<string name="mime_presentation">Prezentáció</string>
-	<string name="mime_spreadsheet">Táblázat</string>
-	<string name="mime_text">Szöveges fájl</string>
-	<string name="mime_video">Videó fájl</string>
-	<string name="mime_word">Szöveges dokumentum</string>
-	<string name="no_filename"><![CDATA[<Nincs fájlnév>]]></string>
-	<string name="send_as_files">Küldés fájlként</string>
-	<string name="send_as_files_warning">A tömörítetlen fájlok és képek továbbítása megnövekedett adatfogyasztáshoz vezet.
-		Ez további költségeket eredményezhet a mobiltelefon-szolgáltatónál. Javasoljuk a WLAN használatát.
-	</string>
-	<string name="prefs_theme">Dizájn stílus</string>
-	<string name="list_theme_light">Világos (standard)</string>
-	<string name="list_theme_dark">Sötét</string>
-	<string name="prefs_header_appearance">Megjelenés</string>
-	<string name="prefs_sum_passphrase">Jelszó megkövetelése a helyi titkosításhoz</string>
-	<string name="prefs_title_masterkey_change_passphrase">Jelszó módosítása</string>
-	<string name="storage_total">Belső tároló</string>
-	<string name="storage_threema">Threema által használt</string>
-	<string name="storage_total_free">Szabad tárhely</string>
-	<string name="storage_total_in_use">Felhasznált</string>
-	<string name="one_year">1 év</string>
-	<string name="six_months">6 hónap</string>
-	<string name="three_months">3 hónap</string>
-	<string name="one_month">1 hónap</string>
-	<string name="one_week">1 hét</string>
-	<string name="everything">mind</string>
-	<string name="delete_media_files_time">Törölje a következőnél régebbi médiákat és fájlokat:</string>
-	<string name="storage_explain">Ha kifogyóban van a tárhelye, törölheti a titkosított formában tárolt régi
+    <string name="revocation_key_title">ID visszavonása</string>
+    <string name="revocation_key_not_set">Nincs visszavonási jelszó beállítva</string>
+    <string name="revocation_key_set_at">Jelszó megadva %1$s</string>
+    <string name="prefs_sum_remove_wallpapers">Az összes egyedi háttérkép eltávolítása</string>
+    <string name="prefs_title_remove_wallpapers">Minden háttérkép eltávolítása</string>
+    <string name="really_remove_wallpapers">Biztos, hogy az összes háttérképet el akarja távolítani?</string>
+    <string name="wallpapers_removed">Háttérképek eltávolítva</string>
+    <string name="invalid_backup">A biztonsági másolat adatai érvénytelenek. Visszaállítás nem lehetséges.</string>
+    <string name="revocation_explain">Az itt megadott jelszóval visszavonhatja ID-jét a
+		https://myid.threema.ch/revoke címen, ha elveszítette vagy ellopták.</string>
+    <string name="no_unread_messages">Nincsenek olvasatlan üzenetek vagy a PIN-zár aktív</string>
+    <string name="send_media">Média küldése</string>
+    <string name="rotate">Elforgatni</string>
+    <string name="remove">Eltávolítani</string>
+    <string name="image_already_added">Ez a kép már ki van választva.</string>
+    <string name="password_too_short" tools:ignore="PluralsCandidate">Legalább %d karakter</string>
+    <string name="mark_read">Elolvasottként megjelölés</string>
+    <string name="attach_document">Fájl</string>
+    <string name="parent_directory">Felső könyvtár</string>
+    <string name="file_placeholder">Fájl</string>
+    <string name="internal_storage">Tárhely</string>
+    <string name="no_activity_for_mime_type">Nem találtunk megfelelő alkalmazást ehhez a fájlhoz.</string>
+    <string name="open_from">Megnyitás</string>
+    <string name="file_one_contact_not_supported">%1$s még nem tud fájlokat fogadni.</string>
+    <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Figyelmeztetés: %1$d kapcsolat nem tud fájlokat fogadni.</string>
+    <string name="mime_android_apk">Android csomag</string>
+    <string name="mime_audio">Hangfájl</string>
+    <string name="mime_certificate">Digitális tanúsítvány</string>
+    <string name="mime_codes">Programkód</string>
+    <string name="mime_compressed">Tömörített fájl</string>
+    <string name="mime_contact">Névjegy</string>
+    <string name="mime_event">Meghívó</string>
+    <string name="mime_font">Betűtípus fájl</string>
+    <string name="mime_image">Kép</string>
+    <string name="mime_pdf">PDF dokumentum</string>
+    <string name="mime_presentation">Prezentáció</string>
+    <string name="mime_spreadsheet">Táblázat</string>
+    <string name="mime_text">Szöveges fájl</string>
+    <string name="mime_video">Videó fájl</string>
+    <string name="mime_word">Szöveges dokumentum</string>
+    <string name="no_filename"><![CDATA[<Nincs fájlnév>]]></string>
+    <string name="send_as_files">Küldés fájlként</string>
+    <string name="send_as_files_warning">A tömörítetlen fájlok és képek továbbítása megnövekedett adatfogyasztáshoz vezet.
+		Ez további költségeket eredményezhet a mobiltelefon-szolgáltatónál. Javasoljuk a WLAN használatát.</string>
+    <string name="prefs_theme">Dizájn stílus</string>
+    <string name="list_theme_light">Világos (standard)</string>
+    <string name="list_theme_dark">Sötét</string>
+    <string name="prefs_header_appearance">Megjelenés</string>
+    <string name="prefs_sum_passphrase">Jelszó megkövetelése a helyi titkosításhoz</string>
+    <string name="prefs_title_masterkey_change_passphrase">Jelszó módosítása</string>
+    <string name="storage_total">Belső tároló</string>
+    <string name="storage_threema">Threema által használt</string>
+    <string name="storage_total_free">Szabad tárhely</string>
+    <string name="storage_total_in_use">Felhasznált</string>
+    <string name="one_year">1 év</string>
+    <string name="six_months">6 hónap</string>
+    <string name="three_months">3 hónap</string>
+    <string name="one_month">1 hónap</string>
+    <string name="one_week">1 hét</string>
+    <string name="everything">mind</string>
+    <string name="delete_media_files_time">Törölje a következőnél régebbi médiákat és fájlokat:</string>
+    <string name="storage_explain">Ha kifogyóban van a tárhelye, törölheti a titkosított formában tárolt régi
 		médiafájlokat, hogy helyet szabadítson fel. A miniatűrök megmaradnak. Vegye figyelembe, hogy ez nem
-		automatikus folyamat. Csak akkor törlődik, ha megérinti az alábbi gombok egyikét.
-	</string>
-	<string name="delete_data">Adatok törlése most</string>
-	<string name="delete_date_confirm_message">A fájlok véglegesen törlődnek, és csak a miniatűrök maradnak meg.</string>
-	<string name="media_files_deleted">%d Média/fájlok törölve.</string>
-	<string name="storage_management">Tároláskezelés</string>
-	<string name="media">Média</string>
-	<string name="prefs_storage_mgmt_title">Fájlok és üzenetek tisztítása</string>
-	<string name="num_messages">Üzenetek száma</string>
-	<string name="delete_messages_explain">A következőnél régebbi üzenetek törlése:</string>
-	<string name="delete_message">Üzenetek törlése</string>
-	<string name="really_delete_messages">Az üzenetek teljesen törlődnek, és nem állíthatók vissza.</string>
-	<string name="messages_delete_explain">A régi üzeneteket teljesen törölheti.</string>
-	<string name="backup_started">Az adatmentés elindult</string>
-	<string name="invalid_data">Érvénytelen adat. Küldés nem lehetséges.</string>
-	<string name="prefs_android_emojis">Rendszer emojik</string>
-	<string name="prefs_emoji_style">Emoji stílus</string>
-	<string name="prefs_default_emojis">Threema-emojik (alapértelmezett)</string>
-	<string name="android_emojis_warning">Megjegyzés: Előfordulhat, hogy a rendszer karakterkészlete nem képes
-		megjeleníteni a Threema által támogatott összes emojit.
-	</string>
-	<string name="crop">Kivágás</string>
-	<string name="scan_id_mismatch_title">Az ID nem egyezik</string>
-	<string name="scan_id_mismatch_message">A beolvasott ID nem egyezik a mentett névjeggyel.
-	</string>
-	<string name="title_remove_picture">Kép eltávolítása</string>
-	<string name="blocked">blokkolt</string>
-	<string name="name">Név</string>
-	<string name="privacy_policy">Adatvédelmi szabályzat</string>
-	<string name="terms_of_service">Általános Szerződési Feltételek</string>
-	<string name="save_group_changes">Szeretné a csoportra alkalmazni a módosításokat?</string>
-	<string name="prefs_title_fontsize">Betűméret</string>
-	<string name="fontsize_normal">Normál</string>
-	<string name="fontsize_large">Nagy</string>
-	<string name="fontsize_xlarge">Nagyon nagy</string>
-	<string name="no_app_for_location">Ezen a készüléken nem található térképalkalmazás.</string>
-	<string name="chat_deleted">%d csevegés törölve</string>
-	<string name="prefs_sendlog">Naplófájl küldése</string>
-	<string name="prefs_sendlog_summary">Naplófájl elküldése a Threema számára a problémaelemzéshez.</string>
-	<string name="permission_storage_required">Aktiválja a mentési engedélyt a média mentéséhez vagy küldéséhez.</string>
-	<string name="permission_location_required">Aktiválja a helymeghatározási engedélyt a tartózkodási helye elküldéséhez.
-	</string>
-	<string name="permission_contacts_required">Aktiválja a kapcsolatok engedélyt egy névjegy elküldéséhez.
-	</string>
-	<string name="message_declined">Üzenet elutasítva</string>
-	<string name="notifications_settings">Értesítési beállítások</string>
-	<string name="notifications_default">Alapértelmezett beállítás</string>
-	<string name="notifications_for_x_hours">%d órára</string>
-	<string name="notifications_until">%s-ig</string>
-	<string name="notifications_mute">Néma</string>
-	<string name="notifications_choose_sound">Hang kiválasztása</string>
-	<string name="error_video_conversion">Videókonverziós hiba.</string>
-	<string name="confirm_your_pin">PIN-kód megerősítése</string>
-	<string name="too_many_incorrect_attempts">Túl sok hibás próbálkozás. Kérjük, próbálja meg újra %s másodperc múlva.</string>
-	<string name="no_lockscreen_set">Nincs beállítva a rendszer kijelzőjének zárolása.</string>
-	<string name="on">be</string>
-	<string name="off">ki</string>
-	<string name="new_wizard_select_country">Válasszon országot</string>
-	<string name="new_wizard_lets_get_started">Gyerünk!</string>
-	<string name="new_wizard_setup_threema">Beállítás</string>
-	<string name="new_wizard_restore_id_backup">Exportált ID visszaállítása</string>
-	<string name="new_wizard_welcome">Üdvözöljük a Threema-nál</string>
-	<string name="new_wizard_move_finger">Mozgassa az ujját a mezőben, hogy új Threema ID-t hozzon létre.</string>
-	<string name="new_wizard_this_is_your_id">Ez az Ön Threema ID-ja:</string>
-	<string name="new_wizard_works_like_phone_number">A Threema ID úgy működik, mint egy telefonszám. Barátai ezen az ID-n keresztül érhetik el Önt.
-	</string>
-	<string name="new_wizard_choose_nickname">Válasszon becenevet</string>
-	<string name="new_wizard_nickname_explain">A becenév megjelenik a barátainak, amikor üzenetet kapnak.</string>
-	<string name="new_wizard_hint_enter_nickname">Becenév megadása</string>
-	<string name="new_wizard_help_your_friends_find_you">Hogy az emberek könnyebben megtalálják Önt</string>
-	<string name="new_wizard_link_mobile">Csatolja össze mobilszámát és/vagy e-mail címét a Threema ID-jával.</string>
-	<string name="new_wizard_link_mobile_only">Csatolja össze mobilszámát a Threema ID-jával.</string>
-	<string name="new_wizard_hint_mobile_number">Mobilszám (nem kötelező)</string>
-	<string name="new_wizard_hint_email">Email (nem kötelező)</string>
-	<string name="new_wizard_find_friends">Találd meg barátaidat Threema-n</string>
-	<string name="new_wizard_sync_contacts_explain">Kapcsolja be, hogy lássa, mely barátai használják a Threema-t.</string>
-	<string name="new_wizard_done_title">Minden rendben?</string>
-	<string name="new_wizard_linked_to">Összecsatolva:</string>
-	<string name="new_wizard_need_internet">Az egyedi Threema ID létrehozásához stabil internetkapcsolat szükséges. Kérjük, próbálja meg újra.</string>
-	<string name="new_wizard_more_information">További információ</string>
-	<string name="new_wizard_use_id_as_nickname">Szeretné becenévként használni a Threema ID-t?</string>
-	<string name="new_wizard_phone_email_invalid">A megadott mobilszám vagy e-mail cím érvénytelen\nKérjük, a folytatás előtt javítsa ki vagy törölje a kiemelt adatokat.</string>
-	<string name="new_wizard_phone_invalid">Az Ön által megadott mobilszám érvénytelen\nKérjük, a folytatás előtt javítsa ki vagy törölje a kiemelt adatokat.</string>
-	<string name="new_wizard_info_fingerprint">Az ujjad mozgatásával véletlenszerű adatokat (úgynevezett entrópiát) generálsz, amelyekből a
+		automatikus folyamat. Csak akkor törlődik, ha megérinti az alábbi gombok egyikét.</string>
+    <string name="delete_data">Adatok törlése most</string>
+    <string name="delete_date_confirm_message">A fájlok véglegesen törlődnek, és csak a miniatűrök maradnak meg.</string>
+    <string name="media_files_deleted" tools:ignore="PluralsCandidate">%d Média/fájlok törölve.</string>
+    <string name="storage_management">Tároláskezelés</string>
+    <string name="media">Média</string>
+    <string name="prefs_storage_mgmt_title">Fájlok és üzenetek tisztítása</string>
+    <string name="num_messages">Üzenetek száma</string>
+    <string name="delete_messages_explain">A következőnél régebbi üzenetek törlése:</string>
+    <string name="delete_message">Üzenetek törlése</string>
+    <string name="really_delete_messages">Az üzenetek teljesen törlődnek, és nem állíthatók vissza.</string>
+    <string name="messages_delete_explain">A régi üzeneteket teljesen törölheti.</string>
+    <string name="backup_started">Az adatmentés elindult</string>
+    <string name="invalid_data">Érvénytelen adat. Küldés nem lehetséges.</string>
+    <string name="prefs_emoji_style">Emoji stílus</string>
+    <string name="prefs_android_emojis">Rendszer emojik</string>
+    <string name="prefs_default_emojis">Threema-emojik (alapértelmezett)</string>
+    <string name="android_emojis_warning">Megjegyzés: Előfordulhat, hogy a rendszer karakterkészlete nem képes
+		megjeleníteni a Threema által támogatott összes emojit.</string>
+    <string name="crop">Kivágás</string>
+    <string name="scan_id_mismatch_title">Az ID nem egyezik</string>
+    <string name="scan_id_mismatch_message">A beolvasott ID nem egyezik a mentett névjeggyel.</string>
+    <string name="title_remove_picture">Kép eltávolítása</string>
+    <string name="blocked">blokkolt</string>
+    <string name="name">Név</string>
+    <string name="privacy_policy">Adatvédelmi szabályzat</string>
+    <string name="terms_of_service">Általános Szerződési Feltételek</string>
+    <string name="save_group_changes">Szeretné a csoportra alkalmazni a módosításokat?</string>
+    <string name="prefs_title_fontsize">Betűméret</string>
+    <string name="fontsize_normal">Normál</string>
+    <string name="fontsize_large">Nagy</string>
+    <string name="fontsize_xlarge">Nagyon nagy</string>
+    <string name="no_app_for_location">Ezen a készüléken nem található térképalkalmazás.</string>
+    <string name="chat_deleted" tools:ignore="PluralsCandidate">%d csevegés törölve</string>
+    <string name="prefs_sendlog">Naplófájl küldése</string>
+    <string name="prefs_sendlog_summary">Naplófájl elküldése a Threema számára a problémaelemzéshez.</string>
+    <string name="permission_storage_required">Aktiválja a mentési engedélyt a média mentéséhez vagy küldéséhez.</string>
+    <string name="permission_location_required">Aktiválja a helymeghatározási engedélyt a tartózkodási helye elküldéséhez.</string>
+    <string name="permission_contacts_required">Aktiválja a kapcsolatok engedélyt egy névjegy elküldéséhez.</string>
+    <string name="message_declined">Üzenet elutasítva</string>
+    <string name="notifications_settings">Értesítési beállítások</string>
+    <string name="notifications_default">Alapértelmezett beállítás</string>
+    <string name="notifications_for_x_hours" tools:ignore="PluralsCandidate">%d órára</string>
+    <string name="notifications_until">%s-ig</string>
+    <string name="notifications_mute">Néma</string>
+    <string name="notifications_choose_sound">Hang kiválasztása</string>
+    <string name="error_video_conversion">Videókonverziós hiba.</string>
+    <string name="confirm_your_pin">PIN-kód megerősítése</string>
+    <string name="too_many_incorrect_attempts">Túl sok hibás próbálkozás. Kérjük, próbálja meg újra %s másodperc múlva.</string>
+    <string name="no_lockscreen_set">Nincs beállítva a rendszer kijelzőjének zárolása.</string>
+    <string name="on">be</string>
+    <string name="off">ki</string>
+    <string name="new_wizard_select_country">Válasszon országot</string>
+    <string name="new_wizard_lets_get_started">Gyerünk!</string>
+    <string name="new_wizard_setup_threema">Beállítás</string>
+    <string name="new_wizard_restore_id_backup">Exportált ID visszaállítása</string>
+    <string name="new_wizard_welcome">Üdvözöljük a Threema-nál</string>
+    <string name="new_wizard_move_finger">Mozgassa az ujját a mezőben, hogy új Threema ID-t hozzon létre.</string>
+    <string name="new_wizard_this_is_your_id">Ez az Ön Threema ID-ja:</string>
+    <string name="new_wizard_works_like_phone_number">A Threema ID úgy működik, mint egy telefonszám. Barátai ezen az ID-n keresztül érhetik el Önt.</string>
+    <string name="new_wizard_choose_nickname">Válasszon becenevet</string>
+    <string name="new_wizard_nickname_explain">A becenév megjelenik a barátainak, amikor üzenetet kapnak.</string>
+    <string name="new_wizard_hint_enter_nickname">Becenév megadása</string>
+    <string name="new_wizard_help_your_friends_find_you">Hogy az emberek könnyebben megtalálják Önt</string>
+    <string name="new_wizard_link_mobile">Csatolja össze mobilszámát és/vagy e-mail címét a Threema ID-jával.</string>
+    <string name="new_wizard_link_mobile_only">Csatolja \u00f6ssze mobilsz\u00e1m\u00e1t a Threema ID-j\u00e1val.</string>
+    <string name="new_wizard_hint_mobile_number">Mobilszám (nem kötelező)</string>
+    <string name="new_wizard_hint_email">Email (nem kötelező)</string>
+    <string name="new_wizard_find_friends">Találd meg barátaidat Threema-n</string>
+    <string name="new_wizard_sync_contacts_explain">Kapcsolja be, hogy lássa, mely barátai használják a Threema-t.</string>
+    <string name="new_wizard_done_title">Minden rendben?</string>
+    <string name="new_wizard_linked_to">Összecsatolva:</string>
+    <string name="new_wizard_need_internet">Az egyedi Threema ID létrehozásához stabil internetkapcsolat szükséges. Kérjük, próbálja meg újra.</string>
+    <string name="new_wizard_more_information">További információ</string>
+    <string name="new_wizard_use_id_as_nickname">Szeretné becenévként használni a Threema ID-t?</string>
+    <string name="new_wizard_phone_email_invalid">A megadott mobilszám vagy e-mail cím érvénytelen\nKérjük, a folytatás előtt javítsa ki vagy törölje a kiemelt adatokat.</string>
+    <string name="new_wizard_phone_invalid">Az Ön által megadott mobilszám érvénytelen\nKérjük, a folytatás előtt javítsa ki vagy törölje a kiemelt adatokat.</string>
+    <string name="new_wizard_info_fingerprint">Az ujjad mozgatásával véletlenszerű adatokat (úgynevezett entrópiát) generálsz, amelyekből a
 		kulcspár generálódik. Ez a kulcspár az új Threema ID-hez lesz társítva.	Ez egy <b>nyilvános kulcsból</b> áll, amelyet barátaid
 		kapnak meg, és egy <b>titkos kulcsból</b>, amely a készülékeden marad! A barátaid a nyilvános kulcsot használják a neked szóló
-		üzenetek titkosítására. Csak a privát kulcs tulajdonosa és senki más nem tudja újra visszafejteni az üzeneteket.
-	</string>
-	<string name="new_wizard_info_id">A Threema ID-val létrehozott egy kulcspárt. A nyilvános kulcsot elküldtük a szerverünkre.
-		A privát kulcs soha nem hagyja el a készülékét. Ez biztosítja, hogy senki más ne tudja elolvasni az üzeneteit.
-	</string>
-	<string name="new_wizard_info_sync_contacts">Ha engedélyezi ezt a beállítást, a címjegyzékből származó e-mail címek és telefonszámok
+		üzenetek titkosítására. Csak a privát kulcs tulajdonosa és senki más nem tudja újra visszafejteni az üzeneteket.</string>
+    <string name="new_wizard_info_id">A Threema ID-val létrehozott egy kulcspárt. A nyilvános kulcsot elküldtük a szerverünkre.
+		A privát kulcs soha nem hagyja el a készülékét. Ez biztosítja, hogy senki más ne tudja elolvasni az üzeneteit.</string>
+    <string name="new_wizard_info_sync_contacts">Ha engedélyezi ezt a beállítást, a címjegyzékből származó e-mail címek és telefonszámok
 		egyirányú titkosításra (hash-elve) kerülnek, mielőtt elküldjük őket a kiszolgálónak a kapcsolattartás céljából.
 		Nem tárolunk semmilyen címjegyzékadatot.</string>
-	<string name="new_wizard_info_link">Ha megadja saját mobilszámát és/vagy e-mail címét, a Threema segítségével barátai automatikusan
+    <string name="new_wizard_info_link">Ha megadja saját mobilszámát és/vagy e-mail címét, a Threema segítségével barátai automatikusan
 		megtalálják Önt, ha szerepel a címjegyzékükben. Az információkat egyirányú titkosítással (hash-elve) tároljuk a szerverünkön.
-		Ha névtelenül szeretné használni a Threemát, akkor ezt a lépést egyszerűen kihagyhatja.
-	</string>
-	<string name="new_wizard_info_link_phone_only">Ha megadja a saját mobilszámát, a Threema segítségével barátai automatikusan
+		Ha névtelenül szeretné használni a Threemát, akkor ezt a lépést egyszerűen kihagyhatja.</string>
+    <string name="new_wizard_info_link_phone_only">Ha megadja a saját mobilszámát, a Threema segítségével barátai automatikusan
 		megtalálják önt, ha benne vagy a címjegyzékükben. A számot egyirányú titkosítással (hash-elve) tároljuk a szerverünkön.
-		Ha névtelenül szeretné használni a Threemát, akkor ezt a lépést egyszerűen kihagyhatja.
-	</string>
-	<string name="new_wizard_info_nickname">A becenév egyes eszközökön megjelenik az értesítésekben, és további azonosító jelként
+		Ha névtelenül szeretné használni a Threemát, akkor ezt a lépést egyszerűen kihagyhatja.</string>
+    <string name="new_wizard_info_nickname">A becenév egyes eszközökön megjelenik az értesítésekben, és további azonosító jelként
 		szolgál a névjegyzékben azon csevegőpartnerek számára, akik nem szerepelnek a névjegyzékben. Javasoljuk, hogy csak keresztnevet
-		vagy álnevet használjon. Ha nem állít be becenevet, a Threema ID lesz használva.
-	</string>
-	<string name="new_wizard_anonymous_confirm">Nem adtál meg mobiltelefonszámot vagy e-mail címet összecsatoláshoz. Ezért nem fog automatikusan szerepelni a barátai névjegyzékében. Tényleg teljesen anonim módon szeretné használni a Threemát?</string>
-	<string name="new_wizard_anonymous_confirm_phone_only">Ön nem adott meg mobiltelefonszámot összecsatoláshoz. Ezért nem fog automatikusan szerepelni a barátai névjegyzékében. Tényleg teljesen anonim módon szeretné használni a Threemát?</string>
-	<string name="not_linked">nem összecsatolt</string>
-	<string name="linked">összecsatolt</string>
-	<string name="pending_sms_verification_notice">A mobilszámodat még nem ellenőriztük.</string>
-	<string name="no_sms_received">Nem kapott SMS-t?</string>
-	<string name="really_cancel_verify">Tényleg megszakítod a mobilszámod hitelesítését? Ha megszakítod az ellenőrzést, a mobilszám nem lesz összecsatolva.</string>
-	<string name="verification_of">%s ellenőrzése</string>
-	<string name="status_ballot_voting_changed">Új szavazat érkezett a «%1$s» szavazásra</string>
-	<string name="status_ballot_user_first_vote">«%1$s» szavazott «%2$s» mellett</string>
-	<string name="status_ballot_user_modified_vote">«%1$s» megváltoztatta szavazatát «%2$s»-hoz</string>
-	<string name="status_ballot_all_votes">Szavazás «%1$s» befejeződött</string>
-	<string name="restore">Visszaállítás</string>
-	<string name="new_wizard_scan_id_backup">Vagy szkennelje be az ID export QR-kódját.</string>
-	<string name="error_saving_file">Hiba mentés közben. Nincs engedélye?</string>
-	<string name="state_dec">visszautasítva</string>
-	<string name="wait_one_minute">Kérjük, várjon legalább 10 percet az SMS-re, mielőtt visszahívást kérne.</string>
-	<string name="backup_id">ID export</string>
-	<string name="backup_data">Adatmentés</string>
-	<string name="really_leave_group_admin_message">Ön ennek a csoportnak az adminisztrátora. Ha most elhagyja, akkor elárvul. A többi tag folytathatja a csevegést, de módosítások már nem lehetségesek.</string>
-	<string name="action_delete_group">Csoport törlése</string>
-	<string name="delete_my_group_message">Teljesen törölni szeretné ezt a csoportot? Minden üzenet törlésre kerül, és a megmaradt tagok többé nem használhatják a csoportot.</string>
-	<string name="error_out_of_memory">Túl kevés a szabad memória a művelet végrehajtásához</string>
-	<string name="configure">Beállítás</string>
-	<string name="file_is_not_audio">Nincs hangfájl</string>
-	<string name="disabled_by_policy">Egyes beállításokat a rendszergazda letiltott</string>
-	<string name="select_all">Minden kiválasztása</string>
-	<string name="deleting_messages">Az üzenetek törlődnek</string>
-	<string name="media_gallery_files">Fájlok</string>
-	<string name="prefs_gif_autoplay">Anim GIF-ek automatikus lejátszása</string>
-	<string name="media_gallery_audio">Hangüzenetek</string>
-	<string name="action_clone_group">Csoport klónozása</string>
-	<string name="clone_group_message">Az aktuális csoport másolata jön létre Önnel mint rendszergazdával. Folytatja?</string>
-	<string name="prefs_proximity_sensor">Közelségérzékelő használata</string>
-	<string name="prefs_proximity_sensor_explain">Hangüzeneteket a fülhallgatón keresztül visszajátszani, ha a közelségérzékelő le van fedve</string>
-	<string name="error_creating_group">Hiba a csoport létrehozásában/frissítésében</string>
-	<string name="no_media_found_generic">Nem találtunk médiát</string>
-	<string name="max_images_reached">Egyszerre nem lehet több mint %d képet szerkeszteni</string>
-	<string name="enter_description">Kérjük, írja le a problémát vagy hibát.</string>
-	<string name="add_caption_hint">Felirat hozzáadása</string>
-	<string name="disable">Kikapcsolás</string>
-	<string name="continue_anyway">Folytassa</string>
-	<string name="invalid_input">Érvénytelen bevitel</string>
-	<string name="already_licensed">Már engedélyezett</string>
-	<string name="hide_chat">Privát csevegések</string>
-	<string name="really_hide_chat_message">Tényleg magánbeszélgetésnek akarod jelölni ezt a csevegést? A privát beszélgetések elrejtéséhez vagy újra láthatóvá tételéhez használja a funkciót a menüben.</string>
-	<string name="chat_hidden">A csevegés privátként jelölése</string>
-	<string name="title_show_private_chats">Privát csevegések megjelenítése</string>
-	<string name="title_hide_private_chats">Privát csevegések elrejtése</string>
-	<string name="chat_visible">A chat mostantól mindig látható</string>
-	<string name="prefs_title_locking_mechanism">Védelmi mechanizmus</string>
-	<string name="lock_option_none">Nincs</string>
-	<string name="lock_option_pin">PIN-kód</string>
-	<string name="lock_option_screenlock">Rendszer-zárolás</string>
-	<string name="hide_chat_message_explain">Bizonyos csevegésekhez való hozzáférést PIN-kóddal védheti, és átmenetileg elrejtheti a csevegéseket a csevegési listában. A funkció használatához először állítson be egy hozzáférési védelmet.</string>
-	<string name="set_lock">Aktiválás</string>
-	<string name="prefs_title_access_protection">Hozzáférésvédelem</string>
-	<string name="private_chat_subject">Privát</string>
-	<string name="grace_thirty_seconds">30 másodperc</string>
-	<string name="grace_one_minute">1 perc</string>
-	<string name="grace_two_minutes">2 perc</string>
-	<string name="grace_five_minutes">5 perc</string>
-	<string name="grace_ten_minutes">10 perc</string>
-	<string name="grace_thirty_minutes">30 perc</string>
-	<string name="grace_never">Soha (kézi)</string>
-	<string name="never">Soha</string>
-	<string name="unhide_chats_confirm">Ha eltávolítja a hozzáférés-védelmet, a privát beszélgetések ismét láthatóvá válnak.</string>
-	<string name="verification_started">Ellenőrzés elkezdve</string>
-	<string name="cannot_open_file">A fájlt nem lehetett megnyitni </string>
-	<string name="prefs_title_image_attach_previews">Média gyorsválasztó</string>
-	<string name="prefs_sum_image_attach_previews">A legújabb képek listájának megjelenítése a Hozzáadás ablakban</string>
-	<string name="prefs_title_direct_share">Közvetlen megosztás</string>
-	<string name="prefs_sum_direct_share">Legutóbbi beszélgetések megjelenítése más alkalmazásokból történő megosztáskor</string>
-	<string name="restore_disable_energy_saving">A folytatás előtt csatlakoztassa készülékét a töltőhöz. Győződjön meg róla, hogy a telefon összes energiatakarékos üzemmódja ki van kapcsolva, hogy a biztonsági mentés/visszaállítás ne szakadjon meg.</string>
-	<string name="draft">Vázlat</string>
-	<string name="prefs_bigger_single_emojis">Önálló emojik nagyítása</string>
-	<string name="wizard1_sync_work">Szinkronizálás folyamatban…</string>
-	<string name="notification_hidden_text">Tartalom elrejtve</string>
-	<string name="really_reset_ringtones">Értesítési hangok visszaállítása a gyári beállításokra?</string>
-	<string name="reset_ringtones_confirm">Értesítési hangok visszaállítva</string>
-	<string name="prefs_title_reset_ringtones">Értesítési hangok visszaállítása</string>
-	<string name="prefs_sum_reset_ringtones">Gyári beállítások visszaállítása</string>
-	<string name="prefs_language_override">Nyelv</string>
-	<string name="threema_channel_intro">A Threema Channel a Threema-ról szóló hírekkel látja el Önt. Szeretne feliratkozni a
-		Threema Channelre és hozzáadni a névjegyzékbe? Ingyenes, és bármikor leiratkozhatsz róla.
-	</string>
-	<string name="quote">Idéz</string>
-	<string name="really_delete_contacts_message">Biztosan törölni szeretne %1$d névjegyet és az összes kapcsolódó csevegést?</string>
-	<string name="contacts_deleted">A névjegyek törölve lettek</string>
-	<string name="some_contacts_not_deleted">%d névjegyet nem lehetett törölni, mert még mindig egy csoportban vannak.</string>
-	<string name="take_photo">Fotózás</string>
-	<string name="select_from_gallery">Galériából választás</string>
-	<string name="palette">Paletta</string>
-	<string name="stickers">Matricák</string>
-	<string name="text">Szöveg</string>
-	<string name="undo">Vissza</string>
-	<string name="android_backup_date">Utolsó biztonsági mentés</string>
-	<string name="check_now">Ellenőrzés</string>
-	<string name="discard">Eldob</string>
-	<string name="android_backup_restart_threema">Kérem, várjon. Az alkalmazás hamarosan újraindul.</string>
-	<string name="battery_optimizations_title">Az akkumulátoroptimalizálás letiltása</string>
-	<string name="battery_optimizations_explain">Az akkumulátorteljesítmény optimalizálása megakadályozza, hogy a %1$s megfelelően működjön, amikor a telefon alvó üzemmódba kapcsol. Kérjük, tiltsa le az optimalizálást %2$s számára.</string>
-	<string name="battery_optimizations_disable_guide">A legördülő menüben válassza az «Összes alkalmazás»-t</string>
-	<string name="battery_optimizations_disable_guide_ctd">Keresse a %s-t a listában és kikapcsolja ki az optimalizálást</string>
-	<string name="battery_optimizations_disable_confirm">Tényleg engedélyezve akarja hagyni az akkumulátor teljesítményének optimalizálását %1$s esetében? Ezáltal a %2$s használhatatlanná válhat.</string>
-	<string name="enter_text_hint">Írja be</string>
-	<string name="backup_explain_text">Ha lecseréli vagy elveszíti a készülékét, senki sem tudja visszaállítani a Threema azonosítóját és a csevegéseket biztonsági mentés nélkül. Ezért készítsen biztonsági másolatot az adatokról a rendelkezésre álló biztonsági mentési lehetőségekkel.</string>
-	<string name="data_backup_explain">Az adatmentés a következőket menti:\n\n&#9679; ID és kulcspár\n&#9679; névjegyzék és bizalmi státusz\n&#9679; csoporttagságok\n&#9679; csevegések\n&#9679; médiák és fájlok (opcionális)\n\nAz adatok titkosított ZIP-ben kerülnek mentésre. A biztonsági másolatot ezután a készüléken kívül, megfelelő helyen kell tárolni.</string>
-	<string name="draw">Rajzolás</string>
-	<string name="edit">Szerkesztés</string>
-	<string name="discard_changes">El akarja vetni a változtatásokat?</string>
-	<string name="prefs_title_network">Hálózat</string>
-	<string name="prefs_title_ipv6_preferred">IPv6 üzenetekhez</string>
-	<string name="prefs_ipv6_preferred_off">Csak IPv4 kapcsolatokat használjon</string>
-	<string name="prefs_ipv6_preferred_on">IPv6 előnyben részesítése</string>
-	<string name="prefs_title_ipv6_webrtc_allowed">IPv6 hívásokhoz és webhez</string>
-	<string name="prefs_ipv6_webrtc_allowed_on">IPv6 engedélyezése a Threema-hívásokhoz és a Threema Webhez</string>
-	<string name="prefs_ipv6_webrtc_allowed_off">Ne használja az IPv6-ot a Threema-hívásokhoz és a Threema Webhez.</string>
-	<string name="ipv6_requires_restart">Ez a módosítás az alkalmazás újraindítását igényli.</string>
-	<string name="ipv6_restart_now">Újraindítás most</string>
-	<string name="on_cap">Be</string>
-	<string name="off_cap">Ki</string>
-	<string name="share_chat">Csevegés megosztása</string>
-	<string name="flip">Tükrözés</string>
-	<string name="to_front">Előre</string>
-	<string name="play">Lejátszás</string>
-	<string name="pause">Szünet</string>
-	<string name="retry">Ismét</string>
-	<string name="voice_message_record">Hangüzenet felvétele</string>
-	<string name="open_navdrawer">Oldalmenü megnyitása</string>
-	<string name="profile_picture">Profilkép</string>
-	<string name="profile_picture_release">Ki láthatja a profilképét?</string>
-	<string name="picrelease_nobody">Senki</string>
-	<string name="picrelease_selected">Kiválasztott névjegyek</string>
-	<string name="picrelease_everyone">Mindenki, akinek írsz</string>
-	<string name="prefs_title_receive_profilepics">Profilképek megjelenítése</string>
-	<string name="prefs_sum_receive_profilepics_off">A névjegyek profilképeinek elrejtése</string>
-	<string name="prefs_sum_receive_profilepics_on">A névjegyek profilképeinek megjelenítése</string>
-	<string name="prefs_sum_receive_profilepics_recipients_list">Az ebben a listában kiválasztott névjegyek megkapják a profilképét, amikor ír nekik.</string>
-	<string name="menu_send_profilpic">Profilkép címzett hozzáadás</string>
-	<string name="menu_send_profilpic_off">Profilkép címzett eltávolítás</string>
-	<string name="menu_send_profilpic_now">Profilkép küldése most</string>
-	<string name="profile_picture_sent">A profilkép elküldve</string>
-	<string name="sending_messages">Küldés…</string>
-	<string name="backup_data_media_confirm">A nagyméretű médiafájlok ZIP biztonsági mentése hosszú időt vehet igénybe, és meghaladhatja a készülék processzor- és memóriakapacitását. A biztonsági mentés során nem fogadhatók Threema üzenetek. Biztos, hogy folytatni akarod?</string>
-	<string name="backup_data_cancelled">A biztonsági mentés leállítása</string>
-	<string name="service_manager_not_available">Az alkalmazás nem indítható. Kérjük, kapcsolja ki teljesen a készüléket, majd kapcsolja be újra.</string>
-	<string name="edit_name_only">Névváltoztatás</string>
-	<string name="message_sent">Üzenetet elküldve</string>
-	<string name="threema_call">Threema hívás</string>
-	<string name="threema_call_with">%s hívása</string>
-	<string name="threema_message_to">Üzenet %s-nek</string>
-	<string name="permission_record_audio_required">Engedélyezze a mikrofon használatát titkosított Threema-hívások kezdeményezéséhez és hangüzenetek rögzítéséhez.</string>
-	<string name="prefs_voice_call_notifications">Hanghívások</string>
-	<string name="prefs_voice_call_sound">Csengőhang</string>
-	<string name="prefs_sum_voice_call_sound">Csengőhang kiválasztása Threema hanghívásokhoz</string>
-	<string name="prefs_sum_voice_call_vibrate">Rezgés a bejövő Threema hanghívásoknál</string>
-	<string name="prefs_title_voip">Threema hívások</string>
-	<string name="prefs_title_force_turn">Hívások mindig a szerveren keresztül</string>
-	<string name="prefs_summary_force_turn_off">Ha lehetséges, használjon közvetlen kapcsolatot, és csak nem ellenőrzött névjegyek hívásait irányítsa a Threema szerverein keresztül. Feltárhatja az IP-címét.</string>
-	<string name="prefs_summary_force_turn_on">Minden hívást a Threema szervereken keresztül irányít. Védi az IP-címet, de rosszabb hívásminőséget eredményezhet.</string>
-	<string name="prefs_title_voip_enable">Threema-hívások engedélyezése</string>
-	<string name="webclient_invalid_push_token_message">Kézi indítás szükséges</string>
-	<string name="threema_work_contact">Threema Work névjegy</string>
-	<string name="permission_phone_required">A Threema-hívás közbeni hívások kezeléséhez kapcsolja be ezt az engedélyt.</string>
-	<string name="strikethrough">Áthúzott</string>
-	<string name="italic">Kurzív</string>
-	<string name="bold">Vastag</string>
-	<string name="shortcut_choice_title">Parancsikon készítése…</string>
-	<string name="prefs_title_device_info">Eszköz információ</string>
-	<string name="notifications_disabled_title">Értesítések letiltva</string>
-	<string name="notifications_disabled_text">A Threema értesítéseit teljesen letiltották a rendszerben. Nem kap értesítést, ha új üzenetek érkeznek.</string>
-	<string name="notifications_disabled_settings">Rendszerbeállítások módosítása</string>
-	<string name="error_attaching_files">Hiba fájlok hozzáadásakor.</string>
-	<string name="prefs_fix_powermanager_problems">A háttérben való futás engedélyezése</string>
-	<string name="prefs_fix_powermanager_problems_desc">Problémák javítása a telefonon, amelyek megakadályozzák, hogy a Threema a háttérben fusson és üzeneteket fogadjon</string>
-	<string name="disable_powermanager_explain">A következő képernyőn győződjön meg arról, hogy a «%s» védve van mindenféle korlátozás alól, és aktív lehet a háttérben. Kattintson a vissza gombra, ha végzett.</string>
-	<string name="notification_priority_default">Alacsony</string>
-	<string name="notification_priority_high">Magas</string>
-	<string name="notification_priority_max">Maximum</string>
-	<string name="prefs_title_notification_priority">Prioritás</string>
-	<string name="pin">Feltűzni</string>
-	<string name="unpin">Levenni</string>
-	<string name="location_services_disabled">A helymeghatározási szolgáltatások ki vannak kapcsolva. Szeretné őket most aktiválni?</string>
-	<string name="send_location">Helyszín elküldése</string>
-	<string name="unknown_address">Ismeretlen cím</string>
-	<string name="your_location">Tartózkodási helye</string>
-	<string name="network_blocked_title">Háttéradatok letiltva</string>
-	<string name="network_blocked_body">%s nem tud üzeneteket fogadni a háttérben. A háttéradatok engedélyezéséhez kattintson ide.</string>
-	<string name="reply_later">Később jelentkezem</string>
-	<string name="reply_on_my_way">Úton vagyok</string>
-	<string name="reply_thank_you">Köszönöm</string>
-	<string name="reply_youre_welcome">Szívesen</string>
-	<string name="prefs_auto_download_title">Médiák automatikus letöltése</string>
-	<string name="prefs_auto_download_wifi">WLAN-on</string>
-	<string name="prefs_auto_download_mobile">A mobilhálózatokon</string>
-	<string name="rate_intro">Hogy tetszik a Threema?</string>
-	<string name="rate_feedback_intro">Kérjük, mondja el, mit tehetnénk jobban (nem kötelező).</string>
-	<string name="rate_positive">Értékelés küldése</string>
-	<string name="rate_title">Threema értékelése</string>
-	<string name="rate_thank_you">Köszönjük értékelését!</string>
-	<string name="disabled_by_policy_short">A funkciót a rendszergazda letiltotta</string>
-	<string name="rate_forward_to_play_store">Ön is szeretne értékelni minket a Google Play-en?</string>
-	<string name="rate_error">Nem tudta elküldeni a véleményét. Kérjük, győződjön meg róla, hogy csatlakozik az internethez.</string>
-	<string name="off_unless_i_was_mentioned">Be, kivéve, ha említenek</string>
-	<string name="dnd">Ne zavarj</string>
-	<string name="minus">Mínusz</string>
-	<string name="plus">Plusz</string>
-	<string name="switched_off">Ki</string>
-	<string name="switched_on">Be</string>
-	<string name="title_tab_work_users">Threema Work felhasználók</string>
-	<string name="no_matching_work_contacts">Nem találtunk olyan Threema Work névjegyet, amelyet a rendszergazda ellenőrzött.</string>
-	<string name="all">Mind</string>
-	<string name="webclient_session_stop_all">Mind leállítása</string>
-	<string name="webclient_running_sessions">%d futó munkamenet</string>
-	<string name="passphrase_service_name">Jelszó szolgáltatás</string>
-	<string name="passphrase_service_description">Értesítés ha a jelszó feloldva</string>
-	<string name="webclient_service_description">Értesítés, ha egy webes/asztalos munkamenet aktív</string>
-	<string name="prefs_title_accept_privacy_policy">Adatvédelmi irányelvek elfogadása</string>
-	<string name="privacy_policy_explain">%1$s következetesebben védi az Ön privátszféráját, mint bármely más messenger. Nézze meg az %2$s-ot, hogy többet tudjon meg.</string>
-	<string name="privacy_policy_check_confirm">Kérjük, fogadja el az adatvédelmi nyilatkozatot, hogy használni tudja a %s-t.\n\n(Az EU 2016/679 rendelet szerinti követelmény)</string>
-	<string name="prefs_title_incognito_keyboard">Inkognitó billentyűzet kérése</string>
-	<string name="prefs_sum_incognito_keyboard">Az adatok gyűjtésének letiltása a személyre szabott javaslatokhoz (ha a billentyűzet támogatja)</string>
-	<string name="tooltip_mentions">Érintse meg a @ jelet a billentyűzeten, hogy közvetlenül megszólítson vagy megemlítsen egy kapcsolatot ebben a csoportban.</string>
-	<string name="tooltip_imagepaint">Légy kreatív! Érintse meg a varázspálcát, hogy firkáljon, vagy adjon matricákat és szöveget a képekhez elküldés előtt.</string>
-	<string name="call_ongoing">Hívás folyamatban</string>
-	<string name="ballot_received_votes">Beérkezett szavazatok: %1$d/%2$d</string>
-	<string name="quote_not_found">Idézett üzenet nem található</string>
-	<string name="ballot_secret">titkos</string>
-	<string name="password_too_short_generic">A jelszó túl rövid</string>
-	<string name="passwords_dont_match">Nem azonos</string>
-	<string name="disable_autostart_explain">A következő képernyőn kérjük, aktiválja az automatikus indítást a «%s» számára! Kattintson a "Vissza" gombra, ha végzett.</string>
-	<string name="disable_powermanager_title">Akku-korlátozások</string>
-	<string name="disable_autostart_title">Autom. indulás</string>
-	<string name="unchanged">változatlan</string>
-	<string name="preparing_threema_safe">Threema Safe előkészítése</string>
-	<string name="safe_learn_more_button">További információ</string>
-	<string name="safe_enable_explain">A Threema-nál nincs központi felhasználói fiókja. Az Ön adatai csak az adott eszközön léteznek, és így a legjobban védettek a külső hozzáféréstől.\n\nA Threema Safe rendszeresen készít titkosított, anonim biztonsági másolatot az Ön <b>kulcsairól, névjegyeiről, csoportjairól és beállításairól</b> (de az üzenetek tartalmáról nem) egy Ön által választott szerveren. Az Ön azonosítója és a kiválasztott jelszó elegendő ahhoz, hogy visszaállítsa ezeket az adatokat egy másik eszközön.</string>
-	<string name="safe_disable_confirm">A Threema Safe aktiválása nélkül szeretne folytatni? A Threema Safe lehetővé teszi a Threema ID, a névjegyek és a csoportok visszaállítását, ha elveszíti a készülékét.</string>
-	<string name="safe_configure_choose_password">Válasszon egy biztonságos jelszót. Erre a jelszóra szüksége lesz a Threema Safe biztonsági mentés visszaállításához.</string>
-	<string name="safe_configure_choose_server">Kiszolgáló kiválasztása</string>
-	<string name="safe_configure_server_explain">Threema Safe biztonsági másolatának tárolása a Threema-nál vagy az Ön által választott szerveren.</string>
-	<string name="safe_use_default_server">Alapkiszolgáló</string>
-	<string name="safe_test_server">Kiszolgáló tesztelése</string>
-	<string name="safe_advanced_options">Szakértői beállítások</string>
-	<string name="safe_enter_password">Kérjük, adja meg a Threema Safe jelszavát</string>
-	<string name="safe_threema_id">Az ön Threema ID-ja</string>
-	<string name="safe_restore_enter_id">Kérjük, adja meg a helyreállítani kívánt Threema ID-t</string>
-	<string name="safe_search_id_title">Kérjük, adja meg a Threema ID-hoz csatolt mobilszámot vagy e-mail címet.</string>
-	<string name="safe_id_lookup">Threema-ID keresése</string>
-	<string name="safe_no_id_found">Nem találtunk Threema-ID-t</string>
-	<string name="safe_no_backup_found">Nincs biztonsági mentés a kiszolgálón. Ellenőrizze az ID-t és a jelszót.</string>
-	<string name="safe_select_id">Több Threema ID-t találtunk. Válassza ki a kívánt ID-t:</string>
-	<string name="safe_backup_now">Biztonsági mentés most</string>
-	<string name="safe_enable_explain_short">Aktiválja a Threema Safe szolgáltatást a legfontosabb adatok automatikus, biztonságos és anonim mentéséhez</string>
-	<string name="safe_deleting">A Threema Safe biztonsági mentés törlődik</string>
-	<string name="safe_delete_error">Törlési hiba: %s</string>
-	<string name="safe_delete_success">A biztonsági másolat sikeresen törlődött a kiszolgálóról</string>
-	<string name="safe_error_preparing">Hiba a Threema Safe biztonsági mentés elkészítése közben</string>
-	<string name="safe_configure_choose_password_force">Állítson be egy erős jelszót, hogy a Threema Safe segítségével megvédje ID-jét. Ne felejtse el, hogy mit ír be ide!</string>
-	<string name="safe_deactivate">Threema Safe kikapcsolása</string>
-	<string name="safe_deactivate_explain">A meglévő Threema Safe biztonsági mentések visszavonhatatlanul törlődnek a kiszolgálón. Akarod folytatni?</string>
-	<string name="add_group_members">Új tag</string>
-	<string name="contact_add_confirm">Szeretné felvenni az új névjegyet «%1$s» a névjegyzékébe?</string>
-	<string name="password_bad">Nem biztonságos jelszó</string>
-	<string name="prefs_fix_background_data">Háttéradatok engedélyezése</string>
-	<string name="prefs_fix_background_data_desc">Ha engedélyezni szeretné, hogy a Threema a háttérben fogadjon üzeneteket, engedélyezze a Háttéradatok és a Korlátlan adatforgalom funkciót</string>
-	<string name="prefs_fix_device">Az eszköz konfigurációs problémáinak javítása</string>
-	<string name="safe_successful">Sikeres</string>
-	<string name="safe_unsuccessful">Sikertelen</string>
-	<string name="safe_upload_failed">A feltöltés sikertelen</string>
-	<string name="safe_upload_size_exceeded">A biztonsági mentés túlméretes</string>
-	<string name="safe_server_name">Kiszolgáló</string>
-	<string name="safe_max_backup_size">Max. biztonsági mentés méret</string>
-	<string name="safe_retention">Tárolási idő</string>
-	<string name="safe_result">Eredmény</string>
-	<string name="number_of_days">%d nap</string>
-	<string name="backup_other_restore_options">Egyéb helyreállítási lehetőségek</string>
-	<string name="safe_size">A mentés mérete</string>
-	<string name="safe_version_mismatch">A biztonsági mentés verziója magasabb az alkalmazás által támogatottnál. Kérjük, frissítse az alkalmazást.</string>
-	<string name="safe_restore_failed">A visszaállítás sikertelen</string>
-	<string name="safe_failed_notification">A Threema Safe %d napja nem tud biztonsági mentést készíteni. Kérjük, kattintson ide az ellenőrzéshez.</string>
-	<string name="safe_connection_error">Csatlakozási hiba</string>
-	<string name="test_unsuccessful">A teszt sikertelen</string>
-	<string name="safe_restore">Threema Safe visszaállítása</string>
-	<string name="backup_restore_in_progress">Biztonsági mentés vagy visszaállítás folyamatban. További információkért nézze meg az értesítést.</string>
-	<string name="restore_error_body">A visszaállítás sikertelen</string>
-	<string name="private_contact">Privát névjegy</string>
-	<string name="forgot_your_id">Elfelejtette az ID-ját?</string>
-	<string name="restore_success_body">A visszaállítás sikeresen befejeződött.</string>
-	<string name="ringtone_selection_default">Alapértelmezett (%s)</string>
-	<string name="work_data_sync">Adatok szinkronizálása</string>
-	<string name="work_data_sync_desc">Threema Work szinkronizálás</string>
-	<string name="ballot_not_connected">Kérjük, a szavazás kitöltése előtt győződjön meg arról, hogy a Threema online van.</string>
-	<string name="empty_chat_title">Csevegés kiürítése</string>
-	<string name="empty_chat_confirm">Ebben a csevegésben minden üzenet törlésre kerül. Folytassuk?</string>
-	<string name="emptying_chat">Csevegés ürítése</string>
-	<string name="set_private">«Privát csevegés»-ként jelölés</string>
-	<string name="unset_private">«Privát csevegés» kikapcsolása</string>
-	<string name="delete_group_message">Ki akarsz lépni ebből a csoportból, és teljesen törölni akarod? Minden üzenet törlődik.</string>
-	<string name="delete_left_group_message">Teljesen törölni szeretné ezt a csoportot? Minden üzenet törlődik.</string>
-	<string name="chats">Csevegések</string>
-	<string name="notification_setting_ignored">A VÁLTOZTATÁSOK FIGYELMEN KÍVÜL LESZNEK HAGYVA!</string>
-	<string name="notification_channel_alerts">Figyelmeztetések és hibaüzenetek</string>
-	<string name="notification_channel_notices">Megjegyzések</string>
-	<string name="chat_updates">Csevegés frissítések</string>
-	<string name="backup_or_restore_progress">Biztonsági mentés/visszaállítás állapota</string>
-	<string name="tooltip_export_id">Kattintson ide a titkosított Threema ID megosztásához vagy kinyomtatásához.</string>
-	<string name="downloading">Letöltés</string>
-	<string name="today">Ma</string>
-	<string name="restore_data_cancelled">Visszaállítás megszakítva</string>
-	<string name="safe_change_password">Jelszó módosítása</string>
-	<string name="safe_configure_choose_password_title">Jelszó választása</string>
-	<string name="password_bad_explain">Az Ön által választott Threema Safe jelszó nagyon gyenge, ezért a támadók könnyen kitalálhatják. Kérjük, válasszon biztonságos jelszót. Tipp: Használjon több kifejezésből álló összetett szót.</string>
-	<string name="safe_password_updated">A Threema Safe jelszó frissítve lett.</string>
-	<string name="safe_activated">A Threema Safe aktiválódott.</string>
-	<string name="restore_zip_invalid_file">A biztonsági mentési fájl érvénytelen.</string>
-	<string name="push_token_cleared">A push token eltávolításra került</string>
-	<string name="insert_date">Dátum beillesztése</string>
-	<string name="add_answer">Válasz hozzáadása</string>
-	<string name="title_cannot_be_empty">A szavazás címe nem lehet üres</string>
-	<string name="voip_disabled">Threema-hívások letiltva</string>
-	<string name="hide_chat_enter_message_explain">Ez a csevegés privátnak van jelölve. A megtekintéshez először állítson be egy hozzáférés védelmet.</string>
-	<string name="unknown">Ismeretlen</string>
-	<string name="miui_notification_title">Fontos megjegyzés a MIUI felhasználók számára</string>
-	<string name="miui_notification_body">A MIUI 10 alapértelmezetten letiltja a hangokat, a LED-et és a felugró ablakokat az újonnan létrehozott értesítési csatornákhoz (kivéve néhány, a Xiaomi által «fontosnak» tartott alkalmazás esetében). Ezért ezeket a paramétereket a telefon Threema-specifikus értesítési beállításaiban kell engedélyeznie az egyes csatornákhoz. További információért forduljon a telefon gyártójához.</string>
-	<string name="miui12_notification_body">A MIUI alapértelmezetten kikapcsolja a hangokat, a LED-et és a felugró ablakokat (kivéve néhány nagyon népszerű alkalmazást, amelyeket a Xiaomi «fontosnak» tart). Ezért sajnos manuálisan kell aktiválnia ezeket a beállításokat a telefon Threema-specifikus értesítési beállításaiban, és minden alkalmazásfrissítés után meg kell ismételnie az eljárást. További információért forduljon a telefon gyártójához.</string>
-	<string name="dont_show_again">Ne mutassa újra</string>
-	<string name="miui_notification_prefs">MIUI beállítások</string>
-	<string name="threema_safe_upload_successful">Threema-Safe biztonsági mentés sikeresen feltöltve</string>
-	<string name="time_remaining">még %s</string>
-	<string name="safe_configure_server_credentials_title">Hitelesítés (opcionális)</string>
-	<string name="username_hint">Felhasználónév</string>
-	<string name="lock_option_biometric">Biometrikus</string>
-	<string name="biometric_enter_authentication">Kérjük, hitelesítse magát a feloldáshoz</string>
-	<string name="biometric_authentication_failed">A hitelesítés sikertelen</string>
-	<string name="biometric_authentication_successful">Önt sikeresen hitelesítették</string>
-	<string name="work_safe_forced_explain">A rendszergazda engedélyezte a Threema Safe szolgáltatást az Ön készülékén.</string>
-	<string name="pin_locked_cannot_send">Alkalmazás zárolva. Küldés nem lehetséges.</string>
-	<string name="prefs_summary_hide_screenshots_notice">Adatvédelmi okokból a miniatűrök és a képernyőképek mindig le vannak tiltva, ha az alkalmazászár engedélyezve van.</string>
-	<string name="work_select_categories">Kategóriák kiválasztása</string>
-	<string name="my_profile">Profilom</string>
-	<string name="message_too_long">Az üzenet túl hosszú és nem küldhető el.</string>
-	<string name="database_migration_no_space">Az adatbázis migrációja nem lehetséges: Túl kevés a szabad hely.</string>
-	<string name="advanced_options">További lehetőségek</string>
-	<string name="url_warning_body">A megnyitni kívánt weboldal gyanús:\n\nMegjelenített hostnév: <b>%s</b>\nValódi hostnév: <b>%s</b>\n\nLehet, hogy egy hamis weboldalra próbálják átirányítani Önt.\n\nMégis folytatni akarja?</string>
-	<string name="url_warning_title">Adathalászat figyelmeztetés</string>
-	<string name="permission_camera_qr_required">A QR-kódok beolvasásához kamerához való hozzáférés szükséges</string>
-	<string name="voice_action_title">Hangparancsok</string>
-	<string name="voice_action_body">A hangparancs feldolgozása</string>
-	<string name="permission_camera_photo_required">A fénykép készítéséhez kérjük, engedélyezze a kamerához való hozzáférést.</string>
-	<string name="global_search">Csevegések böngészése</string>
-	<string name="global_search_empty_view_text">Adjon meg legalább két karaktert az üzenetekben való kereséséhez</string>
-	<string name="my_id">Az én ID-m</string>
-	<string name="profile_picture_and_nickname">Profilkép és becenév</string>
-	<string name="lp_select_this_place">Ez a helyszín kiválasztása</string>
-	<string name="lp_or_select_nearby">Vagy válasszon egy közeli helyszínt</string>
-	<string name="lp_use_this_location">Helyszín elküldése?</string>
-	<string name="lp_search_place">Helyszín megadása</string>
-	<string name="lp_no_nearby_places_found">Nem találtunk a közelben ilyen helyet</string>
-	<string name="select_directory_for_backup">Mentés ide</string>
-	<string name="data_backup_headline">Hozzon létre biztonsági mentést az összes adat, csevegés és médiáról.</string>
-	<string name="data_backup_save_path">Biztonsági mentés útvonala</string>
-	<string name="change">Módosítás</string>
-	<string name="data_backup_last_date">Utolsó sikeres biztonsági mentés</string>
-	<string name="archived">Archív</string>
-	<string name="to_archive">Archiválás</string>
-	<string name="message_archived">%d csevegés archiválva</string>
-	<string name="archived_chats">Archivált csevegések</string>
-	<string name="unarchive">Archívból törlés</string>
-	<string name="no_archived_chats">Nincsenek archivált csevegések.\nHúzzon balra egy csevegést a csevegési listában az archiválásához.</string>
-	<string name="add_contact_enter_id_hint">Kérjük, adja meg a hozzáadni kívánt kapcsolat Threema ID-ját.</string>
-	<string name="notification_channel_new_contact">Új névjegyek</string>
-	<string name="notification_channel_new_contact_desc">Értesítés új névjegyekről</string>
-	<string name="notification_contact_has_joined">%1$s most %2$s-nél van. Kattintson ide egy üzenet elküldéséhez.</string>
-	<string name="notification_contact_has_joined_multiple">%1$d kapcsolata most %2$s: %3$s-nél van. Kattintson ide egy üzenet küldéséhez.</string>
-	<string name="system_default">Rendszer alapértelmezett</string>
-	<string name="open_in_maps_app">Megnyitás a Térképalkalmazásban</string>
-	<string name="delete">Törlés</string>
-	<string name="num_archived_chats">%d archivált csevegés</string>
-	<string name="continue_recording">Felvétel folytatása</string>
-	<string name="tap_to_start">Kattintson ide a %s indításához.</string>
-	<string name="two_years">2 év</string>
-	<string name="invalid_backup_path">Érvénytelen mentési útvonal</string>
-	<string name="backup_data_no_permission">Nincs író hozzáférés ehhez a könyvtárhoz. Kérjük, válasszon egy másikat.</string>
-	<string name="prefs_sum_show_unread_badge">Jelvények megjelenítése a navigációs fülön</string>
-	<string name="prefs_title_show_unread_badge">Jelvények</string>
-	<string name="pinning_not_trusted">A tanúsítvány nem ellenőrizhető. Győződjön meg róla, hogy az «Entrust Root Certification Authority - G2» biztonsági tanúsítvány telepítve és aktiválva van a telefon tanúsítványtárolójában..</string>
-	<string name="pinning_failed">A tanúsítvány nem ellenőrizhető. Lehetséges man-in-the-middle támadás. Ha telepítve van egy reklámblokkoló, tartalomszűrő vagy tűzfal alkalmazás, mint például az "AdGuard", tiltsa le a Threema számára.</string>
-	<string name="open_myid_popup">Felugró ablak megnyitása a gyorsválasztóhoz</string>
-	<string name="logo">Logó / Görgessen a tetejére</string>
-	<string name="quote_subj_end">Idézet vége</string>
-	<string name="quote_subj">Idézet</string>
-	<string name="duration">Időtartam</string>
-	<string name="seconds">Másodperc</string>
-	<string name="minutes">Perc</string>
-	<string name="and">és</string>
-	<string name="edit_type_content_description">%1$s %2$s megjelenítése vagy szerkesztése</string>
-	<string name="group">Csoport</string>
-	<string name="send_location_privacy_policy_v4_0"><![CDATA[<p>Adatvédelmi szabályzatunk a következő változásnak megfelelően módosult:</p><p>%1$s már nem függ a Google Play és a Google Maps térkép- és OVI-adatoktól.</p>Kérjük, tekintse meg a teljes adatvédelmi szabályzatot <a href="%2$s">itt</a>.]]></string>
-	<string name="play_services_not_installed_unable_to_use_push">A szolgáltatás nincs telepítve. Nem lehet «Push»-ra váltani.</string>
-	<string name="unable_to_get_current_location">Nem tudjuk meghatározni az aktuális pozíciót.</string>
-	<string name="lp_search_place_min_chars">Kérjük, legalább 3 karaktert adjon meg a helykereséshez.</string>
-	<string name="lp_search_place_no_matches">Nincs megfelelő helyszín. Kérjük, módosítsa a keresést.</string>
-	<string name="wallpaper_default">Alapértelmezett háttérkép</string>
-	<string name="wallpaper_gallery">Galériából választ</string>
-	<string name="wallpaper_none">Nincs háttérkép</string>
-	<string name="wallpaper_threema">%s-háttérkép</string>
-	<string name="message_id">Üzenet-ID</string>
-	<string name="mime_type">MIME-Típus</string>
-	<string name="password_does_not_comply">A megadott jelszó nem felel meg az irányelveknek.</string>
-	<string name="audio_mute_due_to_focus_loss">A hangfókusz elvesztése miatt átmenetileg elnémult a hang</string>
-	<string name="restore_data_backup_explain">Az adatmentés visszaállításához először törölje Threema ID-ját a «saját profil» oldalon.\n\nAmikor az alkalmazás újraindul, válassza a «Biztonsági mentés visszaállítása», «További visszaállítási lehetőségek», «Adatmentés» lehetőséget, és a fájlkeresőben kattintson a visszaállítani kívánt adatmentésre.</string>
-	<string name="audio_focus_loss_complete">A hívás a hangfókusz teljes elvesztése miatt véget ért.</string>
-	<string name="tap_for_picture_hold_for_video">Fényképhez megérintés, videóhoz nyomva tartás</string>
-	<string name="sending_media">Médiá(k) elküldése</string>
-	<string name="permission_record_video_audio_required">Kérjük, engedélyezze a mikrofon használatát a hanggal ellátott videó rögzítéséhez</string>
-	<string name="media_files">Fájlok</string>
-	<string name="auto_download_limit_explain">A %s-nál nagyobb videók és fájlok mindig igény szerint kerülnek letöltésre</string>
-	<string name="quoted_message_deleted">Az idézett üzenet már nem elérhető</string>
-	<string name="searching">Keressük…</string>
-	<string name="prefs_work_life_balance">Ne zavarjanak</string>
-	<string name="prefs_title_working_days">Munkanapok</string>
-	<string name="prefs_working_days_sum">Válassza ki a munkanapokat</string>
-	<string name="prefs_work_time_start">Munkakezdet</string>
-	<string name="prefs_work_time_start_sum">Állítsa be a munka kezdetét</string>
-	<string name="prefs_work_time_end">Munka vége</string>
-	<string name="prefs_work_time_end_sum">Állítsa be a munka végét</string>
-	<string name="prefs_working_days_enable_title">Pihenőidő-politika</string>
-	<string name="prefs_working_days_enable_sum">Ne jelenítsen meg értesítéseket és utasítsa el a Threema hívásokat munkaidőn kívül</string>
-	<string name="work_life_dnd_active">Pihenőidő aktív</string>
-	<string name="pencil">Ceruza</string>
-	<string name="warning">Figyelmeztetés</string>
-	<string name="password_remember_warning">Ne feledje, mit ír be ide! Mivel a %s nem tárolja a jelszavakat a kiszolgálón, nem tudunk segíteni, ha elfelejtette a PIN-kódot vagy a jelszót.</string>
-	<string name="safe_backup_tap_to_restart">Kattintson a megjelenő rendszerértesítésre az alkalmazás újraindításához. Ha nem látja az értesítést, kérjük húzza le a telefonján az értesítési sávot.</string>
-	<string name="send_to_support">Küldés a Threema ügyfélszolgálatnak</string>
-	<string name="menu_legal">Jogi</string>
-	<string name="tooltip_work_hint">Ez a névjegy a Threema Work-ot használja.</string>
-	<string name="video_camera_on">Videokamera be</string>
-	<string name="video_camera_off">Videokamera ki</string>
-	<string name="permission_camera_videocall_required">Aktiválja a kamera engedélyt a videóhívásokhoz</string>
-	<string name="enable_picture_in_picture">Kép-a-képben üzemmód indítása</string>
-	<string name="call_with">%s felhívása</string>
-	<string name="picture_in_picture_disabled_in_setting">A kép a képben funkciót kikapcsolták a %s-hoz. Kérjük, aktiválja a mobiltelefon beállításaiban.</string>
-	<string name="delete_everything">Minden törlése</string>
-	<string name="prefs_title_voip_video_enable">Videóhívások engedélyezése</string>
-	<string name="video_calls">Videóhívások</string>
-	<string name="prefs_videocall_profile">Preferált képminőség</string>
-	<string name="videocall_profile_auto">Kiegyensúlyozott (ajánlott)</string>
-	<string name="videocall_profile_low_bandwidth">Alacsony adatfogyasztás</string>
-	<string name="videocall_profile_max_quality">Maximális minőség</string>
-	<string name="unable_to_play_video">A videó nem játszható le</string>
-	<string name="tooltip_voip_turn_on_camera">Kattintson ide a kamera bekapcsolásához</string>
-	<string name="prefs_videocall_profile_explain">A tényleges képminőség a hálózattól és a másik fél beállításaitól függ</string>
-	<string name="feedback">Visszajelzés</string>
-	<string name="tooltip_voip_enable_speakerphone">Kattintson ide a beszélgetés kihangosításához</string>
-	<string name="ballot_open">Nyílt szavazások</string>
-	<string name="translators">Fordítók</string>
-	<string name="credits">Köszönetnyilvánítás</string>
-	<string name="translators_thanks">Köszönet önkéntes fordítóinknak:\n%s</string>
-	<string name="ballot_window_hide">Nyílt szavazások elrejtése</string>
-	<string name="ballot_window_show">Nyílt szavazások megjelenítése</string>
-	<string name="tooltip_voip_other_party_video_on">Beszélgetőpartnere videóhívást indított. Kattintson ide a kamera bekapcsolásához is.</string>
-	<string name="tooltip_voip_other_party_video_disabled">Beszélgetőpartnere nem az aktuális alkalmazásverziót használja, vagy nem engedélyezi a videóhívásokat.</string>
-	<string name="biometrics_not_enrolled">A rendszer nem tárol biometrikus adatokat.</string>
-	<string name="biometrics_not_avilable">Biometrikus hitelesítés nem áll rendelkezésre.</string>
-	<string name="biometrics_no_permission">Nincs felhatalmazás a biometrikus adatokhoz való hozzáférésre.</string>
-	<string name="verification_settings_desc">A pontok a kapcsolat bizalmi szintjét jelzik.</string>
-	<string name="verification_levels_title">Bizalmi szintek</string>
-	<string name="work_verification_levels_title">Névjegyek az Ön szervezetében</string>
-	<string name="external_verification_levels_title">Egyéb névjegyek</string>
-	<string name="switch_flash">Vakumód váltása</string>
-	<string name="message_not_found">Az üzenet nem található</string>
-	<string name="insert_datetime">Dátum és idő beillesztése</string>
-	<string name="prefs_sum_disable_smart_replies">Válaszjavaslatok letiltása az Android értesítésekben</string>
-	<string name="prefs_title_disable_smart_replies">Válaszjavaslatok letiltása</string>
-	<string name="attach_gallery">Galéria</string>
-	<string name="selected_media">Az Ön választása</string>
-	<string name="attach_gif">Gif</string>
-	<string name="filter_by_album">Szűrés média album szerint</string>
-	<string name="media_date_taken">Felvétel dátuma: %s</string>
-	<string name="media_date_added">Hozzáadás dátuma: %s</string>
-	<string name="media_date_modified">Módosítás dátuma: %s</string>
-	<string name="media_date_unknown">Ismeretlen dátum</string>
-	<string name="url_warning_body_alt">A weboldal, amelyet megnyitni próbál, gyanús.\n\nLehet, hogy egy hamis weboldalra próbálják átirányítani Önt.\n\nMégis folytatni szeretné?</string>
-	<string name="read_on">Bővebben…</string>
-	<string name="forward_text">Szöveg továbbítása</string>
-	<string name="an_error_occurred_during_send">Hiba történt egy vagy több üzenet küldése közben.</string>
-	<string name="state_processing">feldolgozás alatt</string>
-	<string name="passphrase_locked">A jelszó blokkolva van</string>
-	<string name="error_unable_loading_media_thumb">Az előnézet nem tölthető be</string>
-	<string name="select">Kiválaszt</string>
-	<string name="filter_list">Lista szűrése</string>
-	<string name="hint_filter_list">Szűrő kifejezés megadása</string>
-	<string name="add">Hozzáadás</string>
-	<string name="threema_message_from">Üzenet %s-től</string>
-	<string name="show_text">Szöveg megjelenítése</string>
-	<string name="only_images_or_videos">Csak képek és videók választhatók ki</string>
-	<string name="media_gallery_gifs">GIF-ek</string>
-	<string name="no_media_found_global">Nem találtunk médiát ezen az eszközön</string>
-	<string name="enable_formatting">Formázás engedélyezése</string>
-	<string name="original_file_no_longer_avilable">Nincs többé hozzáférés az eredeti fájlhoz. Kérjük, küldje el újra ezt az üzenetet.</string>
-	<string name="state_transcoding">átkódolás alatt</string>
-	<string name="importing_files">Fájlok importálása folyamatban</string>
-	<string name="tooltip_image_resolution_hint">A képfelbontás testreszabásához kattintson ide.</string>
-	<string name="max_selectable_media_exceeded">Egyszerre legfeljebb %d objektum küldhető.</string>
-	<string name="ballot_created_successfully">A szavazás sikeresen elkészült.</string>
-	<string name="file_size">Fájlméret</string>
-	<string name="thirty_days_abbrev">30n</string>
-	<string name="show_in_chat">Megjelenítés a csevegésben</string>
-	<string name="group_create_no_members">Biztos, hogy üres csoportot szeretne létrehozni?</string>
-	<string name="notes">Megjegyzések</string>
-	<string name="blur_faces">Arcok elmosása</string>
-	<string name="brush">Ecset</string>
-	<string name="error_detecting_faces">Hiba történt az arcfelismerés során</string>
-	<string name="no_faces_detected">Nem találtunk arcokat</string>
-	<string name="smiley">Smiley</string>
-	<string name="blur">Elmosás</string>
-	<string name="face_blur_tooltip_title">Új: Arcfelismerés</string>
-	<string name="face_blur_tooltip_text">Keress arcokat a képen, és homályosítsd el őket, vagy fedd le egy smileyval.</string>
-	<string name="listened_to">meghallgatva</string>
-	<string name="transcoder_unsupported_audio_format">A hangformátum konvertálása a rendszer támogatásának hiánya miatt nem sikerült.</string>
-	<string name="transcoder_unknown_audio_error">A hangformátum konvertálása ismeretlen hibával megszakadt.</string>
-	<string name="video_size_explain">A nagyon nagyméretű videók tömörítésre kerülnek, így ettől a beállítástól függetlenül elküldhetők.</string>
-	<string name="status_create_notes">*Egyedül vagy itt*\nEzt a csevegést biztonságos jegyzetfüzetként használhatod szövegek, médiaanyagok és dokumentumok számára.</string>
-	<string name="status_create_notes_off">*Nem vagy többé egyedül ebben a csevegésben*\nAz új üzeneteket a csoport minden tagjának elküldjük.</string>
-	<string name="note_group_howto">Tipp: Ha nem ad hozzá tagokat, a csoportba küldött üzenetek helyben maradnak. Ez ideális jegyzetek, médiatartalmak vagy dokumentumok biztonságos tárolására vagy az asztalra történő átvitelére.</string>
-	<string name="mark_unread">Olvasatlannak jelölni</string>
-	<string name="mark_read_short">Olvasva</string>
-	<string name="unread">Olvasatlan</string>
-	<string name="missing_app_licence">Az App Store nem tudta ellenőrizni az alkalmazás licencét. Ha a Google Play alkalmazást használja, törölje a Google Play Store alkalmazás adatait, és indítsa újra a telefonját.</string>
-	<string name="set_backup_path">Biztonsági mentés helyének beállítása</string>
-	<string name="set_backup_path_intro">A következő képernyőn válassza ki azt a mappát, ahová az adatmentéseket tenni kívánja.</string>
-	<string name="discard_changes_title">Változások elvetése</string>
-	<string name="group_join_request_message_info"><![CDATA[Írjon egy rövid üzenetet <b>%1$s</b> adminnak, hogy miért szeretne csatlakozni az <b>%2$s</b>-hoz.]]></string>
-	<string name="group_join_request">Csoportkérelem</string>
-	<string name="group_join_request_for">Csoportkérelem %s számára</string>
-	<string name="group_link_default_name">Ismeretlen link</string>
-	<string name="group_link_share">Csoport link megosztása</string>
-	<string name="group_request_incoming_dialog_title">Kérelem %s-tól</string>
-	<string name="accept">Elfogad</string>
-	<string name="reject">Elutasít</string>
-	<string name="group_request_already_sent"><![CDATA[Már van egy nyitott kérelme <b>%s</b> számára, és a csoportadminisztrátor válaszára vár. Kattintson a listában a kérelemre, ha újra el szeretné küldeni a kérelmet.]]></string>
-	<string name="group_link_none">Még nem generált linket</string>
-	<string name="group_request_confirm_send"><![CDATA[Csoportkérelmet készül küldeni <b>%1$s</b> számára <b>%2$s</b> adminisztrátornak. Ha ez a link időközben nem lett érvénytelenítve, akkor Önt hozzáadjuk a csoporthoz, amint az admin eszköze elérhetővé válik.]]></string>
-	<string name="really_delete_outgoing_request">Tényleg törölni akar %d csoportkérelmet? Ne feledje, hogy a nyitott kérelmet nem vonják vissza, és később is felvehetik a csoportba.</string>
-	<string name="really_delete_group_request_title">Tényleg törölné a csoportkérelmet?</string>
-	<string name="sent_to">Ide küldve: %s</string>
-	<string name="sent_on">Elküldve: %s</string>
-	<string name="group_response">Válasz a csoportkérelemre</string>
-	<string name="group_response_accepted">A %s csoportra vonatkozó kérelmét elfogadták.</string>
-	<string name="group_response_full">A %s csoportra vonatkozó kérelmét elutasították, mivel a csoport már megtelt.</string>
-	<string name="group_response_rejected">A %s csoportra vonatkozó kérelmét elutasították.</string>
-	<string name="group_link_expiration_none">Korlátlan</string>
-	<string name="group_request_hint">Szia, én vagyok…</string>
-	<string name="group_request_send_title">Csoportkérelem küldése</string>
-	<string name="group_request_message_empty">Az adminisztrátornak küldött üzenet nem lehet üres!</string>
-	<string name="group_requests_all_title">Összes csoportkérelem</string>
-	<string name="group_requests_none_outgoing">Nem küldött csoportkérelmet. A kérelmeket csoporthivatkozásokon keresztül lehet elküldeni.</string>
-	<string name="notification_channel_group_join_response">Értesítés a csoportkérelmekre adott válaszokról</string>
-	<string name="group_qr_code_title">Csoport QR-kód</string>
-	<string name="group_link_qr_desc"><![CDATA[Ossza meg ezt a linket azokkal, akiket szeretne meghívni az <b>%s</b> csoportba.]]></string>
-	<string name="new_group_link_success">Új link hozzáadva</string>
-	<string name="link_administration_off_explain">Ezt a linket már megosztották, és nyilvános. Az adminisztráció utólag nem módosítható. Egyszerűen hozzon létre egy új linket a kívánt opcióval.</string>
-	<string name="group_link_update_success">Link frissítés sikeres</string>
-	<string name="no_group_links">Nincsenek csoporthivatkozások. Csoporthivatkozások létrehozásához kattintson a "Link létrehozása" gombra, vagy aktiválja az alapértelmezett linket a csoport áttekintésében.</string>
-	<string name="really_delete_group_link">Tényleg törölni szeretne %d csoporthivatkozást? A törlés után a felhasználók már nem küldhetnek érvényes kérelmeket. A már beérkezett kérelmeket azonban továbbra is el lehet fogadni vagy el lehet utasítani.</string>
-	<string name="group_links_overview_title">Csoporthivatkozások %s számára</string>
-	<string name="group_link_invalid">Lejárt</string>
-	<string name="group_link_valid">Érvényes</string>
-	<string name="open_group_requests_chips_title">Nyitott csoportkérelmek</string>
-	<string name="all_open_group_requests">Összes csoportkérelem</string>
-	<string name="no_incoming_group_requests">Még nincsenek bejövő csoportkérelmek. Ezeket csoporthivatkozásokként küldhetik el Önnek, amelyeket a csoport adatainak nézetében kezelhet, ha Ön az adminisztrátor.</string>
-	<string name="received_on">Beérkezett %s-kor</string>
-	<string name="group_request_state_full">Csoport teli</string>
-	<string name="group_request_state_rejected">Visszautasítva</string>
-	<string name="group_request_state_expired">Lejárt</string>
-	<string name="group_request_state_pending">Függőben</string>
-	<string name="group_request_state_accepted">Elfogadva</string>
-	<string name="open_group_requests_show">Csoportkérelmek mutatása</string>
-	<string name="open_group_requests_hide">Csoportkérelmek elrejtése</string>
-	<string name="group_request_link_already_deleted">Csoporthivatkozás már törölve</string>
-	<string name="really_delete_incoming_request">Tényleg törölni akar %d csoportkérelmeket? A törlés után többé nem tudsz válaszolni rájuk.</string>
-	<string name="incoming_group_request_no_message">Nyitott hivatkozáson keresztül küldték… Nincs üzenet</string>
-	<string name="group_request_received_through">Hivatkozáson keresztül: %s</string>
-	<string name="reaccept">Újra elfogad</string>
-	<string name="group_link_edit_expiration_date">Lejárati idő megadása</string>
-	<string name="group_link_show_qr">QR-kód megjelenítése</string>
-	<string name="group_link_rename">Hivatkozás átnevezése</string>
-	<string name="group_link_rename_tag">Új név</string>
-	<string name="tap_here_for_more">További információért kattintson ide</string>
-	<string name="another_connection_instructions">A kiszolgáló két vagy több különböző eszközről származó, azonos Threema ID-vel rendelkező kapcsolatot észlelt.\n\nEgy Threema ID-t nem lehet egyszerre több eszközön használni. Az új üzenetek csak arra az eszközre kézbesülnek, amelyik legutóbb bejelentkezett a kiszolgálóra.\n\nHa új eszközre vált, kérjük, távolítsa el vagy deaktiválja a %s-t a régi eszközön, majd indítsa újra az új eszközt.</string>
-	<string name="app_store_error_code">App Store hibakód: %d</string>
-	<string name="backup_restore_type"><![CDATA[Milyen típusú másolatot szeretne visszaállítani? <br/><br/> <a href=%s>Tudjon meg többet a Threema biztonsági mentésekről</a>]]></string>
-	<string name="data_backup_info">Mindent visszaállít, csevegésekkel</string>
-	<string name="new_to_threema">Új a %s-nál?</string>
-	<string name="back_to_threema">Visszatért a %s-hoz?</string>
-	<string name="id_backup_info">Csak az ID helyreállítása</string>
-	<string name="restore_your_id_contacts_and_groups">ID, kapcsolatok és csoportok visszaállítása</string>
-	<string name="threema_safe_backup">Threema Safe biztonsági mentés</string>
-	<string name="forgot_your_password"><![CDATA[<a href=%s>Elfelejtette a jelszót?</a>]]></string>
-	<string name="download_failed">Letöltés sikertelen. Hibakód: %d</string>
-	<string name="share_media">Megosztás más alkalmazással…</string>
-	<string name="group_link_administered">Adminisztrált</string>
-	<string name="group_link_open">Nyílt</string>
-	<string name="group_link_share_message">Csatlakozz a Threema csoportomhoz az alábbi hivatkozáson keresztül: %s</string>
-	<string name="group_link_bottom_sheet_title">Csoporthivatkozás</string>
-	<string name="group_link_bottom_sheet_desc">Ossza meg ezt a hivatkozást azokkal, akiket meg szeretne meghívni. Vegye figyelembe az alábbi beállításokat</string>
-	<string name="group_link_bottom_sheet_link_title">Hivatkozás</string>
-	<string name="group_link_properties_title">Hivatkozás tulajdonságok</string>
-	<string name="group_link_property_administration_title">Kézi megerősítés</string>
-	<string name="group_link_property_administration_desc">Ha engedélyezve van, akkor a csoportban kapja meg a kérelmeket, és egyenként megerősítheti azokat.</string>
-	<string name="group_link_property_expiration_title">Lejárati idő</string>
-	<string name="group_link_property_expiration_desc">A hivatkozás a megadott dátum után érvénytelenné válik.</string>
-	<string name="group_image">Csoportkép</string>
-	<string name="add_group_link">Tagok hozzáadása csoporthivatkozásokkal</string>
-	<string name="miui_battery_optimization">Kérjük, kapcsolja ki az "Akkumulátor optimalizálás" opciót a %s-hoz, hogy lehetővé tegye ezt a funkciót. Mivel a Xiaomi nem tartja szükségesnek az Android szabványok betartását, ezt kézileg kell megtennie a telefon beállításaiban. Az akkumulátor-optimalizálás letiltásával kapcsolatos segítségért forduljon a Xiaomi ügyfélszolgálatához.</string>
-	<string name="forward_captions">Küldje el a címkéket is</string>
-	<string name="importing_files_failed">A biztonsági mentési fájl importálása sikertelen. Győződjön meg róla, hogy elegendő szabad tárhely van.</string>
-	<string name="label_continue">Tovább</string>
-	<string name="select_date">Dátum kiválasztása</string>
-	<string name="select_time">Idő kiválasztása</string>
-	<string name="send_to">Küldés ide: %s</string>
-	<string name="receipts_override_choice_send">Küldjön</string>
-	<string name="receipts_override_choice_dont_send">Ne küldjön</string>
-	<string name="receipts_override_choice_default">Alapértelmezett (%s)</string>
-	<string name="unable_to_determine_recording_length">A felvétel üres vagy a hossza nem határozható meg</string>
-	<string name="prefs_header_receipts">Visszaigazolások</string>
-	<string name="prefs_title_reset_receipts">Egyedi beállítások visszaállítása</string>
-	<string name="prefs_sum_reset_receipts">Az olvasási bizonylatok és a «jelentés, amikor írok» kapcsolatspecifikus beállításainak alapértelmezettre állítása</string>
-	<string name="reset_successful">Alapértelmezett beállításokat sikeresen visszaállítva</string>
-	<string name="group_link_add">Hivatkozás létrehozása</string>
-	<string name="group_requests_show_menu_title">Nyitott csoportkérelmek megjelenítése</string>
-	<string name="group_request_show_all">Összes csoportoskérelem megjelenítése</string>
-	<string name="group_links_manage_menu">Csoporthivatkozások kezelése</string>
-	<string name="group_request_sent_menu">Elküldött csoportkérelem</string>
-	<string name="really_delete_group_link_title">Csoporthivatkozások törlése</string>
-	<string name="qr_scan_result_dialog_title">QR beolvasás eredmény</string>
-	<string name="scan_failure_dialog_title">Sikertelen beolvasás</string>
-	<string name="no_threema_qr_info">Ez nem egy Threema QR-kód, a dekódolt tartalma:</string>
-	<string name="default_group_link">Alapértelmezett csoporthivatkozás</string>
-	<string name="default_link_name">Alapértelmezett hivatkozás</string>
-	<string name="reset_default_group_link">Csoporthivatkozás visszaállítása</string>
-	<string name="resend">Újra elküldeni</string>
-	<string name="group_request_already_sent_title">Csoportkérelem már elküldve</string>
-	<string name="qr_scanner_id_hint">Egy másik névjegy QR-kódjának beolvasásával ellenőrizheti őt. A QR-kód a Threema főképernyő bal felső sarkában lévő profilképre kattintva tekinthető meg.</string>
-	<string name="enable_storage_access_for_media">Aktiválja a tárhelyelérést a képek és videók megtekintéséhez</string>
-	<string name="take_me_there">Aktiváld most…</string>
-	<string name="notification_channel_group_join_request">Értesítések a csoportkérelmekről</string>
-	<string name="reset_default_group_link_title">Visszaállítás-infó</string>
-	<string name="reset_default_group_link_desc">A korábban megosztott hivatkozás érvénytelenné válik, és a régi linken keresztül érkező kérelmeket automatikusan elutasítjuk.</string>
-	<string name="custom">továbbiak</string>
-	<string name="show_public_key">Nyilvános kulcs megjelenítése</string>
-	<string name="public_key_for">%s nyilvános kulcsa</string>
-	<string name="copied">Másolva</string>
-	<string name="no_votes_yet">Még nem adtak le szavazatot.</string>
-	<string name="permission_contacts_sync_required">A szinkronizáláshoz engedélyezze a névjegyekhez való hozzáférést.</string>
-	<string name="not_voted_user_list">Ezek a résztvevők nem szavaztak: %s</string>
-	<string name="invalid_onprem_id">Nincs érvényes Threema OnPrem-ID</string>
-	<string name="enable_unknown_sources">Telepítés nem lehetséges. Kérjük, engedélyezze a \"Ismeretlen alkalmazások telepítése\" opciót a %s-hoz.</string>
-	<string name="full_name">Név</string>
-	<string name="name_given">Utónév</string>
-	<string name="name_family">Vezetéknév</string>
-	<string name="name_prefix">Név előtagja</string>
-	<string name="name_middle">Második utónév</string>
-	<string name="name_suffix">Név utótagja</string>
-	<string name="phoneTypeCustom">"Egyéni"</string>
-	<string name="phoneTypeHome">"Otthoni"</string>
-	<string name="phoneTypeMobile">"Mobil"</string>
-	<string name="phoneTypeWork">"Munkahelyi"</string>
-	<string name="phoneTypePager">"Személyhívó"</string>
-	<string name="phoneTypeOther">"Egyéb"</string>
-	<string name="phoneTypeCar">"Gépkocsi"</string>
-	<string name="phoneTypeIsdn">"ISDN"</string>
-	<string name="phoneTypeOtherFax">"Egyéb fax"</string>
-	<string name="eventTypeCustom">"Egyéni"</string>
-	<string name="eventTypeBirthday">"Születésnap"</string>
-	<string name="eventTypeAnniversary">"Évforduló"</string>
-	<string name="eventTypeOther">"Egyéb"</string>
-	<string name="emailTypeHome">"Otthoni"</string>
-	<string name="emailTypeWork">"Munkahelyi"</string>
-	<string name="emailTypeOther">"Egyéb"</string>
-	<string name="postalTypeCustom">"Egyéni"</string>
-	<string name="postalTypeHome">"Otthoni"</string>
-	<string name="postalTypeWork">"Munkahelyi"</string>
-	<string name="postalTypeOther">"Egyéb"</string>
-	<string name="relationTypeCustom">"Egyéni"</string>
-	<string name="relationTypeChild">"Gyermek"</string>
-	<string name="relationTypeFriend">"Ismerős"</string>
-	<string name="relationTypeParent">"Szülő"</string>
-	<string name="relationTypeSpouse">"Házastárs"</string>
-	<string name="contact_property_key">"Kulcs"</string>
-	<string name="header_nickname_entry">"Becenév"</string>
-	<string name="organization_type">Szervezet</string>
-	<string name="messages_cannot_be_recovered">Az üzeneteket nem lehet visszaállítani.</string>
-	<plurals name="contacts_counter_label">
-		<item quantity="one">%d névjegyek</item>
-		<item quantity="other">%d névjegyek</item>
-	</plurals>
-	<plurals name="really_delete_thread_message">
-		<item quantity="one">Tényleg törölni szeretné a %d csevegést?</item>
-		<item quantity="other">Tényleg törölni szeretné az %d csevegéseket?</item>
-	</plurals>
-	<plurals name="sending_message_failed">
-		<item quantity="one">%1$d üzenet nem küldhető</item>
-		<item quantity="other">%1$d üzenet nem küldhető</item>
-	</plurals>
-	<plurals name="selection_counter_label">
-		<item quantity="one">%d kép kiválasztva</item>
-		<item quantity="other">%d kép kiválasztva</item>
-	</plurals>
+		vagy álnevet használjon. Ha nem állít be becenevet, a Threema ID lesz használva.</string>
+    <string name="not_linked">nem összecsatolt</string>
+    <string name="linked">összecsatolt</string>
+    <string name="pending_sms_verification_notice">A mobilszámodat még nem ellenőriztük.</string>
+    <string name="no_sms_received">Nem kapott SMS-t?</string>
+    <string name="really_cancel_verify">Tényleg megszakítod a mobilszámod hitelesítését? Ha megszakítod az ellenőrzést, a mobilszám nem lesz összecsatolva.</string>
+    <string name="verification_of">%s ellenőrzése</string>
+    <string name="status_ballot_voting_changed">Új szavazat érkezett a «%1$s» szavazásra</string>
+    <string name="status_ballot_user_first_vote">«%1$s» szavazott «%2$s» mellett</string>
+    <string name="status_ballot_user_modified_vote">«%1$s» megváltoztatta szavazatát «%2$s»-hoz</string>
+    <string name="status_ballot_all_votes">Szavazás «%1$s» befejeződött</string>
+    <string name="restore">Visszaállítás</string>
+    <string name="new_wizard_anonymous_confirm">Nem adtál meg mobiltelefonszámot vagy e-mail címet összecsatoláshoz. Ezért nem fog automatikusan szerepelni a barátai névjegyzékében. Tényleg teljesen anonim módon szeretné használni a Threemát?</string>
+    <string name="new_wizard_anonymous_confirm_phone_only">Ön nem adott meg mobiltelefonszámot összecsatoláshoz. Ezért nem fog automatikusan szerepelni a barátai névjegyzékében. Tényleg teljesen anonim módon szeretné használni a Threemát?</string>
+    <string name="new_wizard_scan_id_backup">Vagy szkennelje be az ID export QR-kódját.</string>
+    <string name="error_saving_file">Hiba mentés közben. Nincs engedélye?</string>
+    <string name="wait_one_minute">Kérjük, várjon legalább 10 percet az SMS-re, mielőtt visszahívást kérne.</string>
+    <string name="backup_id">ID export</string>
+    <string name="backup_data">Adatmentés</string>
+    <string name="really_leave_group_admin_message">Ön ennek a csoportnak az adminisztrátora. Ha most elhagyja, akkor elárvul. A többi tag folytathatja a csevegést, de módosítások már nem lehetségesek.</string>
+    <string name="action_delete_group">Csoport törlése</string>
+    <string name="delete_my_group_message">Teljesen törölni szeretné ezt a csoportot? Minden üzenet törlésre kerül, és a megmaradt tagok többé nem használhatják a csoportot.</string>
+    <string name="error_out_of_memory">Túl kevés a szabad memória a művelet végrehajtásához</string>
+    <string name="configure">Beállítás</string>
+    <string name="file_is_not_audio">Nincs hangfájl</string>
+    <!-- restrictions -->
+    <string name="disabled_by_policy">Egyes beállításokat a rendszergazda letiltott</string>
+    <string name="select_all">Minden kiválasztása</string>
+    <string name="deleting_messages">Az üzenetek törlődnek</string>
+    <string name="media_gallery_files">Fájlok</string>
+    <string name="prefs_gif_autoplay">Anim GIF-ek automatikus lejátszása</string>
+    <string name="media_gallery_audio">Hangüzenetek</string>
+    <string name="action_clone_group">Csoport klónozása</string>
+    <string name="clone_group_message">Az aktuális csoport másolata jön létre Önnel mint rendszergazdával. Folytatja?</string>
+    <string name="prefs_proximity_sensor">Közelségérzékelő használata</string>
+    <string name="prefs_proximity_sensor_explain">Hangüzeneteket a fülhallgatón keresztül visszajátszani, ha a közelségérzékelő le van fedve</string>
+    <string name="error_creating_group">Hiba a csoport létrehozásában/frissítésében</string>
+    <string name="no_media_found_generic">Nem találtunk médiát</string>
+    <string name="max_images_reached" tools:ignore="PluralsCandidate">Egyszerre nem lehet több mint %d képet szerkeszteni</string>
+    <string name="enter_description">Kérjük, írja le a problémát vagy hibát.</string>
+    <string name="add_caption_hint">Felirat hozzáadása</string>
+    <string name="disable">Kikapcsolás</string>
+    <string name="continue_anyway">Folytassa</string>
+    <string name="invalid_input">Érvénytelen bevitel</string>
+    <string name="already_licensed">Már engedélyezett</string>
+    <string name="hide_chat">Privát csevegések</string>
+    <string name="really_hide_chat_message">Tényleg magánbeszélgetésnek akarod jelölni ezt a csevegést? A privát beszélgetések elrejtéséhez vagy újra láthatóvá tételéhez használja a funkciót a menüben.</string>
+    <string name="chat_hidden">A csevegés privátként jelölése</string>
+    <string name="title_show_private_chats">Privát csevegések megjelenítése</string>
+    <string name="title_hide_private_chats">Privát csevegések elrejtése</string>
+    <string name="chat_visible">A chat mostantól mindig látható</string>
+    <string name="prefs_title_locking_mechanism">Védelmi mechanizmus</string>
+    <string name="lock_option_none">Nincs</string>
+    <string name="lock_option_pin">PIN-kód</string>
+    <string name="lock_option_screenlock">Rendszer-zárolás</string>
+    <string name="hide_chat_message_explain">Bizonyos csevegésekhez való hozzáférést PIN-kóddal védheti, és átmenetileg elrejtheti a csevegéseket a csevegési listában. A funkció használatához először állítson be egy hozzáférési védelmet.</string>
+    <string name="set_lock">Aktiválás</string>
+    <string name="prefs_title_access_protection">Hozzáférésvédelem</string>
+    <string name="private_chat_subject">Privát</string>
+    <string name="grace_thirty_seconds">30 másodperc</string>
+    <string name="grace_one_minute">1 perc</string>
+    <string name="grace_two_minutes">2 perc</string>
+    <string name="grace_five_minutes">5 perc</string>
+    <string name="grace_ten_minutes">10 perc</string>
+    <string name="grace_thirty_minutes">30 perc</string>
+    <string name="grace_never">Soha (kézi)</string>
+    <string name="never">Soha</string>
+    <string name="unhide_chats_confirm">Ha eltávolítja a hozzáférés-védelmet, a privát beszélgetések ismét láthatóvá válnak.</string>
+    <string name="verification_started">Ellenőrzés elkezdve</string>
+    <string name="cannot_open_file">A fájlt nem lehetett megnyitni</string>
+    <string name="prefs_title_image_attach_previews">Média gyorsválasztó</string>
+    <string name="prefs_sum_image_attach_previews">A legújabb képek listájának megjelenítése a Hozzáadás ablakban</string>
+    <string name="prefs_title_direct_share">Közvetlen megosztás</string>
+    <string name="prefs_sum_direct_share">Legutóbbi beszélgetések megjelenítése más alkalmazásokból történő megosztáskor</string>
+    <string name="restore_disable_energy_saving">A folytatás előtt csatlakoztassa készülékét a töltőhöz. Győződjön meg róla, hogy a telefon összes energiatakarékos üzemmódja ki van kapcsolva, hogy a biztonsági mentés/visszaállítás ne szakadjon meg.</string>
+    <string name="draft">Vázlat</string>
+    <string name="prefs_bigger_single_emojis">Önálló emojik nagyítása</string>
+    <string name="wizard1_sync_work">Szinkronizálás folyamatban…</string>
+    <string name="notification_hidden_text">Tartalom elrejtve</string>
+    <string name="really_reset_ringtones">Értesítési hangok visszaállítása a gyári beállításokra?</string>
+    <string name="reset_ringtones_confirm">Értesítési hangok visszaállítva</string>
+    <string name="prefs_language_override">Nyelv</string>
+    <string name="threema_channel_intro">A Threema Channel a Threema-ról szóló hírekkel látja el Önt. Szeretne feliratkozni a
+		Threema Channelre és hozzáadni a névjegyzékbe? Ingyenes, és bármikor leiratkozhatsz róla.</string>
+    <string name="quote">Idéz</string>
+    <string name="really_delete_contacts_message" tools:ignore="PluralsCandidate">Biztosan törölni szeretne %1$d névjegyet és az összes kapcsolódó csevegést?</string>
+    <string name="contacts_deleted">A névjegyek törölve lettek</string>
+    <string name="some_contacts_not_deleted" tools:ignore="PluralsCandidate">%d névjegyet nem lehetett törölni, mert még mindig egy csoportban vannak.</string>
+    <string name="take_photo">Fotózás</string>
+    <string name="select_from_gallery">Galériából választás</string>
+    <string name="palette">Paletta</string>
+    <string name="stickers">Matricák</string>
+    <string name="text">Szöveg</string>
+    <string name="undo">Vissza</string>
+    <string name="android_backup_date">Utolsó biztonsági mentés</string>
+    <string name="check_now">Ellenőrzés</string>
+    <string name="discard">Eldob</string>
+    <string name="android_backup_restart_threema">Kérem, várjon. Az alkalmazás hamarosan újraindul.</string>
+    <string name="battery_optimizations_title">Az akkumulátoroptimalizálás letiltása</string>
+    <string name="battery_optimizations_explain">Az akkumulátorteljesítmény optimalizálása megakadályozza, hogy a %1$s megfelelően működjön, amikor a telefon alvó üzemmódba kapcsol. Kérjük, tiltsa le az optimalizálást %2$s számára.</string>
+    <string name="battery_optimizations_disable_guide">A legördülő menüben válassza az «Összes alkalmazás»-t</string>
+    <string name="battery_optimizations_disable_guide_ctd">Keresse a %s-t a listában és kikapcsolja ki az optimalizálást</string>
+    <string name="battery_optimizations_disable_confirm">Tényleg engedélyezve akarja hagyni az akkumulátor teljesítményének optimalizálását %1$s esetében? Ezáltal a %2$s használhatatlanná válhat.</string>
+    <string name="enter_text_hint">Írja be</string>
+    <string name="backup_explain_text">Ha lecseréli vagy elveszíti a készülékét, senki sem tudja visszaállítani a Threema azonosítóját és a csevegéseket biztonsági mentés nélkül. Ezért készítsen biztonsági másolatot az adatokról a rendelkezésre álló biztonsági mentési lehetőségekkel.</string>
+    <string name="data_backup_explain">Az adatmentés a következőket menti:\n\n&#9679; ID és kulcspár\n&#9679; névjegyzék és bizalmi státusz\n&#9679; csoporttagságok\n&#9679; csevegések\n&#9679; médiák és fájlok (opcionális)\n\nAz adatok titkosított ZIP-ben kerülnek mentésre. A biztonsági másolatot ezután a készüléken kívül, megfelelő helyen kell tárolni.</string>
+    <string name="draw">Rajzolás</string>
+    <string name="edit">Szerkesztés</string>
+    <string name="discard_changes">El akarja vetni a változtatásokat?</string>
+    <string name="prefs_title_network">Hálózat</string>
+    <string name="prefs_title_ipv6_preferred">IPv6 üzenetekhez</string>
+    <string name="prefs_ipv6_preferred_off">Csak IPv4 kapcsolatokat használjon</string>
+    <string name="prefs_ipv6_preferred_on">IPv6 előnyben részesítése</string>
+    <string name="prefs_title_ipv6_webrtc_allowed">IPv6 hívásokhoz és webhez</string>
+    <string name="prefs_ipv6_webrtc_allowed_on">IPv6 engedélyezése a Threema-hívásokhoz és a Threema Webhez</string>
+    <string name="prefs_ipv6_webrtc_allowed_off">Ne használja az IPv6-ot a Threema-hívásokhoz és a Threema Webhez.</string>
+    <string name="ipv6_requires_restart">Ez a módosítás az alkalmazás újraindítását igényli.</string>
+    <string name="ipv6_restart_now">Újraindítás most</string>
+    <string name="on_cap">Be</string>
+    <string name="off_cap">Ki</string>
+    <string name="share_chat">Csevegés megosztása</string>
+    <string name="flip">Tükrözés</string>
+    <string name="to_front">Előre</string>
+    <string name="play">Lejátszás</string>
+    <string name="pause">Szünet</string>
+    <string name="retry">Ismét</string>
+    <string name="voice_message_record">Hangüzenet felvétele</string>
+    <string name="open_navdrawer">Oldalmenü megnyitása</string>
+    <string name="profile_picture">Profilkép</string>
+    <string name="profile_picture_release">Ki láthatja a profilképét?</string>
+    <string name="picrelease_nobody">Senki</string>
+    <string name="picrelease_selected">Kiválasztott névjegyek</string>
+    <string name="picrelease_everyone">Mindenki, akinek írsz</string>
+    <string name="prefs_title_receive_profilepics">Profilképek megjelenítése</string>
+    <string name="prefs_sum_receive_profilepics_off">A névjegyek profilképeinek elrejtése</string>
+    <string name="prefs_sum_receive_profilepics_on">A névjegyek profilképeinek megjelenítése</string>
+    <string name="prefs_sum_receive_profilepics_recipients_list">Az ebben a listában kiválasztott névjegyek megkapják a profilképét, amikor ír nekik.</string>
+    <string name="menu_send_profilpic">Profilkép címzett hozzáadás</string>
+    <string name="menu_send_profilpic_off">Profilkép címzett eltávolítás</string>
+    <string name="menu_send_profilpic_now">Profilkép küldése most</string>
+    <string name="profile_picture_sent">A profilkép elküldve</string>
+    <string name="sending_messages">Küldés…</string>
+    <string name="backup_data_media_confirm">A nagyméretű médiafájlok ZIP biztonsági mentése hosszú időt vehet igénybe, és meghaladhatja a készülék processzor- és memóriakapacitását. A biztonsági mentés során nem fogadhatók Threema üzenetek. Biztos, hogy folytatni akarod?</string>
+    <string name="backup_data_cancelled">A biztonsági mentés leállítása</string>
+    <string name="service_manager_not_available">Az alkalmazás nem indítható. Kérjük, kapcsolja ki teljesen a készüléket, majd kapcsolja be újra.</string>
+    <string name="message_sent">Üzenetet elküldve</string>
+    <string name="threema_call">Threema hívás</string>
+    <string name="threema_message_to">Üzenet %s-nek</string>
+    <string name="threema_call_with">%s hívása</string>
+    <string name="prefs_title_voip">Threema hívások</string>
+    <string name="prefs_title_force_turn">Hívások mindig a szerveren keresztül</string>
+    <string name="prefs_summary_force_turn_off">Ha lehetséges, használjon közvetlen kapcsolatot, és csak nem ellenőrzött névjegyek hívásait irányítsa a Threema szerverein keresztül. Feltárhatja az IP-címét.</string>
+    <string name="prefs_summary_force_turn_on">Minden hívást a Threema szervereken keresztül irányít. Védi az IP-címet, de rosszabb hívásminőséget eredményezhet.</string>
+    <string name="permission_record_audio_required">Engedélyezze a mikrofon használatát titkosított Threema-hívások kezdeményezéséhez és hangüzenetek rögzítéséhez.</string>
+    <string name="prefs_voice_call_notifications">Hanghívások</string>
+    <string name="prefs_voice_call_sound">Csengőhang</string>
+    <string name="prefs_sum_voice_call_sound">Csengőhang kiválasztása Threema hanghívásokhoz</string>
+    <string name="prefs_sum_voice_call_vibrate">Rezgés a bejövő Threema hanghívásoknál</string>
+    <string name="prefs_title_voip_enable">Threema-hívások engedélyezése</string>
+    <string name="webclient_invalid_push_token_message">Kézi indítás szükséges</string>
+    <string name="threema_work_contact">Threema Work névjegy</string>
+    <string name="permission_phone_required">A Threema-hívás közbeni hívások kezeléséhez kapcsolja be ezt az engedélyt.</string>
+    <string name="strikethrough">Áthúzott</string>
+    <string name="italic">Kurzív</string>
+    <string name="bold">Vastag</string>
+    <string name="shortcut_choice_title">Parancsikon készítése…</string>
+    <string name="prefs_title_device_info">Eszköz információ</string>
+    <string name="notifications_disabled_title">Értesítések letiltva</string>
+    <string name="notifications_disabled_text">A Threema értesítéseit teljesen letiltották a rendszerben. Nem kap értesítést, ha új üzenetek érkeznek.</string>
+    <string name="notifications_disabled_settings">Rendszerbeállítások módosítása</string>
+    <string name="error_attaching_files">Hiba fájlok hozzáadásakor.</string>
+    <string name="prefs_fix_powermanager_problems">A háttérben való futás engedélyezése</string>
+    <string name="prefs_fix_powermanager_problems_desc">Problémák javítása a telefonon, amelyek megakadályozzák, hogy a Threema a háttérben fusson és üzeneteket fogadjon</string>
+    <string name="disable_powermanager_explain">A következő képernyőn győződjön meg arról, hogy a «%s» védve van mindenféle korlátozás alól, és aktív lehet a háttérben. Kattintson a vissza gombra, ha végzett.</string>
+    <string name="disable_autostart_explain">A következő képernyőn kérjük, aktiválja az automatikus indítást a «%s» számára! Kattintson a \"Vissza\" gombra, ha végzett.</string>
+    <string name="notification_priority_default">Alacsony</string>
+    <string name="notification_priority_high">Magas</string>
+    <string name="notification_priority_max">Maximum</string>
+    <string name="prefs_title_notification_priority">Prioritás</string>
+    <string name="pin">Feltűzni</string>
+    <string name="unpin">Levenni</string>
+    <string name="location_services_disabled">A helymeghatározási szolgáltatások ki vannak kapcsolva. Szeretné őket most aktiválni?</string>
+    <string name="send_location">Helyszín elküldése</string>
+    <string name="unknown_address">Ismeretlen cím</string>
+    <string name="your_location">Tartózkodási helye</string>
+    <string name="network_blocked_title">Háttéradatok letiltva</string>
+    <string name="network_blocked_body">%s nem tud üzeneteket fogadni a háttérben. A háttéradatok engedélyezéséhez kattintson ide.</string>
+    <string name="reply_later">Később jelentkezem</string>
+    <string name="reply_on_my_way">Úton vagyok</string>
+    <string name="reply_thank_you">Köszönöm</string>
+    <string name="reply_youre_welcome">Szívesen</string>
+    <string name="prefs_auto_download_title">Médiák automatikus letöltése</string>
+    <string name="prefs_auto_download_wifi">WLAN-on</string>
+    <string name="prefs_auto_download_mobile">A mobilhálózatokon</string>
+    <string name="rate_intro">Hogy tetszik a Threema?</string>
+    <string name="rate_feedback_intro">Kérjük, mondja el, mit tehetnénk jobban (nem kötelező).</string>
+    <string name="rate_positive">Értékelés küldése</string>
+    <string name="rate_title">Threema értékelése</string>
+    <string name="rate_thank_you">Köszönjük értékelését!</string>
+    <string name="disabled_by_policy_short">A funkciót a rendszergazda letiltotta</string>
+    <string name="rate_forward_to_play_store">Ön is szeretne értékelni minket a Google Play-en?</string>
+    <string name="rate_error">Nem tudta elküldeni a véleményét. Kérjük, győződjön meg róla, hogy csatlakozik az internethez.</string>
+    <string name="off_unless_i_was_mentioned">Be, kivéve, ha említenek</string>
+    <string name="dnd">Ne zavarj</string>
+    <string name="minus">Mínusz</string>
+    <string name="plus">Plusz</string>
+    <string name="switched_off">Ki</string>
+    <string name="switched_on">Be</string>
+    <string name="title_tab_work_users">Threema Work felhasználók</string>
+    <string name="no_matching_work_contacts">Nem találtunk olyan Threema Work névjegyet, amelyet a rendszergazda ellenőrzött.</string>
+    <string name="all">Mind</string>
+    <string name="webclient_session_stop_all">Mind leállítása</string>
+    <string name="webclient_running_sessions">%d futó munkamenet</string>
+    <string name="passphrase_service_name">Jelszó szolgáltatás</string>
+    <string name="passphrase_service_description">Értesítés ha a jelszó feloldva</string>
+    <string name="webclient_service_description">Értesítés, ha egy webes/asztalos munkamenet aktív</string>
+    <string name="prefs_title_accept_privacy_policy">Adatvédelmi irányelvek elfogadása</string>
+    <string name="privacy_policy_explain">%1$s következetesebben védi az Ön privátszféráját, mint bármely más messenger. Nézze meg az %2$s-ot, hogy többet tudjon meg.</string>
+    <string name="privacy_policy_check_confirm">Kérjük, fogadja el az adatvédelmi nyilatkozatot, hogy használni tudja a %s-t.\n\n(Az EU 2016/679 rendelet szerinti követelmény)</string>
+    <string name="prefs_title_incognito_keyboard">Inkognitó billentyűzet kérése</string>
+    <string name="prefs_sum_incognito_keyboard">Az adatok gyűjtésének letiltása a személyre szabott javaslatokhoz (ha a billentyűzet támogatja)</string>
+    <string name="tooltip_mentions">Érintse meg a @ jelet a billentyűzeten, hogy közvetlenül megszólítson vagy megemlítsen egy kapcsolatot ebben a csoportban.</string>
+    <string name="tooltip_imagepaint">Légy kreatív! Érintse meg a varázspálcát, hogy firkáljon, vagy adjon matricákat és szöveget a képekhez elküldés előtt.</string>
+    <string name="call_ongoing">Hívás folyamatban</string>
+    <string name="ballot_received_votes">Beérkezett szavazatok: %1$d/%2$d</string>
+    <string name="quote_not_found">Idézett üzenet nem található</string>
+    <string name="ballot_secret">titkos</string>
+    <string name="password_too_short_generic">A jelszó túl rövid</string>
+    <string name="passwords_dont_match">Nem azonos</string>
+    <string name="test_unsuccessful">A teszt sikertelen</string>
+    <string name="preparing_threema_safe">Threema Safe előkészítése</string>
+    <string name="disable_powermanager_title">Akku-korlátozások</string>
+    <string name="disable_autostart_title">Autom. indulás</string>
+    <string name="unchanged">változatlan</string>
+    <string name="safe_learn_more_button">További információ</string>
+    <string name="safe_enable_explain">A Threema-nál nincs központi felhasználói fiókja. Az Ön adatai csak az adott eszközön léteznek, és így a legjobban védettek a külső hozzáféréstől.\n\nA Threema Safe rendszeresen készít titkosított, anonim biztonsági másolatot az Ön <b>kulcsairól, névjegyeiről, csoportjairól és beállításairól</b> (de az üzenetek tartalmáról nem) egy Ön által választott szerveren. Az Ön azonosítója és a kiválasztott jelszó elegendő ahhoz, hogy visszaállítsa ezeket az adatokat egy másik eszközön.</string>
+    <string name="safe_disable_confirm">A Threema Safe aktiválása nélkül szeretne folytatni? A Threema Safe lehetővé teszi a Threema ID, a névjegyek és a csoportok visszaállítását, ha elveszíti a készülékét.</string>
+    <string name="safe_configure_choose_password">Válasszon egy biztonságos jelszót. Erre a jelszóra szüksége lesz a Threema Safe biztonsági mentés visszaállításához.</string>
+    <string name="safe_configure_choose_server">Kiszolgáló kiválasztása</string>
+    <string name="safe_configure_server_explain">Threema Safe biztonsági másolatának tárolása a Threema-nál vagy az Ön által választott szerveren.</string>
+    <string name="safe_use_default_server">Alapkiszolgáló</string>
+    <string name="safe_test_server">Kiszolgáló tesztelése</string>
+    <string name="safe_advanced_options">Szakértői beállítások</string>
+    <string name="safe_enter_password">Kérjük, adja meg a Threema Safe jelszavát</string>
+    <string name="safe_threema_id">Az ön Threema ID-ja</string>
+    <string name="safe_restore_enter_id">Kérjük, adja meg a helyreállítani kívánt Threema ID-t</string>
+    <string name="safe_search_id_title">Kérjük, adja meg a Threema ID-hoz csatolt mobilszámot vagy e-mail címet.</string>
+    <string name="safe_id_lookup">Threema-ID keresése</string>
+    <string name="safe_no_id_found">Nem találtunk Threema-ID-t</string>
+    <string name="safe_no_backup_found">Nincs biztonsági mentés a kiszolgálón. Ellenőrizze az ID-t és a jelszót.</string>
+    <string name="safe_select_id">Több Threema ID-t találtunk. Válassza ki a kívánt ID-t:</string>
+    <string name="safe_backup_now">Biztonsági mentés most</string>
+    <string name="safe_enable_explain_short">Aktiválja a Threema Safe szolgáltatást a legfontosabb adatok automatikus, biztonságos és anonim mentéséhez</string>
+    <string name="safe_deleting">A Threema Safe biztonsági mentés törlődik</string>
+    <string name="safe_delete_error">Törlési hiba: %s</string>
+    <string name="safe_delete_success">A biztonsági másolat sikeresen törlődött a kiszolgálóról</string>
+    <string name="safe_error_preparing">Hiba a Threema Safe biztonsági mentés elkészítése közben</string>
+    <string name="safe_configure_choose_password_force">Állítson be egy erős jelszót, hogy a Threema Safe segítségével megvédje ID-jét. Ne felejtse el, hogy mit ír be ide!</string>
+    <string name="safe_deactivate">Threema Safe kikapcsolása</string>
+    <string name="safe_deactivate_explain">A meglévő Threema Safe biztonsági mentések visszavonhatatlanul törlődnek a kiszolgálón. Akarod folytatni?</string>
+    <string name="add_group_members">Új tag</string>
+    <string name="contact_add_confirm">Szeretné felvenni az új névjegyet «%1$s» a névjegyzékébe?</string>
+    <string name="password_bad">Nem biztonságos jelszó</string>
+    <string name="prefs_fix_background_data">Háttéradatok engedélyezése</string>
+    <string name="prefs_fix_background_data_desc">Ha engedélyezni szeretné, hogy a Threema a háttérben fogadjon üzeneteket, engedélyezze a Háttéradatok és a Korlátlan adatforgalom funkciót</string>
+    <string name="prefs_fix_device">Az eszköz konfigurációs problémáinak javítása</string>
+    <string name="safe_successful">Sikeres</string>
+    <string name="safe_unsuccessful">Sikertelen</string>
+    <string name="safe_upload_failed">A feltöltés sikertelen</string>
+    <string name="safe_upload_size_exceeded">A biztonsági mentés túlméretes</string>
+    <string name="safe_connection_error">Csatlakozási hiba</string>
+    <string name="safe_server_name">Kiszolgáló</string>
+    <string name="safe_max_backup_size">Max. biztonsági mentés méret</string>
+    <string name="safe_retention">Tárolási idő</string>
+    <string name="safe_result">Eredmény</string>
+    <string name="number_of_days">%d nap</string>
+    <string name="backup_other_restore_options">Egyéb helyreállítási lehetőségek</string>
+    <string name="safe_size">A mentés mérete</string>
+    <string name="safe_version_mismatch">A biztonsági mentés verziója magasabb az alkalmazás által támogatottnál. Kérjük, frissítse az alkalmazást.</string>
+    <string name="safe_restore_failed">A visszaállítás sikertelen</string>
+    <string name="safe_failed_notification">A Threema Safe %d napja nem tud biztonsági mentést készíteni. Kérjük, kattintson ide az ellenőrzéshez.</string>
+    <string name="safe_restore">Threema Safe visszaállítása</string>
+    <string name="backup_restore_in_progress">Biztonsági mentés vagy visszaállítás folyamatban. További információkért nézze meg az értesítést.</string>
+    <string name="restore_error_body">A visszaállítás sikertelen</string>
+    <string name="forgot_your_id">Elfelejtette az ID-ját?</string>
+    <string name="restore_success_body">A visszaállítás sikeresen befejeződött.</string>
+    <string name="work_data_sync">Adatok szinkronizálása</string>
+    <string name="private_contact">Privát névjegy</string>
+    <string name="ringtone_selection_default">Alapértelmezett (%s)</string>
+    <string name="work_data_sync_desc">Threema Work szinkronizálás</string>
+    <string name="ballot_not_connected">Kérjük, a szavazás kitöltése előtt győződjön meg arról, hogy a Threema online van.</string>
+    <string name="empty_chat_title">Csevegés kiürítése</string>
+    <string name="empty_chat_confirm">Ebben a csevegésben minden üzenet törlésre kerül. Folytassuk?</string>
+    <string name="emptying_chat">Csevegés ürítése</string>
+    <string name="set_private">«Privát csevegés»-ként jelölés</string>
+    <string name="unset_private">«Privát csevegés» kikapcsolása</string>
+    <string name="delete_group_message">Ki akarsz lépni ebből a csoportból, és teljesen törölni akarod? Minden üzenet törlődik.</string>
+    <string name="delete_left_group_message">Teljesen törölni szeretné ezt a csoportot? Minden üzenet törlődik.</string>
+    <string name="chats">Csevegések</string>
+    <string name="notification_setting_ignored">A VÁLTOZTATÁSOK FIGYELMEN KÍVÜL LESZNEK HAGYVA!</string>
+    <string name="notification_channel_alerts">Figyelmeztetések és hibaüzenetek</string>
+    <string name="notification_channel_notices">Megjegyzések</string>
+    <string name="chat_updates">Csevegés frissítések</string>
+    <string name="backup_or_restore_progress">Biztonsági mentés/visszaállítás állapota</string>
+    <string name="tooltip_export_id">Kattintson ide a titkosított Threema ID megosztásához vagy kinyomtatásához.</string>
+    <string name="downloading">Letöltés</string>
+    <string name="today">Ma</string>
+    <string name="restore_data_cancelled">Visszaállítás megszakítva</string>
+    <string name="safe_change_password">Jelszó módosítása</string>
+    <string name="safe_configure_choose_password_title">Jelszó választása</string>
+    <string name="password_bad_explain">Az Ön által választott Threema Safe jelszó nagyon gyenge, ezért a támadók könnyen kitalálhatják. Kérjük, válasszon biztonságos jelszót. Tipp: Használjon több kifejezésből álló összetett szót.</string>
+    <string name="safe_password_updated">A Threema Safe jelszó frissítve lett.</string>
+    <string name="safe_activated">A Threema Safe aktiválódott.</string>
+    <string name="restore_zip_invalid_file">A biztonsági mentési fájl érvénytelen.</string>
+    <string name="push_token_cleared">A push token eltávolításra került</string>
+    <string name="insert_date">Dátum beillesztése</string>
+    <string name="add_answer">Válasz hozzáadása</string>
+    <string name="title_cannot_be_empty">A szavazás címe nem lehet üres</string>
+    <string name="voip_disabled">Threema-hívások letiltva</string>
+    <string name="hide_chat_enter_message_explain">Ez a csevegés privátnak van jelölve. A megtekintéshez először állítson be egy hozzáférés védelmet.</string>
+    <string name="unknown">Ismeretlen</string>
+    <string name="miui_notification_title">Fontos megjegyzés a MIUI felhasználók számára</string>
+    <string name="miui_notification_body">A MIUI 10 alapértelmezetten letiltja a hangokat, a LED-et és a felugró ablakokat az újonnan létrehozott értesítési csatornákhoz (kivéve néhány, a Xiaomi által «fontosnak» tartott alkalmazás esetében). Ezért ezeket a paramétereket a telefon Threema-specifikus értesítési beállításaiban kell engedélyeznie az egyes csatornákhoz. További információért forduljon a telefon gyártójához.</string>
+    <string name="miui12_notification_body">A MIUI alapértelmezetten kikapcsolja a hangokat, a LED-et és a felugró ablakokat (kivéve néhány nagyon népszerű alkalmazást, amelyeket a Xiaomi «fontosnak» tart). Ezért sajnos manuálisan kell aktiválnia ezeket a beállításokat a telefon Threema-specifikus értesítési beállításaiban, és minden alkalmazásfrissítés után meg kell ismételnie az eljárást. További információért forduljon a telefon gyártójához.</string>
+    <string name="dont_show_again">Ne mutassa újra</string>
+    <string name="miui_notification_prefs">MIUI beállítások</string>
+    <string name="threema_safe_upload_successful">Threema-Safe biztonsági mentés sikeresen feltöltve</string>
+    <string name="time_remaining">még %s</string>
+    <string name="safe_configure_server_credentials_title">Hitelesítés (opcionális)</string>
+    <string name="username_hint">Felhasználónév</string>
+    <string name="lock_option_biometric">Biometrikus</string>
+    <string name="biometric_enter_authentication">Kérjük, hitelesítse magát a feloldáshoz</string>
+    <string name="biometric_authentication_failed">A hitelesítés sikertelen</string>
+    <string name="biometric_authentication_successful">Önt sikeresen hitelesítették</string>
+    <string name="work_safe_forced_explain">A rendszergazda engedélyezte a Threema Safe szolgáltatást az Ön készülékén.</string>
+    <string name="pin_locked_cannot_send">Alkalmazás zárolva. Küldés nem lehetséges.</string>
+    <string name="prefs_summary_hide_screenshots_notice">Adatvédelmi okokból a miniatűrök és a képernyőképek mindig le vannak tiltva, ha az alkalmazászár engedélyezve van.</string>
+    <string name="work_select_categories">Kategóriák kiválasztása</string>
+    <string name="my_profile">Profilom</string>
+    <string name="message_too_long">Az üzenet túl hosszú és nem küldhető el.</string>
+    <string name="database_migration_no_space">Az adatbázis migrációja nem lehetséges: Túl kevés a szabad hely.</string>
+    <string name="advanced_options">További lehetőségek</string>
+    <string name="url_warning_body">A megnyitni kívánt weboldal gyanús:\n\nMegjelenített hostnév: <b>%s</b>\nValódi hostnév: <b>%s</b>\n\nLehet, hogy egy hamis weboldalra próbálják átirányítani Önt.\n\nMégis folytatni akarja?</string>
+    <string name="url_warning_title">Adathalászat figyelmeztetés</string>
+    <string name="permission_camera_qr_required">A QR-kódok beolvasásához kamerához való hozzáférés szükséges</string>
+    <string name="voice_action_title">Hangparancsok</string>
+    <string name="voice_action_body">A hangparancs feldolgozása</string>
+    <string name="permission_camera_photo_required">A fénykép készítéséhez kérjük, engedélyezze a kamerához való hozzáférést.</string>
+    <string name="global_search">Csevegések böngészése</string>
+    <string name="global_search_empty_view_text">Adjon meg legalább két karaktert az üzenetekben való kereséséhez</string>
+    <string name="my_id">Az én ID-m</string>
+    <string name="profile_picture_and_nickname">Profilkép és becenév</string>
+    <string name="lp_select_this_place">Ez a helyszín kiválasztása</string>
+    <string name="lp_or_select_nearby">Vagy válasszon egy közeli helyszínt</string>
+    <string name="lp_use_this_location">Helyszín elküldése?</string>
+    <string name="lp_search_place">Helyszín megadása</string>
+    <string name="lp_no_nearby_places_found">Nem találtunk a közelben ilyen helyet</string>
+    <string name="select_directory_for_backup">Mentés ide</string>
+    <string name="data_backup_headline">Hozzon létre biztonsági mentést az összes adat, csevegés és médiáról.</string>
+    <string name="data_backup_save_path">Biztonsági mentés útvonala</string>
+    <string name="change">Módosítás</string>
+    <string name="data_backup_last_date">Utolsó sikeres biztonsági mentés</string>
+    <string name="archived">Archív</string>
+    <string name="to_archive">Archiválás</string>
+    <string name="message_archived">%d csevegés archiválva</string>
+    <string name="archived_chats">Archivált csevegések</string>
+    <string name="unarchive">Archívból törlés</string>
+    <string name="no_archived_chats">Nincsenek archivált csevegések.\nHúzzon balra egy csevegést a csevegési listában az archiválásához.</string>
+    <string name="add_contact_enter_id_hint">Kérjük, adja meg a hozzáadni kívánt kapcsolat Threema ID-ját.</string>
+    <string name="notification_channel_new_contact">Új névjegyek</string>
+    <string name="notification_channel_new_contact_desc">Értesítés új névjegyekről</string>
+    <string name="notification_contact_has_joined">%1$s most %2$s-nél van. Kattintson ide egy üzenet elküldéséhez.</string>
+    <string name="notification_contact_has_joined_multiple">%1$d kapcsolata most %2$s: %3$s-nél van. Kattintson ide egy üzenet küldéséhez.</string>
+    <string name="system_default">Rendszer alapértelmezett</string>
+    <string name="open_in_maps_app">Megnyitás a Térképalkalmazásban</string>
+    <string name="delete">Törlés</string>
+    <string name="num_archived_chats">%d archivált csevegés</string>
+    <string name="continue_recording">Felvétel folytatása</string>
+    <string name="tap_to_start">Kattintson ide a %s indításához.</string>
+    <string name="two_years">2 év</string>
+    <string name="invalid_backup_path">Érvénytelen mentési útvonal</string>
+    <string name="backup_data_no_permission">Nincs író hozzáférés ehhez a könyvtárhoz. Kérjük, válasszon egy másikat.</string>
+    <string name="prefs_sum_show_unread_badge">Jelvények megjelenítése a navigációs fülön</string>
+    <string name="prefs_title_show_unread_badge">Jelvények</string>
+    <string name="pinning_not_trusted">A tanúsítvány nem ellenőrizhető. Győződjön meg róla, hogy az «Entrust Root Certification Authority - G2» biztonsági tanúsítvány telepítve és aktiválva van a telefon tanúsítványtárolójában..</string>
+    <string name="pinning_failed">A tanúsítvány nem ellenőrizhető. Lehetséges man-in-the-middle támadás. Ha telepítve van egy reklámblokkoló, tartalomszűrő vagy tűzfal alkalmazás, mint például az \"AdGuard\", tiltsa le a Threema számára.</string>
+    <string name="open_myid_popup">Felugró ablak megnyitása a gyorsválasztóhoz</string>
+    <string name="logo">Logó / Görgessen a tetejére</string>
+    <string name="quote_subj_end">Idézet vége</string>
+    <string name="quote_subj">Idézet</string>
+    <string name="duration">Időtartam</string>
+    <string name="seconds">Másodperc</string>
+    <string name="minutes">Perc</string>
+    <string name="and">és</string>
+    <string name="edit_type_content_description">%1$s %2$s megjelenítése vagy szerkesztése</string>
+    <string name="group">Csoport</string>
+    <string name="send_location_privacy_policy_v4_0"><![CDATA[<p>Adatvédelmi szabályzatunk a következő változásnak megfelelően módosult:</p><p>%1$s már nem függ a Google Play és a Google Maps térkép- és OVI-adatoktól.</p>Kérjük, tekintse meg a teljes adatvédelmi szabályzatot <a href="%2$s">itt</a>.]]></string>
+    <string name="play_services_not_installed_unable_to_use_push">A szolgáltatás nincs telepítve. Nem lehet «Push»-ra váltani.</string>
+    <string name="unable_to_get_current_location">Nem tudjuk meghatározni az aktuális pozíciót.</string>
+    <string name="lp_search_place_min_chars">Kérjük, legalább 3 karaktert adjon meg a helykereséshez.</string>
+    <string name="lp_search_place_no_matches">Nincs megfelelő helyszín. Kérjük, módosítsa a keresést.</string>
+    <string name="wallpaper_default">Alapértelmezett háttérkép</string>
+    <string name="wallpaper_gallery">Galériából választ</string>
+    <string name="wallpaper_none">Nincs háttérkép</string>
+    <string name="wallpaper_threema">%s-háttérkép</string>
+    <string name="message_id">Üzenet-ID</string>
+    <string name="mime_type">MIME-Típus</string>
+    <string name="password_does_not_comply">A megadott jelszó nem felel meg az irányelveknek.</string>
+    <string name="audio_mute_due_to_focus_loss">A hangfókusz elvesztése miatt átmenetileg elnémult a hang</string>
+    <string name="restore_data_backup_explain">Az adatmentés visszaállításához először törölje Threema ID-ját a «saját profil» oldalon.\n\nAmikor az alkalmazás újraindul, válassza a «Biztonsági mentés visszaállítása», «További visszaállítási lehetőségek», «Adatmentés» lehetőséget, és a fájlkeresőben kattintson a visszaállítani kívánt adatmentésre.</string>
+    <string name="audio_focus_loss_complete">A hívás a hangfókusz teljes elvesztése miatt véget ért.</string>
+    <string name="tap_for_picture_hold_for_video">Fényképhez megérintés, videóhoz nyomva tartás</string>
+    <string name="sending_media">Médiá(k) elküldése</string>
+    <string name="permission_record_video_audio_required">Kérjük, engedélyezze a mikrofon használatát a hanggal ellátott videó rögzítéséhez</string>
+    <string name="media_files">Fájlok</string>
+    <string name="auto_download_limit_explain">A %s-nál nagyobb videók és fájlok mindig igény szerint kerülnek letöltésre</string>
+    <string name="quoted_message_deleted">Az idézett üzenet már nem elérhető</string>
+    <string name="searching">Keressük…</string>
+    <string name="prefs_work_life_balance">Ne zavarjanak</string>
+    <string name="prefs_title_working_days">Munkanapok</string>
+    <string name="prefs_working_days_sum">Válassza ki a munkanapokat</string>
+    <string name="prefs_work_time_start">Munkakezdet</string>
+    <string name="prefs_work_time_start_sum">Állítsa be a munka kezdetét</string>
+    <string name="prefs_work_time_end">Munka vége</string>
+    <string name="prefs_work_time_end_sum">Állítsa be a munka végét</string>
+    <string name="prefs_working_days_enable_title">Pihenőidő-politika</string>
+    <string name="prefs_working_days_enable_sum">Ne jelenítsen meg értesítéseket és utasítsa el a Threema hívásokat munkaidőn kívül</string>
+    <string name="work_life_dnd_active">Pihenőidő aktív</string>
+    <string name="pencil">Ceruza</string>
+    <string name="warning">Figyelmeztetés</string>
+    <string name="password_remember_warning">Ne feledje, mit ír be ide! Mivel a %s nem tárolja a jelszavakat a kiszolgálón, nem tudunk segíteni, ha elfelejtette a PIN-kódot vagy a jelszót.</string>
+    <string name="safe_backup_tap_to_restart">Kattintson a megjelenő rendszerértesítésre az alkalmazás újraindításához. Ha nem látja az értesítést, kérjük húzza le a telefonján az értesítési sávot.</string>
+    <string name="send_to_support">Küldés a Threema ügyfélszolgálatnak</string>
+    <string name="menu_legal">Jogi</string>
+    <string name="tooltip_work_hint">Ez a névjegy a Threema Work-ot használja.</string>
+    <string name="video_camera_on">Videokamera be</string>
+    <string name="video_camera_off">Videokamera ki</string>
+    <string name="enable_picture_in_picture">Kép-a-képben üzemmód indítása</string>
+    <string name="call_with">%s felhívása</string>
+    <string name="picture_in_picture_disabled_in_setting">A kép a képben funkciót kikapcsolták a %s-hoz. Kérjük, aktiválja a mobiltelefon beállításaiban.</string>
+    <string name="delete_everything">Minden törlése</string>
+    <string name="prefs_title_voip_video_enable">Videóhívások engedélyezése</string>
+    <string name="video_calls">Videóhívások</string>
+    <string name="prefs_videocall_profile">Preferált képminőség</string>
+    <string name="videocall_profile_auto">Kiegyensúlyozott (ajánlott)</string>
+    <string name="videocall_profile_low_bandwidth">Alacsony adatfogyasztás</string>
+    <string name="videocall_profile_max_quality">Maximális minőség</string>
+    <string name="unable_to_play_video">A videó nem játszható le</string>
+    <string name="tooltip_voip_turn_on_camera">Kattintson ide a kamera bekapcsolásához</string>
+    <string name="prefs_videocall_profile_explain">A tényleges képminőség a hálózattól és a másik fél beállításaitól függ</string>
+    <string name="permission_camera_videocall_required">Aktiválja a kamera engedélyt a videóhívásokhoz</string>
+    <string name="feedback">Visszajelzés</string>
+    <string name="tooltip_voip_enable_speakerphone">Kattintson ide a beszélgetés kihangosításához</string>
+    <string name="ballot_open">Nyílt szavazások</string>
+    <string name="translators">Fordítók</string>
+    <string name="credits">Köszönetnyilvánítás</string>
+    <string name="translators_thanks">Köszönet önkéntes fordítóinknak:\n%s</string>
+    <string name="ballot_window_hide">Nyílt szavazások elrejtése</string>
+    <string name="ballot_window_show">Nyílt szavazások megjelenítése</string>
+    <string name="tooltip_voip_other_party_video_on">Beszélgetőpartnere videóhívást indított. Kattintson ide a kamera bekapcsolásához is.</string>
+    <string name="tooltip_voip_other_party_video_disabled">Beszélgetőpartnere nem az aktuális alkalmazásverziót használja, vagy nem engedélyezi a videóhívásokat.</string>
+    <string name="biometrics_not_enrolled">A rendszer nem tárol biometrikus adatokat.</string>
+    <string name="biometrics_not_avilable">Biometrikus hitelesítés nem áll rendelkezésre.</string>
+    <string name="biometrics_no_permission">Nincs felhatalmazás a biometrikus adatokhoz való hozzáférésre.</string>
+    <string name="verification_settings_desc">A pontok a kapcsolat bizalmi szintjét jelzik.</string>
+    <string name="verification_levels_title">Bizalmi szintek</string>
+    <string name="work_verification_levels_title">Névjegyek az Ön szervezetében</string>
+    <string name="external_verification_levels_title">Egyéb névjegyek</string>
+    <string name="switch_flash">Vakumód váltása</string>
+    <string name="message_not_found">Az üzenet nem található</string>
+    <string name="insert_datetime">Dátum és idő beillesztése</string>
+    <string name="prefs_sum_disable_smart_replies">Válaszjavaslatok letiltása az Android értesítésekben</string>
+    <string name="prefs_title_disable_smart_replies">Válaszjavaslatok letiltása</string>
+    <string name="url_warning_body_alt">A weboldal, amelyet megnyitni próbál, gyanús.\n\nLehet, hogy egy hamis weboldalra próbálják átirányítani Önt.\n\nMégis folytatni szeretné?</string>
+    <string name="read_on">Bővebben…</string>
+    <string name="forward_text">Szöveg továbbítása</string>
+    <string name="an_error_occurred_during_send">Hiba történt egy vagy több üzenet küldése közben.</string>
+    <string name="state_processing">feldolgozás alatt</string>
+    <string name="passphrase_locked">A jelszó blokkolva van</string>
+    <string name="selected_media">Az Ön választása</string>
+    <string name="attach_gif">Gif</string>
+    <string name="attach_gallery">Galéria</string>
+    <string name="attach_picture">Kép</string>
+    <string name="attach_video">Videó</string>
+    <string name="attach_location">Helyszín</string>
+    <string name="filter_by_album">Szűrés média album szerint</string>
+    <string name="media_date_taken">Felvétel dátuma: %s</string>
+    <string name="media_date_added">Hozzáadás dátuma: %s</string>
+    <string name="media_date_modified">Módosítás dátuma: %s</string>
+    <string name="media_date_unknown">Ismeretlen dátum</string>
+    <string name="max_selectable_media_exceeded">Egyszerre legfeljebb %d objektum küldhető.</string>
+    <string name="error_unable_loading_media_thumb">Az előnézet nem tölthető be</string>
+    <string name="select">Kiválaszt</string>
+    <string name="filter_list">Lista szűrése</string>
+    <string name="hint_filter_list">Szűrő kifejezés megadása</string>
+    <string name="add">Hozzáadás</string>
+    <string name="threema_message_from">Üzenet %s-től</string>
+    <string name="show_text">Szöveg megjelenítése</string>
+    <string name="only_images_or_videos">Csak képek és videók választhatók ki</string>
+    <string name="media_gallery_gifs">GIF-ek</string>
+    <string name="no_media_found_global">Nem találtunk médiát ezen az eszközön</string>
+    <string name="enable_formatting">Formázás engedélyezése</string>
+    <string name="original_file_no_longer_avilable">Nincs többé hozzáférés az eredeti fájlhoz. Kérjük, küldje el újra ezt az üzenetet.</string>
+    <string name="state_transcoding">átkódolás alatt</string>
+    <string name="importing_files">Fájlok importálása folyamatban</string>
+    <string name="tooltip_image_resolution_hint">A képfelbontás testreszabásához kattintson ide.</string>
+    <string name="ballot_created_successfully">A szavazás sikeresen elkészült.</string>
+    <string name="file_size">Fájlméret</string>
+    <!-- Abbreviation for "30 days", shown at the bottom of the contact list -->
+    <string name="thirty_days_abbrev">30n</string>
+    <string name="show_in_chat">Megjelenítés a csevegésben</string>
+    <string name="group_create_no_members">Biztos, hogy üres csoportot szeretne létrehozni?</string>
+    <string name="notes">Megjegyzések</string>
+    <string name="blur_faces">Arcok elmosása</string>
+    <string name="brush">Ecset</string>
+    <string name="error_detecting_faces">Hiba történt az arcfelismerés során</string>
+    <string name="no_faces_detected">Nem találtunk arcokat</string>
+    <string name="smiley">Smiley</string>
+    <string name="blur">Elmosás</string>
+    <string name="face_blur_tooltip_title">Új: Arcfelismerés</string>
+    <string name="face_blur_tooltip_text">Keress arcokat a képen, és homályosítsd el őket, vagy fedd le egy smileyval.</string>
+    <string name="listened_to">meghallgatva</string>
+    <string name="transcoder_unsupported_audio_format">A hangformátum konvertálása a rendszer támogatásának hiánya miatt nem sikerült.</string>
+    <string name="transcoder_unknown_audio_error">A hangformátum konvertálása ismeretlen hibával megszakadt.</string>
+    <string name="video_size_explain">A nagyon nagyméretű videók tömörítésre kerülnek, így ettől a beállítástól függetlenül elküldhetők.</string>
+    <string name="status_create_notes">*Egyedül vagy itt*\nEzt a csevegést biztonságos jegyzetfüzetként használhatod szövegek, médiaanyagok és dokumentumok számára.</string>
+    <string name="status_create_notes_off">*Nem vagy többé egyedül ebben a csevegésben*\nAz új üzeneteket a csoport minden tagjának elküldjük.</string>
+    <string name="note_group_howto">Tipp: Ha nem ad hozzá tagokat, a csoportba küldött üzenetek helyben maradnak. Ez ideális jegyzetek, médiatartalmak vagy dokumentumok biztonságos tárolására vagy az asztalra történő átvitelére.</string>
+    <string name="mark_unread">Olvasatlannak jelölni</string>
+    <string name="mark_read_short">Olvasva</string>
+    <string name="unread">Olvasatlan</string>
+    <string name="missing_app_licence">Az App Store nem tudta ellenőrizni az alkalmazás licencét. Ha a Google Play alkalmazást használja, törölje a Google Play Store alkalmazás adatait, és indítsa újra a telefonját.</string>
+    <string name="set_backup_path">Biztonsági mentés helyének beállítása</string>
+    <string name="set_backup_path_intro">A következő képernyőn válassza ki azt a mappát, ahová az adatmentéseket tenni kívánja.</string>
+    <string name="discard_changes_title">Változások elvetése</string>
+    <string name="group_join_request_message_info"><![CDATA[Írjon egy rövid üzenetet <b>%1$s</b> adminnak, hogy miért szeretne csatlakozni az <b>%2$s</b>-hoz.]]></string>
+    <string name="group_join_request">Csoportkérelem</string>
+    <string name="group_join_request_for">Csoportkérelem %s számára</string>
+    <string name="group_link_default_name">Ismeretlen link</string>
+    <string name="group_link_share">Csoport link megosztása</string>
+    <string name="group_request_incoming_dialog_title">Kérelem %s-tól</string>
+    <string name="accept">Elfogad</string>
+    <string name="reject">Elutasít</string>
+    <string name="group_request_already_sent"><![CDATA[Már van egy nyitott kérelme <b>%s</b> számára, és a csoportadminisztrátor válaszára vár. Kattintson a listában a kérelemre, ha újra el szeretné küldeni a kérelmet.]]></string>
+    <string name="group_link_none">Még nem generált linket</string>
+    <string name="group_request_confirm_send"><![CDATA[Csoportkérelmet készül küldeni <b>%1$s</b> számára <b>%2$s</b> adminisztrátornak. Ha ez a link időközben nem lett érvénytelenítve, akkor Önt hozzáadjuk a csoporthoz, amint az admin eszköze elérhetővé válik.]]></string>
+    <string name="really_delete_outgoing_request">Tényleg törölni akar %d csoportkérelmet? Ne feledje, hogy a nyitott kérelmet nem vonják vissza, és később is felvehetik a csoportba.</string>
+    <string name="really_delete_group_request_title">Tényleg törölné a csoportkérelmet?</string>
+    <string name="sent_to">Ide küldve: %s</string>
+    <string name="sent_on">Elküldve: %s</string>
+    <string name="group_response">Válasz a csoportkérelemre</string>
+    <string name="group_response_accepted">A %s csoportra vonatkozó kérelmét elfogadták.</string>
+    <string name="group_response_full">A %s csoportra vonatkozó kérelmét elutasították, mivel a csoport már megtelt.</string>
+    <string name="group_response_rejected">A %s csoportra vonatkozó kérelmét elutasították.</string>
+    <string name="group_link_expiration_none">Korlátlan</string>
+    <string name="group_request_hint">Szia, én vagyok…</string>
+    <string name="group_request_send_title">Csoportkérelem küldése</string>
+    <string name="group_request_message_empty">Az adminisztrátornak küldött üzenet nem lehet üres!</string>
+    <string name="group_requests_all_title">Összes csoportkérelem</string>
+    <string name="group_requests_none_outgoing">Nem küldött csoportkérelmet. A kérelmeket csoporthivatkozásokon keresztül lehet elküldeni.</string>
+    <string name="notification_channel_group_join_response">Értesítés a csoportkérelmekre adott válaszokról</string>
+    <string name="group_qr_code_title">Csoport QR-kód</string>
+    <string name="group_link_qr_desc"><![CDATA[Ossza meg ezt a linket azokkal, akiket szeretne meghívni az <b>%s</b> csoportba.]]></string>
+    <string name="new_group_link_success">Új link hozzáadva</string>
+    <string name="link_administration_off_explain">Ezt a linket már megosztották, és nyilvános. Az adminisztráció utólag nem módosítható. Egyszerűen hozzon létre egy új linket a kívánt opcióval.</string>
+    <string name="group_link_update_success">Link frissítés sikeres</string>
+    <string name="no_group_links">Nincsenek csoporthivatkozások. Csoporthivatkozások létrehozásához kattintson a \"Link létrehozása\" gombra, vagy aktiválja az alapértelmezett linket a csoport áttekintésében.</string>
+    <string name="really_delete_group_link">Tényleg törölni szeretne %d csoporthivatkozást? A törlés után a felhasználók már nem küldhetnek érvényes kérelmeket. A már beérkezett kérelmeket azonban továbbra is el lehet fogadni vagy el lehet utasítani.</string>
+    <string name="group_links_overview_title">Csoporthivatkozások %s számára</string>
+    <string name="group_link_invalid">Lejárt</string>
+    <string name="group_link_valid">Érvényes</string>
+    <string name="open_group_requests_chips_title">Nyitott csoportkérelmek</string>
+    <string name="all_open_group_requests">Összes csoportkérelem</string>
+    <string name="no_incoming_group_requests">Még nincsenek bejövő csoportkérelmek. Ezeket csoporthivatkozásokként küldhetik el Önnek, amelyeket a csoport adatainak nézetében kezelhet, ha Ön az adminisztrátor.</string>
+    <string name="received_on">Beérkezett %s-kor</string>
+    <string name="group_request_state_full">Csoport teli</string>
+    <string name="group_request_state_rejected">Visszautasítva</string>
+    <string name="group_request_state_expired">Lejárt</string>
+    <string name="group_request_state_pending">Függőben</string>
+    <string name="group_request_state_accepted">Elfogadva</string>
+    <string name="open_group_requests_show">Csoportkérelmek mutatása</string>
+    <string name="open_group_requests_hide">Csoportkérelmek elrejtése</string>
+    <string name="group_request_link_already_deleted">Csoporthivatkozás már törölve</string>
+    <string name="really_delete_incoming_request">Tényleg törölni akar %d csoportkérelmeket? A törlés után többé nem tudsz válaszolni rájuk.</string>
+    <string name="incoming_group_request_no_message">Nyitott hivatkozáson keresztül küldték… Nincs üzenet</string>
+    <string name="group_request_received_through">Hivatkozáson keresztül: %s</string>
+    <string name="reaccept">Újra elfogad</string>
+    <string name="group_link_edit_expiration_date">Lejárati idő megadása</string>
+    <string name="group_link_show_qr">QR-kód megjelenítése</string>
+    <string name="group_link_rename">Hivatkozás átnevezése</string>
+    <string name="group_link_rename_tag">Új név</string>
+    <string name="tap_here_for_more">További információért kattintson ide</string>
+    <string name="another_connection_instructions">A kiszolgáló két vagy több különböző eszközről származó, azonos Threema ID-vel rendelkező kapcsolatot észlelt.\n\nEgy Threema ID-t nem lehet egyszerre több eszközön használni. Az új üzenetek csak arra az eszközre kézbesülnek, amelyik legutóbb bejelentkezett a kiszolgálóra.\n\nHa új eszközre vált, kérjük, távolítsa el vagy deaktiválja a %s-t a régi eszközön, majd indítsa újra az új eszközt.</string>
+    <string name="app_store_error_code">App Store hibakód: %d</string>
+    <string name="backup_restore_type"><![CDATA[Milyen típusú másolatot szeretne visszaállítani? <br/><br/> <a href=%s>Tudjon meg többet a Threema biztonsági mentésekről</a>]]></string>
+    <string name="data_backup_info">Mindent visszaállít, csevegésekkel</string>
+    <string name="new_to_threema">Új a %s-nál?</string>
+    <string name="back_to_threema">Visszatért a %s-hoz?</string>
+    <string name="id_backup_info">Csak az ID helyreállítása</string>
+    <string name="restore_your_id_contacts_and_groups">ID, kapcsolatok és csoportok visszaállítása</string>
+    <string name="threema_safe_backup">Threema Safe biztonsági mentés</string>
+    <string name="forgot_your_password"><![CDATA[<a href=%s>Elfelejtette a jelszót?</a>]]></string>
+    <string name="download_failed">Letöltés sikertelen. Hibakód: %d</string>
+    <string name="share_media">Megosztás más alkalmazással…</string>
+    <string name="group_link_administered">Adminisztrált</string>
+    <string name="group_link_open">Nyílt</string>
+    <string name="group_link_share_message">Csatlakozz a Threema csoportomhoz az alábbi hivatkozáson keresztül: %s</string>
+    <string name="group_link_bottom_sheet_title">Csoporthivatkozás</string>
+    <string name="group_link_bottom_sheet_desc">Ossza meg ezt a hivatkozást azokkal, akiket meg szeretne meghívni. Vegye figyelembe az alábbi beállításokat</string>
+    <string name="group_link_bottom_sheet_link_title">Hivatkozás</string>
+    <string name="group_link_properties_title">Hivatkozás tulajdonságok</string>
+    <string name="group_link_property_administration_title">Kézi megerősítés</string>
+    <string name="group_link_property_administration_desc">Ha engedélyezve van, akkor a csoportban kapja meg a kérelmeket, és egyenként megerősítheti azokat.</string>
+    <string name="group_link_property_expiration_title">Lejárati idő</string>
+    <string name="group_link_property_expiration_desc">A hivatkozás a megadott dátum után érvénytelenné válik.</string>
+    <string name="group_image">Csoportkép</string>
+    <string name="add_group_link">Tagok hozzáadása csoporthivatkozásokkal</string>
+    <string name="miui_battery_optimization">Kérjük, kapcsolja ki az \"Akkumulátor optimalizálás\" opciót a %s-hoz, hogy lehetővé tegye ezt a funkciót. Mivel a Xiaomi nem tartja szükségesnek az Android szabványok betartását, ezt kézileg kell megtennie a telefon beállításaiban. Az akkumulátor-optimalizálás letiltásával kapcsolatos segítségért forduljon a Xiaomi ügyfélszolgálatához.</string>
+    <string name="forward_captions">Küldje el a címkéket is</string>
+    <string name="importing_files_failed">A biztonsági mentési fájl importálása sikertelen. Győződjön meg róla, hogy elegendő szabad tárhely van.</string>
+    <string name="label_continue">Tovább</string>
+    <string name="select_date">Dátum kiválasztása</string>
+    <string name="select_time">Idő kiválasztása</string>
+    <string name="send_to">Küldés ide: %s</string>
+    <string name="receipts_override_choice_send">Küldjön</string>
+    <string name="receipts_override_choice_dont_send">Ne küldjön</string>
+    <string name="receipts_override_choice_default">Alapértelmezett (%s)</string>
+    <string name="unable_to_determine_recording_length">A felvétel üres vagy a hossza nem határozható meg</string>
+    <string name="prefs_header_receipts">Visszaigazolások</string>
+    <string name="prefs_title_reset_receipts">Egyedi beállítások visszaállítása</string>
+    <string name="prefs_sum_reset_receipts">Az olvasási bizonylatok és a «jelentés, amikor írok» kapcsolatspecifikus beállításainak alapértelmezettre állítása</string>
+    <string name="reset_successful">Alapértelmezett beállításokat sikeresen visszaállítva</string>
+    <string name="group_link_add">Hivatkozás létrehozása</string>
+    <string name="group_requests_show_menu_title">Nyitott csoportkérelmek megjelenítése</string>
+    <string name="group_request_show_all">Összes csoportoskérelem megjelenítése</string>
+    <string name="group_links_manage_menu">Csoporthivatkozások kezelése</string>
+    <string name="group_request_sent_menu">Elküldött csoportkérelem</string>
+    <string name="really_delete_group_link_title">Csoporthivatkozások törlése</string>
+    <string name="qr_scan_result_dialog_title">QR beolvasás eredmény</string>
+    <string name="scan_failure_dialog_title">Sikertelen beolvasás</string>
+    <string name="no_threema_qr_info">Ez nem egy Threema QR-kód, a dekódolt tartalma:</string>
+    <string name="default_group_link">Alapértelmezett csoporthivatkozás</string>
+    <string name="default_link_name">Alapértelmezett hivatkozás</string>
+    <string name="reset_default_group_link">Csoporthivatkozás visszaállítása</string>
+    <string name="resend">Újra elküldeni</string>
+    <string name="group_request_already_sent_title">Csoportkérelem már elküldve</string>
+    <string name="qr_scanner_id_hint">Egy másik névjegy QR-kódjának beolvasásával ellenőrizheti őt. A QR-kód a Threema főképernyő bal felső sarkában lévő profilképre kattintva tekinthető meg.</string>
+    <string name="enable_storage_access_for_media">Aktiválja a tárhelyelérést a képek és videók megtekintéséhez</string>
+    <string name="take_me_there">Aktiváld most…</string>
+    <string name="notification_channel_group_join_request">Értesítések a csoportkérelmekről</string>
+    <string name="reset_default_group_link_title">Visszaállítás-infó</string>
+    <string name="reset_default_group_link_desc">A korábban megosztott hivatkozás érvénytelenné válik, és a régi linken keresztül érkező kérelmeket automatikusan elutasítjuk.</string>
+    <string name="custom">továbbiak</string>
+    <string name="show_public_key">Nyilvános kulcs megjelenítése</string>
+    <string name="public_key_for">%s nyilvános kulcsa</string>
+    <string name="copied">Másolva</string>
+    <string name="no_votes_yet">Még nem adtak le szavazatot.</string>
+    <string name="permission_contacts_sync_required">A szinkronizáláshoz engedélyezze a névjegyekhez való hozzáférést.</string>
+    <string name="not_voted_user_list">Ezek a résztvevők nem szavaztak: %s</string>
+    <string name="invalid_onprem_id">Nincs érvényes Threema OnPrem-ID</string>
+    <string name="enable_unknown_sources">Telepítés nem lehetséges. Kérjük, engedélyezze a \"Ismeretlen alkalmazások telepítése\" opciót a %s-hoz.</string>
+    <string name="name_given">Utónév</string>
+    <string name="name_family">Vezetéknév</string>
+    <string name="name_prefix">Név előtagja</string>
+    <string name="name_middle">Második utónév</string>
+    <string name="name_suffix">Név utótagja</string>
+    <string name="full_name">Név</string>
+    <string name="phoneTypeCustom">Egyéni</string>
+    <string name="phoneTypeHome">Otthoni</string>
+    <string name="phoneTypeMobile">Mobil</string>
+    <string name="phoneTypeWork">Munkahelyi</string>
+    <string name="phoneTypePager">Személyhívó</string>
+    <string name="phoneTypeOther">Egyéb</string>
+    <string name="phoneTypeCar">Gépkocsi</string>
+    <string name="phoneTypeIsdn">ISDN</string>
+    <string name="phoneTypeOtherFax">Egyéb fax</string>
+    <string name="eventTypeCustom">Egyéni</string>
+    <string name="eventTypeBirthday">Születésnap</string>
+    <string name="eventTypeAnniversary">Évforduló</string>
+    <string name="eventTypeOther">Egyéb</string>
+    <string name="emailTypeHome">Otthoni</string>
+    <string name="emailTypeWork">Munkahelyi</string>
+    <string name="emailTypeOther">Egyéb</string>
+    <string name="postalTypeCustom">Egyéni</string>
+    <string name="postalTypeHome">Otthoni</string>
+    <string name="postalTypeWork">Munkahelyi</string>
+    <string name="postalTypeOther">Egyéb</string>
+    <string name="relationTypeCustom">Egyéni</string>
+    <string name="relationTypeChild">Gyermek</string>
+    <string name="relationTypeFriend">Ismerős</string>
+    <string name="relationTypeParent">Szülő</string>
+    <string name="relationTypeSpouse">Házastárs</string>
+    <string name="contact_property_key">"Kulcs"</string>
+    <string name="header_nickname_entry">"Becenév"</string>
+    <string name="organization_type">Szervezet</string>
+    <string name="messages_cannot_be_recovered">Az üzeneteket nem lehet visszaállítani.</string>
+    <plurals name="contacts_counter_label">
+        <item quantity="one">%d névjegyek</item>
+        <item quantity="other">%d névjegyek</item>
+    </plurals>
+    <plurals name="really_delete_thread_message">
+        <item quantity="one">Tényleg törölni szeretné a %d csevegést?</item>
+        <item quantity="other">Tényleg törölni szeretné az %d csevegéseket?</item>
+    </plurals>
+    <plurals name="sending_message_failed">
+        <item quantity="one">%1$d üzenet nem küldhető</item>
+        <item quantity="other">%1$d üzenet nem küldhető</item>
+    </plurals>
+    <plurals name="selection_counter_label">
+        <item quantity="one">%d kép kiválasztva</item>
+        <item quantity="other">%d kép kiválasztva</item>
+    </plurals>
 </resources>

+ 1 - 1
app/src/main/res/values-hu/voicemessage_strings.xml

@@ -7,4 +7,4 @@
 	<string name="cancel_recording">Felvétel törlése</string>
 	<string name="cancel_recording_message">Tényleg le akarja állítani és törölni a felvételt?</string>
 	<string name="stop">Leállítás</string>
-</resources>
+</resources>

+ 7 - 3
app/src/main/res/values-hu/voip_strings.xml

@@ -1,3 +1,4 @@
+<?xml version="1.0"?>
 <resources>
 	<string name="voip_title">Threema hívás</string>
 	<string name="voip_hangup">Letevés</string>
@@ -6,13 +7,19 @@
 	<string name="voip_switch_cam">Kamera átkapcsolása</string>
 	<string name="voip_switch_cam_front">Szelfi kamerára váltott</string>
 	<string name="voip_switch_cam_rear">Fő kamerára váltott</string>
+	<string name="voip_toggle_video">Videó üzemmód váltása</string>
 	<string name="voip_call_confirm">Szeretné felhívni %1$s-t?</string>
+	<string name="voip_error_call">Hiba a Threema hívás során</string>
 	<string name="voip_error_init_call">Híváshiba</string>
 	<string name="voip_notification_title">Threema hívás</string>
 	<string name="voip_notification_text">%1$s hívja</string>
+	<!-- Shown when starting a call, before the peer device is ringing -->
 	<string name="voip_status_initializing">Hívás indítása</string>
+	<!-- Shown when the callee has accepted the call and the connection is being established -->
 	<string name="voip_status_connecting">Csatlakoztatás</string>
+	<!-- Shown when a call is being disconnected -->
 	<string name="voip_status_disconnecting">Kapcsolat bontása</string>
+	<!-- Shown when the device of the callee is ringing -->
 	<string name="voip_status_ringing">Csöng</string>
 	<string name="voip_mic_enable">Mikrofon bekapcsolása</string>
 	<string name="voip_mic_disable">Némítás</string>
@@ -50,12 +57,9 @@
 	<string name="prefs_voip_reject_incoming_calls_title">Mobiltelefon-hívások elutasítása</string>
 	<string name="prefs_voip_reject_incoming_calls_summary">Bejövő mobiltelefon-hívások elutasítása Threema-hívás közben.</string>
 	<string name="voip_contact_not_found">A Threema nem talált elérhetőséget ehhez a számhoz.</string>
-	<string name="voip_toggle_video">Videó üzemmód váltása</string>
-	<string name="voip_error_call">Hiba a Threema hívás során</string>
 	<string name="voip_another_pstn_call">Hívás nem lehetséges. Egy telefonbeszélgetés már folyamatban van.</string>
 	<string name="voip_call_status_off_hours">Hívás munkaidőn kívül</string>
 	<string name="voip_peer_video_disabled">A másik fél letiltotta a videohívásokat.</string>
-
 	<!-- WebRTC debugger -->
 	<string name="voip_prefs_webrtc_debug">WebRTC diagnosztika</string>
 	<string name="voip_prefs_webrtc_debug_summary">Indítsa el ezt az eszközt a híváskapcsolati problémák diagnosztizálásához.</string>

+ 5 - 5
app/src/main/res/values-hu/webclient_strings.xml

@@ -4,17 +4,17 @@
 	<string name="webclient_init_session">Új munkamenet kezdése</string>
 	<string name="webclient_sessions_really_delete">Biztos, hogy törölni szeretné ezt a Threema webes munkamenetet?</string>
 	<string name="webclient_last_usage">Utoljára használva: %s</string>
-	<string name="webclient_active_since">Aktív: %s óta</string>
 	<string name="webclient_created_at">Létrehozva: %1$s (%2$s)</string>
+	<string name="webclient_active_since">Aktív: %s óta</string>
 	<string name="webclient_enable">Threema Webet aktiválás</string>
 	<string name="webclient_no_sessions_found">A csatlakozáshoz nyissa meg az internetböngészőt a számítógépén, és menjen a %s oldalra. Kattintson a lenti gombra a megjelenő kód beolvasásához.</string>
 	<string name="webclient_session_rename">Munkamenet átnevezése</string>
 	<string name="webclient_session_label">Új név</string>
 	<string name="webclient_session_start">Munkamenet megkezdése</string>
 	<string name="webclient_session_stop">Munkamenet megállítása</string>
-	<string name="webclient_unnamed_session">Névtelen munkamenet</string>
 	<string name="webclient_persistent">mentve</string>
 	<string name="webclient_disposable">nem mentve</string>
+	<string name="webclient_unnamed_session">Névtelen munkamenet</string>
 	<string name="webclient_session_remove">Munkamenet eltávolítása</string>
 	<string name="webclient_welcome_title">Csevegés a számítógépről</string>
 	<string name="webclient_welcome_explain">A Threema Web segítségével kényelmesen cseveghet számítógépéről vagy notebookjáról. Teljes körű hozzáférést biztosít az összes kapcsolatához, médiáihoz és beszélgetéseihez, beleértve a korábbi beszélgetéseket is.\n\n<b>A mobiltelefon és a számítógép közötti kommunikáció teljes mértékben végponttól végpontig titkosított</b> és közvetlen kapcsolatot használ, ha mindkét eszköz ugyanazon a hálózaton van.\n\nFigyelem: Ha a Threema Web aktív, az energiafogyasztás magasabb lehet. A funkciót azonban bármikor be- vagy kikapcsolhatja.</string>
@@ -30,13 +30,13 @@
 	<string name="webclient_really_start_webclient_by_payload_body">El akarja kezdeni ezt az munkamenetet most?</string>
 	<string name="webclient_cannot_restore">Nem lehet folytatni a munkamenetet</string>
 	<string name="webclient_disabled">Asztal/Web letiltva</string>
+	<string name="webclient_cannot_start">A Threema webes munkamenet nem indítható</string>
+	<string name="webclient_constrained_by_mdm">A szervert a rendszergazda nem engedélyezte.</string>
 	<string name="webclient_clear_all_sessions">Az összes munkamenet törlése</string>
 	<string name="webclient_clear_all_sessions_confirm">Tényleg törölni szeretné az összes Threema Web munkamenetet?</string>
 	<string name="webclient_prefs_debug_tool_summary">Eszköz a Threema webkapcsolat létrehozásával kapcsolatos problémák elemzésére</string>
 	<string name="webclient_diagnostics">Threema Web diagnózis</string>
 	<string name="webclient_diagnostics_start">Indítás</string>
-	<string name="webclient_diagnostics_intro">A teszt elindításához kattintson az "Indítás" gombra.</string>
+	<string name="webclient_diagnostics_intro">A teszt elindításához kattintson az \"Indítás\" gombra.</string>
 	<string name="webclient_diagnostics_done">Befejezve. Ha problémái vannak a Threema webkapcsolat létrehozásával, kérjük küldje el ezt a naplót a Threema ügyfélszolgálatának.</string>
-	<string name="webclient_cannot_start">A Threema webes munkamenet nem indítható</string>
-	<string name="webclient_constrained_by_mdm">A szervert a rendszergazda nem engedélyezte.</string>
 </resources>

+ 9 - 2
app/src/main/res/values-it/strings.xml

@@ -114,6 +114,7 @@
     <string name="copy_message_action">Copia</string>
     <string name="delete_contact_action">Cancella contatto</string>
     <string name="scan_id">Scansiona ID</string>
+    <string name="id_scanned">ID scansionato</string>
     <string name="id_mismatch">\"La chiave pubblica che hai scansionato non corrisponde alla chiave registrata dal server
 		per questo ID. Ciò significa che qualcuno ha modificato il codice scannerizzato. Sei pregato di non fidarti
 		assolutamente della chiave.</string>
@@ -278,7 +279,7 @@
     <string name="restore_data_password_msg">Inserisci la password utilizzata per creare questo backup.</string>
     <string name="backup_data_media">Comprende file multimediali di grandi dimensioni (video, documenti, immagini originali)</string>
     <string name="backup_data_new">Esegui nuovo backup</string>
-    <string name="pinentry_enter_pin">Inserisci codice PIN</string>
+    <string name="pinentry_enter_pin">Inserisci codice PIN %s</string>
     <string name="pinentry_wrong_pin">Codice PIN errato</string>
     <string name="prefs_sum_security_pin">Bloccare l\'accesso all\'interfaccia utente di Threema</string>
     <string name="prefs_title_pin_switch">Protezione dell\'App</string>
@@ -529,7 +530,6 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
     <string name="file_placeholder">File</string>
     <string name="internal_storage">Memoria interna</string>
     <string name="no_activity_for_mime_type">Non è stata trovata alcuna app per aprire questo file.</string>
-    <string name="message_copied">Messaggio copiato</string>
     <string name="open_from">Apri da</string>
     <string name="file_one_contact_not_supported">%1$s non può ricevere file.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Attenzione: %1$d contatti non possono ricevere il tuo file.</string>
@@ -652,6 +652,7 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
     <string name="new_wizard_info_fingerprint">Muovendo il dito andrai a creare dati casuali (si parla di \"entropia\") utilizzati per generare la coppia di chiavi associata al nuovo e unico Threema ID.</string>
     <string name="new_wizard_info_id">Hai creato anche una coppia di chiavi. La chiave pubblica è stata trasmessa ai nostri server in modo sicuro. La chiave privata non abbandonerà mai il tuo dispositivo. In questo modo, nessun altro potrà leggere i tuoi messaggi.</string>
     <string name="new_wizard_info_sync_contacts">Attivando questa opzione, Threema utilizzerà la crittografia unidirezionale (hashing) per crittografare indirizzi e-mail e numeri di telefono prima di inviarli al server e cercare i contatti corrispondenti. I dati relativi alla rubrica non vengono salvati.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">Sincronizzando i contatti puoi trovare automaticamente i tuoi amici. Se accetti le condizioni, i numeri di cellulare e gli indirizzi e-mail della tua rubrica saranno inviati al nostro server in modo criptato, dove saranno paragonati per trovare i contatti adatti. I dati non saranno né salvati né inoltrati a terzi.\n\nVuoi attivare la sincronizzazione dei contatti?</string>
     <string name="new_wizard_info_link">Se indichi numero di telefono e indirizzo e-mail, potremo aiutare i tuoi amici a trovarti su Threema automaticamente. Queste informazioni verranno conservate in maniera sicura e anonima. Saltando questo passaggio utilizzerai Threema in modo totalmente anonimo.</string>
     <string name="new_wizard_info_link_phone_only">Se indichi il tuo numero di telefono, potremo aiutare i tuoi amici a trovarti su Threema automaticamente. Il numero verrà conservato in maniera sicura e anonima. Saltando questo passaggio utilizzerai Threema in modo totalmente anonimo.</string>
     <string name="new_wizard_info_nickname">Il nickname viene utilizzato nelle notifiche push su alcuni dispositivi o come strumento aggiuntivo di identificazione per gli utenti che non ti hanno in rubrica. Consigliamo di inserire soltanto il nome o uno pseudonimo. Se non imposti il nickname, utilizzeremo il Threema ID come impostazione predefinita.</string>
@@ -1399,6 +1400,8 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
     <string name="last_added_contact">Ultimo contatto aggiunto</string>
     <string name="directory_explain_text">Cerca nell\'indice dell\'impresa tutti i collaboratori che ancora non figurano nella tua rubrica.</string>
     <string name="cannot_display_location">Questo luogo non può essere visualizzato.</string>
+    <string name="unable_to_restore_identity_because">Impossibile ripristinare l\'ID. Motivo: %s</string>
+    <string name="share_with_app">Condividi con Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contatto</item>
         <item quantity="other">%d contatti</item>
@@ -1415,4 +1418,8 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
         <item quantity="one">%d immagine selezionata</item>
         <item quantity="other">%d immagini selezionate</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one">Messaggio copiato</item>
+        <item quantity="other">Messaggi copiati</item>
+    </plurals>
 </resources>

+ 2 - 1
app/src/main/res/values-ja/strings.xml

@@ -110,6 +110,7 @@
     <string name="copy_message_action">コピー</string>
     <string name="delete_contact_action">連絡先を削除する</string>
     <string name="scan_id">IDをスキャン</string>
+    <string name="id_scanned">IDをスキャンしました</string>
     <string name="id_mismatch">スキャンした公開鍵が、サーバーが保存しているこのIDの鍵と一致しません。
 これは、誰かがスキャンしたコードを操作したことを意味し、その鍵を信用してはいけないということになります。</string>
     <string name="scan_successful">IDが正常にスキャンされ、連絡先が確認されました。</string>
@@ -512,7 +513,6 @@ https://myid.threema.ch/revoke に入力することで ID を削除すること
     <string name="file_placeholder">ファイル</string>
     <string name="internal_storage">内部容量</string>
     <string name="no_activity_for_mime_type">このファイルを開くためのアプリが見つかりませんでした</string>
-    <string name="message_copied">メッセージがコピーされました</string>
     <string name="open_from">で開く</string>
     <string name="file_one_contact_not_supported">%1$sファイルを受信できません</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">警告: %1$d 連絡先がファイルを受信できません。</string>
@@ -1225,6 +1225,7 @@ https://myid.threema.ch/revoke に入力することで ID を削除すること
     <string name="header_nickname_entry">"ニックネーム"</string>
     <string name="organization_type">組織</string>
     <string name="messages_cannot_be_recovered">削除後はメッセージを復元することはできません。</string>
+    <string name="share_with_app">Threemaで共有</string>
     <plurals name="contacts_counter_label">
         <item quantity="other">%d 連絡先</item>
     </plurals>

+ 8 - 1
app/src/main/res/values-nl-rNL/strings.xml

@@ -112,6 +112,7 @@
     <string name="copy_message_action">Kopiëren</string>
     <string name="delete_contact_action">Contactpersoon verwijderen</string>
     <string name="scan_id">ID scannen</string>
+    <string name="id_scanned">ID gescand</string>
     <string name="id_mismatch">De openbare sleutel die u hebt gescand komt niet overeen met een sleutel die op de server is opgeslagen voor dit ID. Dit betekent dat iemand de gescande code heeft gemanipuleerd en dat de sleutel niet betrouwbaar is.</string>
     <string name="scan_successful">De ID is gescand en de contactpersoon is geverifieerd.</string>
     <string name="scan_duplicate">Dit ID is al gescand en geverifieerd.</string>
@@ -512,7 +513,6 @@ Voer een vraag in voor uw poll.</string>
     <string name="file_placeholder">Bestand</string>
     <string name="internal_storage">Interne opslag</string>
     <string name="no_activity_for_mime_type">Geen app gevonden om dit bestand te openen.</string>
-    <string name="message_copied">Bericht gekopieerd</string>
     <string name="open_from">Openen vanaf</string>
     <string name="file_one_contact_not_supported">%1$s kan geen bestanden ontvangen.</string>
     <string name="file_x_contact_not_supported" tools:ignore="PluralsCandidate">Waarschuwing: %1$d contactpersonen kunnen uw bestand niet ontvangen.</string>
@@ -635,6 +635,7 @@ Voer een vraag in voor uw poll.</string>
     <string name="new_wizard_info_fingerprint">Door uw vinger te bewegen maakt u een willekeurig patroon aan (entropie) dat wordt gebruikt om een sleutelpaar aan te maken dat wordt gekoppeld aan uw nieuwe unieke Threema ID. Het sleutelpaar bestaat uit een <b>openbare sleutel</b> die aan uw vrienden wordt gestuurd en een <b>privésleutel</b> die veilig wordt opgeslagen op uw telefoon. Uw vrienden kunnen boodschappen aan u versleutelen met uw openbare sleutel. Alleen de eigenaar van de privésleutel (u) en niemand anders kan deze boodschappen ontcijferen.</string>
     <string name="new_wizard_info_id">U maakt ook een sleutelpaar aan. De openbare sleutel wordt veilig verzonden naar onze servers. De privésleutel verlaat uw apparaat niet. Hierdoor kan alleen u uw berichten lezen.</string>
     <string name="new_wizard_info_sync_contacts">Als u deze optie inschakelt, versleutelt (hasht) Threema uw e-mailadressen en telefoonnummers voordat ze naar de server worden verstuurd op zoek naar overeenkomende contactpersonen. We slaan geen adresboekgegevens op.</string>
+    <string name="new_wizard_info_sync_contacts_dialog">Met contactsynchronisatie kunt u uw vrienden automatisch vinden. Als u akkoord gaat, worden de telefoonnummers en de e-mailadressen uit uw telefoonboek versleuteld voordat ze naar onze server worden gestuurd om naar overeenkomstige contacten te zoeken. Er worden geen gegevens opgeslagen of gedeeld.\n\nWilt u contactsynchronisatie inschakelen?</string>
     <string name="new_wizard_info_link">Als u uw telefoonnummer en e-mailadres opgeeft, kan Threema helpen uw vrienden automatisch te vinden als u in hun lijst van contactpersonen staat. E-mailadressen worden versleuteld (hashed) op onze server opgeslagen. U kunt deze stap ook overslaan als u Threema liever anoniem gebruikt.</string>
     <string name="new_wizard_info_link_phone_only">Als u uw telefoonnummer opgeeft, kan Threema helpen uw vrienden automatisch te vinden als u in hun lijst van telefonische contactpersonen staat. Het telefoonnummer wordt versleuteld (hashed) op onze server opgeslagen. U kunt deze stap ook overslaan als u Threema liever volledig anoniem gebruikt.</string>
     <string name="new_wizard_info_nickname">De nickname wordt gebruikt in pushberichten op bepaalde apparaten of als aanvullende manier om u aan gebruikers die u nog niet in hun adresboek hebben, te identificeren. We raden aan alleen uw voornaam of een pseudoniem te gebruiken. Als u geen nickname instelt, gebruiken we standaard uw Threema ID.</string>
@@ -1389,6 +1390,8 @@ Weet u zeker dat u Threema anoniem wil gebruiken?</string>
     <string name="last_added_contact">Laatst toegevoegd</string>
     <string name="directory_explain_text">Zoek in de bedrijfsgids naar werknemers die nog niet aan je contact lijst zijn toegevoegd.</string>
     <string name="cannot_display_location">Deze locatie kan niet worden getoond.</string>
+    <string name="unable_to_restore_identity_because">Niet mogelijk om de ID te herstellen. Reden: %s</string>
+    <string name="share_with_app">Delen met Threema</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contactpersoon</item>
         <item quantity="other">%d contactpersonen</item>
@@ -1405,4 +1408,8 @@ Weet u zeker dat u Threema anoniem wil gebruiken?</string>
         <item quantity="one">%d afbeelding geselecteerd</item>
         <item quantity="other">%d afbeeldingen geselecteerd</item>
     </plurals>
+    <plurals name="message_copied">
+        <item quantity="one">Bericht gekopieerd</item>
+        <item quantity="other">Berichten gekopieerd</item>
+    </plurals>
 </resources>

Some files were not shown because too many files changed in this diff