forked from cwtch.im/cwtch-ui
Compare commits
84 Commits
Author | SHA1 | Date |
---|---|---|
Kaio Duarte Costa | d4a87cd416 | |
Kaio Duarte Costa | 0455ed15d7 | |
Kaio Duarte Costa | 1f15e8af39 | |
Kaio Duarte Costa | 32b4ad2576 | |
Sarah Jamie Lewis | 08d337401f | |
Sarah Jamie Lewis | 91eca10f12 | |
Sarah Jamie Lewis | 870e7338ae | |
Sarah Jamie Lewis | af4aab3a47 | |
Dan Ballard | 8972d0eef5 | |
Sarah Jamie Lewis | 881cfbd0a3 | |
Sarah Jamie Lewis | c5f684e42e | |
Dan Ballard | 2d89b30881 | |
Sarah Jamie Lewis | e51c30ecc9 | |
Sarah Jamie Lewis | fb4c438e1c | |
Sarah Jamie Lewis | 2eca5058a8 | |
Dan Ballard | 94297ee85f | |
Sarah Jamie Lewis | 3fe732809d | |
Dan Ballard | 52b1f28252 | |
Dan Ballard | 16f413177f | |
Dan Ballard | ea7b307de2 | |
Dan Ballard | 4d4901838e | |
Dan Ballard | cfa4b4f95b | |
Dan Ballard | 2defc7ea2c | |
Sarah Jamie Lewis | cfb32bc84a | |
Dan Ballard | e570f6941b | |
Sarah Jamie Lewis | 37e18d03a1 | |
Sarah Jamie Lewis | 76c925d874 | |
Dan Ballard | 975983be3c | |
Sarah Jamie Lewis | 7edc46743f | |
erinn | 74ab39067e | |
erinn | cac2064731 | |
Dan Ballard | 93284708e0 | |
Sarah Jamie Lewis | 521c0600a2 | |
Dan Ballard | 7f2a8d649d | |
Dan Ballard | d550c23fbd | |
Dan Ballard | 5d09341277 | |
Dan Ballard | 191065f51c | |
Sarah Jamie Lewis | 47e26f18fc | |
Dan Ballard | 2bf28e2c6a | |
Sarah Jamie Lewis | af3c6940bd | |
Dan Ballard | c3fa6735f5 | |
Sarah Jamie Lewis | 8cfbc39988 | |
Sarah Jamie Lewis | fc29b10f12 | |
Dan Ballard | a49ad07b40 | |
Sarah Jamie Lewis | 34e296959a | |
Sarah Jamie Lewis | d4d7a54af1 | |
Sarah Jamie Lewis | 5139846f31 | |
Sarah Jamie Lewis | 483213c63b | |
Sarah Jamie Lewis | 546ac6c23d | |
Dan Ballard | 3a752b7397 | |
Sarah Jamie Lewis | 7540aed701 | |
Sarah Jamie Lewis | ad52f2e0c8 | |
Sarah Jamie Lewis | 337f6dc5d9 | |
Sarah Jamie Lewis | 814e6df6f6 | |
Dan Ballard | 62ea8278f3 | |
Sarah Jamie Lewis | e8a638ed29 | |
Sarah Jamie Lewis | 44fba12d21 | |
Sarah Jamie Lewis | 7516232bd4 | |
Sarah Jamie Lewis | 5be25b87c4 | |
Sarah Jamie Lewis | e13ad5d218 | |
Sarah Jamie Lewis | c397a9cdb7 | |
Sarah Jamie Lewis | 60e822cf12 | |
Sarah Jamie Lewis | 0ea2a2116e | |
Dan Ballard | 9fb9759e6a | |
Sarah Jamie Lewis | 62b87f2939 | |
Sarah Jamie Lewis | da58555104 | |
Sarah Jamie Lewis | d8cfb5c730 | |
Sarah Jamie Lewis | 0dd9ecedac | |
Sarah Jamie Lewis | 61ee9491ab | |
Sarah Jamie Lewis | 6b9cf1f164 | |
Sarah Jamie Lewis | b8326762bf | |
Dan Ballard | af9a386ae8 | |
Sarah Jamie Lewis | da5925c7b3 | |
Dan Ballard | eabee61687 | |
Dan Ballard | 102341f931 | |
Dan Ballard | e36c5bf2f9 | |
Dan Ballard | 629c9152ca | |
Dan Ballard | 9298be0a61 | |
Sarah Jamie Lewis | fc4a87e3aa | |
Dan Ballard | bef8ca083b | |
Dan Ballard | 8d0b277731 | |
Sarah Jamie Lewis | 7badbca926 | |
Dan Ballard | 708f00f678 | |
Dan Ballard | e32e32ed27 |
20
.drone.yml
20
.drone.yml
|
@ -8,7 +8,7 @@ clone:
|
|||
|
||||
steps:
|
||||
- name: clone
|
||||
image: cirrusci/flutter:3.0.1
|
||||
image: cirrusci/flutter:3.3.8
|
||||
environment:
|
||||
buildbot_key_b64:
|
||||
from_secret: buildbot_key_b64
|
||||
|
@ -24,7 +24,7 @@ steps:
|
|||
- git checkout $DRONE_COMMIT
|
||||
|
||||
- name: fetch
|
||||
image: cirrusci/flutter:3.0.1
|
||||
image: cirrusci/flutter:3.3.8
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
|
@ -47,7 +47,7 @@ steps:
|
|||
# #Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting
|
||||
|
||||
- name: build-linux
|
||||
image: openpriv/flutter-desktop:linux-fstable-3.0.1
|
||||
image: openpriv/flutter-desktop:linux-fstable-3.3.8
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
|
@ -61,7 +61,7 @@ steps:
|
|||
- rm -r cwtch
|
||||
|
||||
- name: test-build-android
|
||||
image: cirrusci/flutter:3.0.1
|
||||
image: cirrusci/flutter:3.3.8
|
||||
when:
|
||||
event: pull_request
|
||||
volumes:
|
||||
|
@ -71,7 +71,7 @@ steps:
|
|||
- flutter build apk --debug
|
||||
|
||||
- name: build-android
|
||||
image: cirrusci/flutter:3.0.1
|
||||
image: cirrusci/flutter:3.3.8
|
||||
when:
|
||||
event: push
|
||||
environment:
|
||||
|
@ -95,7 +95,7 @@ steps:
|
|||
#- cp build/app/outputs/flutter-apk/app-debug.apk deploy/android
|
||||
|
||||
- name: widget-tests
|
||||
image: cirrusci/flutter:3.0.1
|
||||
image: cirrusci/flutter:3.3.8
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
|
@ -177,7 +177,7 @@ clone:
|
|||
|
||||
steps:
|
||||
- name: clone
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.0.1
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.3.8
|
||||
environment:
|
||||
buildbot_key_b64:
|
||||
from_secret: buildbot_key_b64
|
||||
|
@ -195,7 +195,7 @@ steps:
|
|||
- git checkout $Env:DRONE_COMMIT
|
||||
|
||||
- name: fetch
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.0.1
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.3.8
|
||||
commands:
|
||||
- git describe --tags --abbrev=1 > VERSION
|
||||
- powershell -command "Get-Date -Format 'yyyy-MM-dd-HH-mm'" > BUILDDATE
|
||||
|
@ -203,7 +203,7 @@ steps:
|
|||
- .\fetch-libcwtch-go.ps1
|
||||
|
||||
- name: build-windows
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.0.1
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.3.8
|
||||
commands:
|
||||
- flutter pub get
|
||||
- $Env:version += type .\VERSION
|
||||
|
@ -262,7 +262,7 @@ steps:
|
|||
- move *.sha512 deploy\$Env:builddir
|
||||
|
||||
- name: deploy-windows
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.0.1
|
||||
image: openpriv/flutter-desktop:windows-sdk30-fstable-3.3.8
|
||||
when:
|
||||
event: push
|
||||
status: [ success ]
|
||||
|
|
|
@ -1 +1 @@
|
|||
2022-06-27-15-00-v1.8.0
|
||||
2022-09-10-15-31-v1.9.0-6-g397d264
|
|
@ -1 +1 @@
|
|||
2022-06-27-19-01-v1.8.0
|
||||
2022-09-10-19-30-v1.9.0-6-g397d264
|
|
@ -99,7 +99,10 @@ dependencies {
|
|||
//implementation("androidx.work:work-runtime:$work_version")
|
||||
|
||||
// Kotlin + coroutines
|
||||
implementation("androidx.work:work-runtime-ktx:2.5.0")
|
||||
// 2022.06: upgraded from 2.5 to 2.7 for android 12
|
||||
// err: "requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent"
|
||||
// as per https://github.com/flutter/flutter/issues/93609
|
||||
implementation 'androidx.work:work-runtime-ktx:2.7.0'
|
||||
|
||||
// optional - RxJava2 support
|
||||
//implementation("androidx.work:work-rxjava2:$work_version")
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
android:theme="@style/NormalTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
package im.cwtch.flwtch
|
||||
|
||||
import android.app.*
|
||||
import android.os.Environment
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.work.*
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import cwtch.Cwtch
|
||||
import io.flutter.FlutterInjector
|
||||
import org.json.JSONObject
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import android.net.Uri
|
||||
|
||||
class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||
CoroutineWorker(context, parameters) {
|
||||
|
@ -82,6 +84,10 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
|
||||
Log.i(TAG, "startCwtch success, starting coroutine AppbusEvent loop...")
|
||||
val downloadIDs = mutableMapOf<String, Int>()
|
||||
var flags = PendingIntent.FLAG_UPDATE_CURRENT
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
flags = flags or PendingIntent.FLAG_IMMUTABLE
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
|
||||
|
@ -109,12 +115,11 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
intent.action = Intent.ACTION_RUN
|
||||
intent.putExtra("EventType", "NotificationClicked")
|
||||
}
|
||||
|
||||
val newNotification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle("Cwtch")
|
||||
.setContentText(notificationSimple ?: "New Message")
|
||||
.setSmallIcon(R.mipmap.knott_transparent)
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, flags))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
|
@ -147,7 +152,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
?: "New Message From %1").replace("%1", data.getString("Nick")))
|
||||
.setLargeIcon(BitmapFactory.decodeStream(fh))
|
||||
.setSmallIcon(R.mipmap.knott_transparent)
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, flags))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
|
@ -265,6 +270,10 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
intent.action = Intent.ACTION_RUN
|
||||
intent.putExtra("EventType", "ShutdownClicked")
|
||||
}
|
||||
var flags = PendingIntent.FLAG_UPDATE_CURRENT
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
flags = flags or PendingIntent.FLAG_IMMUTABLE
|
||||
}
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle(title)
|
||||
|
@ -274,7 +283,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
.setOngoing(true)
|
||||
// Add the cancel action to the notification which can
|
||||
// be used to cancel the worker
|
||||
.addAction(android.R.drawable.ic_delete, cancel, PendingIntent.getActivity(applicationContext, 2, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.addAction(android.R.drawable.ic_delete, cancel, PendingIntent.getActivity(applicationContext, 2, cancelIntent, flags))
|
||||
.build()
|
||||
|
||||
return ForegroundInfo(101, notification)
|
||||
|
|
|
@ -313,6 +313,7 @@ class MainActivity: FlutterActivity() {
|
|||
result.success(Cwtch.sendInvitation(profile, conversation.toLong(), target.toLong()))
|
||||
return
|
||||
}
|
||||
|
||||
"ShareFile" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
val conversation: Int = call.argument("conversation") ?: 0
|
||||
|
@ -321,6 +322,27 @@ class MainActivity: FlutterActivity() {
|
|||
return
|
||||
}
|
||||
|
||||
"GetSharedFiles" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
val conversation: Int = call.argument("conversation") ?: 0
|
||||
result.success(Cwtch.getSharedFiles(profile, conversation.toLong()))
|
||||
return
|
||||
}
|
||||
|
||||
"RestartSharing" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
val filepath: String = call.argument("filekey") ?: ""
|
||||
result.success(Cwtch.restartSharing(profile, filepath))
|
||||
return
|
||||
}
|
||||
|
||||
"StopSharing" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
val filepath: String = call.argument("filekey") ?: ""
|
||||
result.success(Cwtch.stopSharing(profile, filepath))
|
||||
return
|
||||
}
|
||||
|
||||
"CreateProfile" -> {
|
||||
val nick: String = call.argument("nick") ?: ""
|
||||
val pass: String = call.argument("pass") ?: ""
|
||||
|
@ -420,7 +442,7 @@ class MainActivity: FlutterActivity() {
|
|||
"ImportBundle" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
val bundle: String = call.argument("bundle") ?: ""
|
||||
Cwtch.importBundle(profile, bundle)
|
||||
result.success(Cwtch.importBundle(profile, bundle))
|
||||
}
|
||||
"CreateGroup" -> {
|
||||
val profile: String = call.argument("ProfileOnion") ?: ""
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
app:lottie_autoPlay="true"
|
||||
app:lottie_rawRes="@raw/cwtch_animated_logo_op"
|
||||
app:lottie_loop="true"
|
||||
app:lottie_speed="1.00" />
|
||||
app:lottie_speed="1.00"
|
||||
app:lottie_enableMergePathsForKitKatAndAbove="true" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
After Width: | Height: | Size: 381 KiB |
Binary file not shown.
After Width: | Height: | Size: 204 KiB |
Binary file not shown.
After Width: | Height: | Size: 346 KiB |
Binary file not shown.
After Width: | Height: | Size: 177 KiB |
|
@ -0,0 +1,16 @@
|
|||
Cwtch (/kʊtʃ/ - a Welsh word roughly translating to “a hug that creates a safe place”) is a decentralized,
|
||||
privacy-preserving, multi-party messaging protocol that can be used to build metadata resistant applications.
|
||||
|
||||
- Decentralized and Open: There is no “Cwtch service” or “Cwtch network”. Participants in Cwtch
|
||||
can host their own safe spaces, or lend their infrastructure to others seeking a safe space.
|
||||
The Cwtch protocol is open, and anyone is free to build bots, services and user interfaces and
|
||||
integrate and interact with Cwtch.
|
||||
|
||||
- Privacy Preserving: All communication in Cwtch is end-to-end encrypted and takes place over Tor v3
|
||||
onion services.
|
||||
|
||||
- Metadata Resistant: Cwtch has been designed such that no information is exchanged or available to
|
||||
anyone without their explicit consent, including on-the-wire messages and protocol metadata.
|
||||
|
||||
For more information on how Cwtch works and a guide to metadata resistant communication please
|
||||
checkout the Cwtch Handbook: https://docs.cwtch.im/
|
|
@ -0,0 +1 @@
|
|||
Metadata resistant privacy platform designed to help you resist surveillance
|
|
@ -0,0 +1 @@
|
|||
Cwtch
|
|
@ -0,0 +1 @@
|
|||
https://cwtch.im/cwtch-explainer.mp4
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd macos
|
||||
curl https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-macos-0.4.6.7.tar.gz --output tor.tar.gz
|
||||
curl https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-macos-0.4.7.8.tar.gz --output tor.tar.gz
|
||||
tar -xzf tor.tar.gz
|
||||
chmod a+x Tor/tor.real
|
||||
cd ..
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Invoke-WebRequest -Uri https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-win64-0.4.6.9.zip -OutFile tor.zip
|
||||
Invoke-WebRequest -Uri https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-win64-0.4.7.8.zip -OutFile tor.zip
|
||||
|
||||
if ((Get-FileHash tor.zip -Algorithm sha512).Hash -ne 'bd99de56ef5ef9516410783ce48d52311093b26e718bf3d0a94efbd754d1cf2d12543f096139d9c289985349d26ee89b2308be5927fa1b410ff4f7f3129d6830' ) { Write-Error 'tor.zip sha512sum mismatch' }
|
||||
if ((Get-FileHash tor.zip -Algorithm sha512).Hash -ne '5b8f900a37f6e90d7a945b3903d769383c7478042cb43b2105d2374186e1a536f1a4758a2823d1d5be71d53a81dcfd8243293e04f82812d355983df322823cf4' ) { Write-Error 'tor.zip sha512sum mismatch' }
|
||||
|
||||
Expand-Archive -Path tor.zip -DestinationPath Tor
|
||||
|
|
10
fetch-tor.sh
10
fetch-tor.sh
|
@ -1,12 +1,14 @@
|
|||
#!/bin/sh
|
||||
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.5.9-linux-x86_64 -O linux/tor
|
||||
chmod a+x linux/tor
|
||||
cd linux
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.7.8-linux-x86_64.tar.gz -O tor.tar.gz
|
||||
tar -xzf tor.tar.gz
|
||||
cd ..
|
||||
|
||||
mkdir -p android/app/src/main/jniLibs/arm64-v8a
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.6.9-arm64 -O android/app/src/main/jniLibs/arm64-v8a/libtor.so
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.7.10-arm64 -O android/app/src/main/jniLibs/arm64-v8a/libtor.so
|
||||
chmod a+x android/app/src/main/jniLibs/arm64-v8a/libtor.so
|
||||
|
||||
mkdir -p android/app/src/main/jniLibs/armeabi-v7a
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.6.9-arm7 -O android/app/src/main/jniLibs/armeabi-v7a/libtor.so
|
||||
wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-0.4.7.10-arm7 -O android/app/src/main/jniLibs/armeabi-v7a/libtor.so
|
||||
chmod a+x android/app/src/main/jniLibs/armeabi-v7a/libtor.so
|
||||
|
|
|
@ -59,6 +59,16 @@ abstract class Cwtch {
|
|||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> ShareFile(String profile, int handle, String filepath);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> GetSharedFiles(String profile, int handle);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void RestartSharing(String profile, String filekey);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void StopSharing(String profile, String filekey);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void DownloadFile(String profile, int handle, String filepath, String manifestpath, String filekey);
|
||||
// android-only
|
||||
|
@ -81,7 +91,7 @@ abstract class Cwtch {
|
|||
void CreateGroup(String profile, String server, String groupName);
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void ImportBundle(String profile, String bundle);
|
||||
Future<dynamic> ImportBundle(String profile, String bundle);
|
||||
// ignore: non_constant_identifier_names
|
||||
void SetProfileAttribute(String profile, String key, String val);
|
||||
// ignore: non_constant_identifier_names
|
||||
|
@ -111,7 +121,7 @@ abstract class Cwtch {
|
|||
Future<void> Shutdown();
|
||||
|
||||
// non-ffi
|
||||
String defaultDownloadPath();
|
||||
String? defaultDownloadPath();
|
||||
|
||||
bool isL10nInit();
|
||||
|
||||
|
|
|
@ -309,6 +309,14 @@ class CwtchNotifier {
|
|||
case "UpdateServerInfo":
|
||||
profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]);
|
||||
break;
|
||||
case "TokenManagerInfo":
|
||||
List<dynamic> associatedGroups = jsonDecode(data["Data"]);
|
||||
int count = int.parse(data["ServerTokenCount"]);
|
||||
associatedGroups.forEach((identifier) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(int.parse(identifier.toString()))!.antispamTickets = count;
|
||||
});
|
||||
EnvironmentConfig.debugLog("update server token count for ${associatedGroups}, $count");
|
||||
break;
|
||||
case "NewGroup":
|
||||
String invite = data["GroupInvite"].toString();
|
||||
if (invite.startsWith("torv3")) {
|
||||
|
|
|
@ -68,6 +68,9 @@ typedef GetJsonBlobFromStrIntStrFn = Pointer<Utf8> Function(Pointer<Utf8>, int,
|
|||
typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32);
|
||||
typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);
|
||||
|
||||
typedef get_json_blob_from_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Int32);
|
||||
typedef GetJsonBlobFromStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, int);
|
||||
|
||||
typedef get_json_blob_from_str_int_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Int32, Int32);
|
||||
typedef GetJsonBlobFromStrIntIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, int, int);
|
||||
|
||||
|
@ -150,14 +153,14 @@ class CwtchFfi implements Cwtch {
|
|||
String cwtchDir = "";
|
||||
if (Platform.isLinux) {
|
||||
cwtchDir = envVars['CWTCH_HOME'] ?? path.join(envVars['HOME']!, ".cwtch");
|
||||
if (await File("linux/tor").exists()) {
|
||||
bundledTor = "linux/tor";
|
||||
} else if (await File("lib/tor").exists()) {
|
||||
bundledTor = "lib/tor";
|
||||
} else if (await File(path.join(home, ".local/lib/cwtch/tor")).exists()) {
|
||||
bundledTor = path.join(home, ".local/lib/cwtch/tor");
|
||||
} else if (await File("/usr/lib/cwtch/tor").exists()) {
|
||||
bundledTor = "/usr/lib/cwtch/tor";
|
||||
if (await File("linux/Tor/tor").exists()) {
|
||||
bundledTor = "linux/Tor/tor";
|
||||
} else if (await File("lib/Tor/tor").exists()) {
|
||||
bundledTor = "lib/Tor/tor";
|
||||
} else if (await File(path.join(home, ".local/lib/cwtch/Tor/tor")).exists()) {
|
||||
bundledTor = path.join(home, ".local/lib/cwtch/Tor/tor");
|
||||
} else if (await File("/usr/lib/cwtch/Tor/tor").exists()) {
|
||||
bundledTor = "/usr/lib/cwtch/Tor/tor";
|
||||
} else {
|
||||
bundledTor = "tor";
|
||||
}
|
||||
|
@ -502,15 +505,18 @@ class CwtchFfi implements Cwtch {
|
|||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void ImportBundle(String profileOnion, String bundle) {
|
||||
var importBundle = library.lookup<NativeFunction<string_string_to_void_function>>("c_ImportBundle");
|
||||
Future<dynamic> ImportBundle(String profileOnion, String bundle) async {
|
||||
var importBundle = library.lookup<NativeFunction<string_string_to_string_function>>("c_ImportBundle");
|
||||
// ignore: non_constant_identifier_names
|
||||
final ImportBundle = importBundle.asFunction<VoidFromStringStringFn>();
|
||||
final ImportBundle = importBundle.asFunction<StringFromStringStringFn>();
|
||||
final u1 = profileOnion.toNativeUtf8();
|
||||
final u2 = bundle.toNativeUtf8();
|
||||
ImportBundle(u1, u1.length, u2, u2.length);
|
||||
Pointer<Utf8> responsePtr = ImportBundle(u1, u1.length, u2, u2.length);
|
||||
String response = responsePtr.toDartString();
|
||||
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(responsePtr);
|
||||
malloc.free(u1);
|
||||
malloc.free(u2);
|
||||
return response;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -756,9 +762,13 @@ class CwtchFfi implements Cwtch {
|
|||
}
|
||||
|
||||
@override
|
||||
String defaultDownloadPath() {
|
||||
String? defaultDownloadPath() {
|
||||
Map<String, String> envVars = Platform.environment;
|
||||
return path.join(envVars[Platform.isWindows ? 'UserProfile' : 'HOME']!, "Downloads");
|
||||
String nominalPath = path.join(envVars[Platform.isWindows ? 'UserProfile' : 'HOME']!, "Downloads");
|
||||
if (Directory(nominalPath).existsSync() == false) {
|
||||
return null;
|
||||
}
|
||||
return nominalPath;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -841,4 +851,40 @@ class CwtchFfi implements Cwtch {
|
|||
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(result);
|
||||
return debugResult;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> GetSharedFiles(String profile, int handle) async {
|
||||
var getSharedFiles = library.lookup<NativeFunction<get_json_blob_from_str_int_function>>("c_GetSharedFiles");
|
||||
final GetSharedFiles = getSharedFiles.asFunction<GetJsonBlobFromStrIntFn>();
|
||||
final utf8profile = profile.toNativeUtf8();
|
||||
Pointer<Utf8> jsonMessageBytes = GetSharedFiles(utf8profile, utf8profile.length, handle);
|
||||
String jsonMessage = jsonMessageBytes.toDartString();
|
||||
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes);
|
||||
malloc.free(utf8profile);
|
||||
return jsonMessage;
|
||||
}
|
||||
|
||||
@override
|
||||
void RestartSharing(String profile, String filekey) {
|
||||
var restartSharingC = library.lookup<NativeFunction<void_from_string_string_function>>("c_RestartSharing");
|
||||
// ignore: non_constant_identifier_names
|
||||
final RestartSharing = restartSharingC.asFunction<VoidFromStringStringFn>();
|
||||
final utf8profile = profile.toNativeUtf8();
|
||||
final ut8filekey = filekey.toNativeUtf8();
|
||||
RestartSharing(utf8profile, utf8profile.length, ut8filekey, ut8filekey.length);
|
||||
malloc.free(utf8profile);
|
||||
malloc.free(ut8filekey);
|
||||
}
|
||||
|
||||
@override
|
||||
void StopSharing(String profile, String filekey) {
|
||||
var stopSharingC = library.lookup<NativeFunction<void_from_string_string_function>>("c_StopSharing");
|
||||
// ignore: non_constant_identifier_names
|
||||
final StopSharing = stopSharingC.asFunction<VoidFromStringStringFn>();
|
||||
final utf8profile = profile.toNativeUtf8();
|
||||
final ut8filekey = filekey.toNativeUtf8();
|
||||
StopSharing(utf8profile, utf8profile.length, ut8filekey, ut8filekey.length);
|
||||
malloc.free(utf8profile);
|
||||
malloc.free(ut8filekey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,8 +190,8 @@ class CwtchGomobile implements Cwtch {
|
|||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void ImportBundle(String profileOnion, String bundle) {
|
||||
cwtchPlatform.invokeMethod("ImportBundle", {"ProfileOnion": profileOnion, "bundle": bundle});
|
||||
Future<dynamic> ImportBundle(String profileOnion, String bundle) {
|
||||
return cwtchPlatform.invokeMethod("ImportBundle", {"ProfileOnion": profileOnion, "bundle": bundle});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -294,7 +294,7 @@ class CwtchGomobile implements Cwtch {
|
|||
}
|
||||
|
||||
@override
|
||||
String defaultDownloadPath() {
|
||||
String? defaultDownloadPath() {
|
||||
return this.androidHomeDirectoryStr;
|
||||
}
|
||||
|
||||
|
@ -333,4 +333,19 @@ class CwtchGomobile implements Cwtch {
|
|||
// we don't implement it
|
||||
return Future.value("{}");
|
||||
}
|
||||
|
||||
@override
|
||||
Future GetSharedFiles(String profile, int handle) {
|
||||
return cwtchPlatform.invokeMethod("GetSharedFiles", {"ProfileOnion": profile, "conversation": handle});
|
||||
}
|
||||
|
||||
@override
|
||||
void RestartSharing(String profile, String filekey) {
|
||||
cwtchPlatform.invokeMethod("RestartSharing", {"ProfileOnion": profile, "filekey": filekey});
|
||||
}
|
||||
|
||||
@override
|
||||
void StopSharing(String profile, String filekey) {
|
||||
cwtchPlatform.invokeMethod("StopSharing", {"ProfileOnion": profile, "filekey": filekey});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/// Flutter icons CwtchIcons
|
||||
/// Copyright (C) 2021 by Open Privacy Research Society via fluttericon.com, fontello.com
|
||||
/// Flutter icons Cwtch
|
||||
/// Copyright (C) 2021-2022 by Open Privacy Research Society
|
||||
/// This font was generated by FlutterIcon.com, which is derived from Fontello.
|
||||
///
|
||||
/// To use this font, place it in your fonts/ directory and include the
|
||||
|
@ -7,9 +7,9 @@
|
|||
///
|
||||
/// flutter:
|
||||
/// fonts:
|
||||
/// - family: CwtchIcons
|
||||
/// - family: Cwtch
|
||||
/// fonts:
|
||||
/// - asset: assets/fonts/CwtchIcons.ttf
|
||||
/// - asset: fonts/Cwtch.ttf
|
||||
///
|
||||
///
|
||||
///
|
||||
|
@ -18,103 +18,112 @@ import 'package:flutter/widgets.dart';
|
|||
class CwtchIcons {
|
||||
CwtchIcons._();
|
||||
|
||||
static const _kFontFam = 'CwtchIcons';
|
||||
static const _kFontFam = 'Cwtch';
|
||||
static const String? _kFontPkg = null;
|
||||
|
||||
static const IconData arrow_back_24px = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData attach_file_24px = IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_peer = IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_unknown = IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_24px = IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData brightness_5_24px = IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData camera_alt_24px = IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData change_language = IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData change_theme = IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_bubble_empty_24px = IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_bubble_24px = IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_seetings_24px = IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData check_24px = IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chevron_left_24px = IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData clear_24px = IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData content_copy_24px = IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData create_group = IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData cwtch_knott = IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dark_mode_24px = IconData(0xe812, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData delete_24px = IconData(0xe813, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_24px = IconData(0xe814, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData drag_indicator_24px = IconData(0xe815, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData edit_24px = IconData(0xe816, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData enable_experiments = IconData(0xe817, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData enable_groups = IconData(0xe818, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_closed = IconData(0xe819, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_open = IconData(0xe81a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_24dp = IconData(0xe81b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_broken = IconData(0xe81c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_brokenhalf = IconData(0xe81d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_malformed = IconData(0xe81e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_sad = IconData(0xe81f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData group_add_24px = IconData(0xe820, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData group_settings_24px = IconData(0xe821, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData groups_24px = IconData(0xe822, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData info_24px = IconData(0xe823, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData join_group = IconData(0xe824, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData list_black_24dp = IconData(0xe825, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData lock_open_24px = IconData(0xe826, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData lock_24px = IconData(0xe827, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData maps_ugc_24px = IconData(0xe828, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData menu_24px = IconData(0xe829, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData message_24px = IconData(0xe82a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData mood_24px = IconData(0xe82b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData more_vert_24px = IconData(0xe82c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData negative_heart_24px = IconData(0xe82d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_off = IconData(0xe82e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_on = IconData(0xe82f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_waiting = IconData(0xe830, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData peer_history = IconData(0xe831, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData peer_settings_24px = IconData(0xe832, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_add_alt_1_24px = IconData(0xe833, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_add_24px = IconData(0xe834, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_24px = IconData(0xe835, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData push_pin_black_24dp = IconData(0xe836, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData push_pin_24px = IconData(0xe837, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData search_24px = IconData(0xe838, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData send_24px = IconData(0xe839, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData settings_24px = IconData(0xe83a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_4_bar_24px = IconData(0xe83b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_alt_24px = IconData(0xe83c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_connected_no_internet_4_bar_24px = IconData(0xe83d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_off_24px = IconData(0xe83e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData swap_horiz_24px = IconData(0xe83f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_disabled_24px = IconData(0xe840, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_problem_24px = IconData(0xe841, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_24px = IconData(0xe842, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_01 = IconData(0xe843, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_02 = IconData(0xe844, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_03 = IconData(0xe845, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData toggle_on_24px = IconData(0xe846, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData vpn_key_24px = IconData(0xe847, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_blocked = IconData(0xe848, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px = IconData(0xe849, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_lines = IconData(0xe84a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_lines_thin___blocked = IconData(0xe84b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_user = IconData(0xe84c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_circle_24px = IconData(0xe84d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_group = IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_peer = IconData(0xe84f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_24px = IconData(0xe850, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData address_copy_2 = IconData(0xe852, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData address = IconData(0xe856, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData streamer_bunnymask = IconData(0xe85b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData streamer_ghost = IconData(0xe85c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData cancel_schedule_send_black_24dp = IconData(0xe85d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData more_horiz_black_24dp = IconData(0xe85e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_black_add_24dp = IconData(0xe85f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_black_24dp = IconData(0xe860, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData info_black_24dp = IconData(0xe861, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData accept_unknown = IconData(0xe862, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_closed_1 = IconData(0xe863, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_open_1 = IconData(0xe864, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData send_invite = IconData(0xe888, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData leave_group = IconData(0xe88a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData leave_chat = IconData(0xe88b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_blocked = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px = IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_lines = IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_lines_thin___blocked = IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData account_circle_24px_user = IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_circle_24px = IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_group = IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_peer = IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData add_24px = IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData address = IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData address_copy = IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData alternate_email_black_24dp = IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData arrow_back_24px = IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData attach_file_24px = IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData attached_file = IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_peer = IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_unknown = IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData block_24px = IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData brightness_5_24px = IconData(0xe812, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData camera_alt_24px = IconData(0xe813, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData cancel_schedule_send_black_24dp = IconData(0xe814, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData change_language = IconData(0xe815, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData change_theme = IconData(0xe816, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_bubble_empty_24px = IconData(0xe817, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_bubble_24px = IconData(0xe818, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chat_seetings_24px = IconData(0xe819, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData check_24px = IconData(0xe81b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData chevron_left_24px = IconData(0xe81c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData clear_24px = IconData(0xe81d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData content_copy_24px = IconData(0xe81e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData copy_address = IconData(0xe81f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData create_group = IconData(0xe820, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData cwtch_knott = IconData(0xe821, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dark_mode_24px = IconData(0xe822, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData delete_24px = IconData(0xe823, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_black_24dp = IconData(0xe824, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_black_add_24dp = IconData(0xe825, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData dns_24px = IconData(0xe826, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData drag_indicator_24px = IconData(0xe827, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData edit_24px = IconData(0xe828, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData enable_experiments = IconData(0xe829, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData enable_groups = IconData(0xe82a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_closed = IconData(0xe82b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData eye_open = IconData(0xe82c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_24dp = IconData(0xe82d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_broken = IconData(0xe82e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_brokenhalf = IconData(0xe82f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_malformed = IconData(0xe830, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData favorite_black_24dp_sad = IconData(0xe831, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData folder_black_24dp = IconData(0xe832, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData group_add_24px = IconData(0xe833, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData group_settings_24px = IconData(0xe834, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData groups_24px = IconData(0xe835, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData image_black_24dp = IconData(0xe836, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData info_black_24dp = IconData(0xe837, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData info_24px = IconData(0xe838, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData join_group = IconData(0xe839, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData leave_chat = IconData(0xe83a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData leave_group = IconData(0xe83b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData link_ = IconData(0xe83c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData list_black_24dp = IconData(0xe83d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData lock_open_24px = IconData(0xe83e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData lock_24px = IconData(0xe83f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData maps_ugc_24px = IconData(0xe841, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData menu_24px = IconData(0xe842, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData message_24px = IconData(0xe843, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData mood_24px = IconData(0xe844, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData more_horiz_black_24dp = IconData(0xe845, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData more_vert_24px = IconData(0xe846, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData negative_heart_24px = IconData(0xe848, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_off = IconData(0xe849, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_on = IconData(0xe84a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData onion_waiting = IconData(0xe84b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData peer_history = IconData(0xe84c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData peer_settings_24px = IconData(0xe84d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_add_alt_1_24px = IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_add_24px = IconData(0xe84f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData person_24px = IconData(0xe850, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData push_pin_black_24dp = IconData(0xe852, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData push_pin_24px = IconData(0xe853, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData search_24px = IconData(0xe855, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData send_invite = IconData(0xe856, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData send_24px = IconData(0xe857, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData settings_24px = IconData(0xe858, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_4_bar_24px = IconData(0xe859, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_alt_24px = IconData(0xe85a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_connected_no_internet_4_bar_24px = IconData(0xe85b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData signal_cellular_off_24px = IconData(0xe85c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData streamer_bunnymask = IconData(0xe85d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData streamer_ghost = IconData(0xe85e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData swap_horiz_24px = IconData(0xe85f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_disabled_24px = IconData(0xe860, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_problem_24px = IconData(0xe861, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData sync_24px = IconData(0xe862, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_01 = IconData(0xe863, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_02 = IconData(0xe864, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData syncing_03 = IconData(0xe865, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData toggle_on_24px = IconData(0xe866, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData vpn_key_24px = IconData(0xe867, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData accept_unknown = IconData(0xe868, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData view_replies = IconData(0xe869, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData anti_spam_2 = IconData(0xe86b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData manage_files = IconData(0xe86c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData attached_file_2 = IconData(0xe86d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData anti_spam_3 = IconData(0xe86e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
}
|
||||
|
|
|
@ -5,23 +5,14 @@ class ErrorHandler extends ChangeNotifier {
|
|||
static const String successErrorType = "success";
|
||||
|
||||
// Add Contact Specific Errors...
|
||||
static const String addContactErrorPrefix = "addcontact";
|
||||
static const String changePasswordErrorPrefix = "changepassword";
|
||||
static const String invalidImportStringErrorType = "invalid_import_string";
|
||||
static const String contactAlreadyExistsErrorType = "contact_already_exists";
|
||||
bool invalidImportStringError = false;
|
||||
bool contactAlreadyExistsError = false;
|
||||
bool explicitAddContactSuccess = false;
|
||||
|
||||
// ChangePassword
|
||||
bool changePasswordError = false;
|
||||
bool explicitChangePasswordSuccess = false;
|
||||
|
||||
// Import Bundle Specific Errors
|
||||
static const String importBundleErrorPrefix = "importBundle";
|
||||
bool importBundleError = false;
|
||||
bool importBundleSuccess = false;
|
||||
|
||||
static const String deleteProfileErrorPrefix = "deleteprofile";
|
||||
bool deleteProfileError = false;
|
||||
bool deleteProfileSuccess = false;
|
||||
|
@ -31,13 +22,6 @@ class ErrorHandler extends ChangeNotifier {
|
|||
bool deletedServerSuccess = false;
|
||||
|
||||
reset() {
|
||||
invalidImportStringError = false;
|
||||
contactAlreadyExistsError = false;
|
||||
explicitAddContactSuccess = false;
|
||||
|
||||
importBundleError = false;
|
||||
importBundleSuccess = false;
|
||||
|
||||
deleteProfileError = false;
|
||||
deleteProfileSuccess = false;
|
||||
|
||||
|
@ -57,12 +41,6 @@ class ErrorHandler extends ChangeNotifier {
|
|||
String errorType = parts[1];
|
||||
|
||||
switch (prefix) {
|
||||
case addContactErrorPrefix:
|
||||
handleAddContactError(errorType);
|
||||
break;
|
||||
case importBundleErrorPrefix:
|
||||
handleImportBundleError(errorType);
|
||||
break;
|
||||
case deleteProfileErrorPrefix:
|
||||
handleDeleteProfileError(errorType);
|
||||
break;
|
||||
|
@ -76,41 +54,6 @@ class ErrorHandler extends ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
handleAddContactError(String errorType) {
|
||||
// Reset add contact errors
|
||||
invalidImportStringError = false;
|
||||
contactAlreadyExistsError = false;
|
||||
explicitAddContactSuccess = false;
|
||||
|
||||
switch (errorType) {
|
||||
case invalidImportStringErrorType:
|
||||
invalidImportStringError = true;
|
||||
break;
|
||||
case contactAlreadyExistsErrorType:
|
||||
contactAlreadyExistsError = true;
|
||||
break;
|
||||
case successErrorType:
|
||||
explicitAddContactSuccess = true;
|
||||
importBundleSuccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleImportBundleError(String errorType) {
|
||||
// Reset add contact errors
|
||||
importBundleError = false;
|
||||
importBundleSuccess = false;
|
||||
|
||||
switch (errorType) {
|
||||
case successErrorType:
|
||||
importBundleSuccess = true;
|
||||
break;
|
||||
default:
|
||||
importBundleError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteProfileError(String errorType) {
|
||||
// Reset add contact errors
|
||||
deleteProfileError = false;
|
||||
|
|
|
@ -618,4 +618,8 @@ class MaterialLocalizationLu extends MaterialLocalizations {
|
|||
// TODO: implement timeOfDayFormat
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement menuBarMenuLabel
|
||||
String get menuBarMenuLabel => throw UnimplementedError();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
{
|
||||
"@@locale": "cy",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Tyrceg \/ Türk",
|
||||
"localeIt": "Eidaleg \/ Italiana",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Almaeneg \/ Deutsch",
|
||||
"localePt": "Portiwgaleg \/ Portuguesa",
|
||||
"localeRo": "Rwmaneg \/ Română",
|
||||
|
@ -9,7 +29,6 @@
|
|||
"localeRU": "Rwsieg \/ Русский",
|
||||
"localeCy": "Cymraeg \/ Cymraeg",
|
||||
"localePl": "Pwylaidd \/ Polski",
|
||||
"localeIt": "Eidaleg \/ Italiana",
|
||||
"localeFr": "Ffrangeg \/ Français",
|
||||
"localeEs": "Sbaeneg \/ Español",
|
||||
"localeNo": "Norwyaidd \/ Norsk",
|
||||
|
|
|
@ -1,12 +1,31 @@
|
|||
{
|
||||
"@@locale": "da",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Tyrkisk \/ Türk",
|
||||
"localeIt": "Italiensk \/ Italiano",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Tysk \/ Deutsch",
|
||||
"localeEn": "Engelsk \/ English",
|
||||
"localeFr": "Fransk \/ Français",
|
||||
"localePt": "Portugisisk \/ Portuguesa",
|
||||
"localeEs": "Spansk \/ Español",
|
||||
"localeIt": "Italiensk \/ Italiana",
|
||||
"localePl": "Polsk \/ Polski",
|
||||
"localeRU": "Russisk \/ Русский",
|
||||
"localeDa": "Danish \/ Dansk",
|
||||
|
|
|
@ -1,9 +1,28 @@
|
|||
{
|
||||
"@@locale": "de",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"localeIt": "Italienisch \/ Italiano",
|
||||
"errorDownloadDirectoryDoesNotExist": "Die Dateifreigabe kann nicht aktiviert werden, da der Download-Ordner nicht festgelegt wurde oder auf einen nicht vorhandenen Ordner festgelegt ist.",
|
||||
"localeTr": "Türkisch \/ Türk",
|
||||
"viewReplies": "Antworten auf diese Nachricht anzeigen",
|
||||
"manageSharedFiles": "Freigegebene Dateien verwalten",
|
||||
"tooltipPinConversation": "Konversation oben in \"Konversationen\" anheften",
|
||||
"tooltipUnpinConversation": "Anheften der Konversation oben in \"Konversationen\" aufheben",
|
||||
"messageNoReplies": "Es gibt keine Antworten auf diese Nachricht.",
|
||||
"stopSharingFile": "Beenden der Dateifreigabe",
|
||||
"restartFileShare": "Freigabe der Datei starten",
|
||||
"replyingTo": "Antwort auf %1",
|
||||
"fileDownloadUnavailable": "Diese Datei steht nicht zum Download zur Verfügung. Der Absender hat möglicherweise das Herunterladen dieser Datei deaktiviert.",
|
||||
"headingReplies": "Antworten",
|
||||
"localeEn": "Englisch \/ English",
|
||||
"localePl": "Polnisch \/ Polski",
|
||||
"localeIt": "Italienisch \/ Italiana",
|
||||
"localeRo": "Rumänisch \/ Română",
|
||||
"localeNo": "Norwegisch \/ Norsk",
|
||||
"localeLb": "Luxemburgisch \/ Lëtzebuergesch",
|
||||
|
|
|
@ -1,6 +1,27 @@
|
|||
{
|
||||
"@@locale": "el",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Τουρκικά \/ Türk",
|
||||
"localeIt": "Italian \/ Italiano",
|
||||
"localeCy": "Ουαλικά \/ Cymraeg",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Γερμανός \/ Deutsch",
|
||||
"localeEn": "English \/ English",
|
||||
"localeLb": "Λουξεμβουργιανά",
|
||||
|
@ -13,8 +34,6 @@
|
|||
"localeDa": "Δανικά",
|
||||
"localePt": "Portuguese \/ Portuguesa",
|
||||
"localeFr": "French \/ Français",
|
||||
"localeIt": "Italian \/ Italiana",
|
||||
"localeCy": "Ουαλικά",
|
||||
"settingImagePreviewsDescription": "Θα γίνει αυτόματη λήψη και προεπισκόπηση των εικόνων. Λάβετε υπόψη ότι οι προεπισκοπήσεις εικόνων μπορεί συχνά να οδηγήσουν σε ευπάθειες ασφαλείας και δεν θα πρέπει να ενεργοποιήσετε αυτό το πείραμα εάν χρησιμοποιείτε το Cwtch με μη αξιόπιστες επαφές. Οι φωτογραφίες προφίλ έχουν προγραμματιστεί για το Cwtch 1.6.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
"tooltipCode": "Code \/ Monospace",
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
{
|
||||
"@@locale": "en",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeIt": "Italian \/ Italiano",
|
||||
"localeTr": "Turkish \/ Türk",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "German \/ Deutsch",
|
||||
"localeEn": "English \/ English",
|
||||
"localeLb": "Luxembourgish \/ Lëtzebuergesch",
|
||||
|
@ -13,7 +33,6 @@
|
|||
"localeDa": "Danish \/ Dansk",
|
||||
"localePt": "Portuguese \/ Portuguesa",
|
||||
"localeFr": "French \/ Français",
|
||||
"localeIt": "Italian \/ Italiana",
|
||||
"localeCy": "Welsh \/ Cymraeg",
|
||||
"settingImagePreviewsDescription": "Images and Profile Pictures will be downloaded and previewed automatically. We recommend that you do not enable this Experiment if you use Cwtch with untrusted contacts.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
{
|
||||
"@@locale": "es",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"tooltipPinConversation": "Fija la conversación en la parte superior de \"Conversaciones\"",
|
||||
"errorDownloadDirectoryDoesNotExist": "No se puede habilitar el uso compartido de archivos porque la carpeta de descarga no se ha configurado o se configuró en una carpeta que no existe.",
|
||||
"acquiringTicketsFromServer": "Realizando Desafío Antispam",
|
||||
"acquiredTicketsFromServer": "Desafío Antispam Completado",
|
||||
"tooltipUnpinConversation": "Desenganchar la conversación de la parte superior de \"Conversaciones\"",
|
||||
"manageSharedFiles": "Administrar Archivos Compartidos",
|
||||
"stopSharingFile": "Dejar de compartir archivos",
|
||||
"restartFileShare": "Comenzar a compartir archivos",
|
||||
"viewReplies": "Ver respuestas a este mensaje",
|
||||
"headingReplies": "Respuestas",
|
||||
"messageNoReplies": "No hay respuestas a este mensaje.",
|
||||
"fileDownloadUnavailable": "Parece que este archivo no está disponible para descargar. Es posible que el remitente haya desactivado las descargas de este archivo.",
|
||||
"replyingTo": "Respondiendo a %1",
|
||||
"localeTr": "Turco \/ Türk",
|
||||
"localeIt": "Italiano \/ Italiano",
|
||||
"localeDe": "Alemán \/ Deutsch",
|
||||
"settingImagePreviewsDescription": "Las imágenes se descargarán y visualizarán automáticamente. Ten en cuenta que las previsualizaciones pueden generar vulnerabilidades de seguridad, no deberías habilitar este experimento si usas Cwtch con contactos que no son de confianza. Las imágenes de perfil están planeadas para Cwtch 1.6.",
|
||||
"tooltipBackToMessageEditing": "Volver a Edición de mensajes",
|
||||
|
@ -36,7 +56,6 @@
|
|||
"localeEs": "Español \/ Español",
|
||||
"localeRU": "Ruso \/ Русский",
|
||||
"localePl": "Polaco \/ Polski",
|
||||
"localeIt": "Italiano \/ Italiana",
|
||||
"localeLb": "Luxemburgués \/ Lëtzebuergesch",
|
||||
"localeEn": "Inglés \/ English",
|
||||
"localeDa": "Danés \/ Dansk",
|
||||
|
|
|
@ -1,10 +1,29 @@
|
|||
{
|
||||
"@@locale": "fr",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Le partage de fichiers ne peut pas être activé car le dossier de téléchargement n'a pas été défini ou est défini sur un dossier qui n'existe pas.",
|
||||
"localeIt": "italien \/ italien",
|
||||
"localeTr": "Turc \/ Türk",
|
||||
"tooltipPinConversation": "Épingler la conversation en haut de «Conversations»",
|
||||
"tooltipUnpinConversation": "Détacher la conversation du haut de «Conversations»",
|
||||
"viewReplies": "Voir les réponses à ce message",
|
||||
"stopSharingFile": "Arrêter le partage de fichiers",
|
||||
"restartFileShare": "Démarrer le partage de fichiers",
|
||||
"replyingTo": "Répondre à %1",
|
||||
"messageNoReplies": "Il n'y a pas de réponses à ce message.",
|
||||
"manageSharedFiles": "Gérer les fichiers partagés",
|
||||
"headingReplies": "Réponses",
|
||||
"fileDownloadUnavailable": "Ce fichier semble indisponible pour le téléchargement. L'expéditeur a peut-être désactivé les téléchargements pour ce fichier.",
|
||||
"localeDe": "Allemand \/ Deutsch",
|
||||
"localeDa": "Danois \/ Dansk",
|
||||
"localePt": "Portugais \/ Portuguesa",
|
||||
"localeIt": "Italien \/ Italiana",
|
||||
"localeCy": "Gallois \/ Cymraeg",
|
||||
"localeEl": "Grec \/ Ελληνικά",
|
||||
"localeRU": "Russe \/ Русский",
|
||||
|
|
|
@ -1,11 +1,30 @@
|
|||
{
|
||||
"@@locale": "it",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"tooltipPinConversation": "Aggiungi la conversazione in cima alla lista \"Conversazioni\"",
|
||||
"tooltipUnpinConversation": "Rimuovi la conversazione dalla cima della lista \"Conversazioni\"",
|
||||
"errorDownloadDirectoryDoesNotExist": "La condivisione file non può essere abilitata perché la destinazione dei download non è stata impostata o è impostata su una cartella che non esiste.",
|
||||
"acquiringTicketsFromServer": "Esecuzione dell'operazione antispam",
|
||||
"acquiredTicketsFromServer": "Operazione antispam completata",
|
||||
"shareProfileMenuTooltop": "Condividi il profilo tramite...",
|
||||
"shareMenuQRCode": "Mostra il codice QR",
|
||||
"enableExperimentQRCode": "Codici QR",
|
||||
"experimentQRCodeDescription": "Il supporto del codice QR consente la condivisione di dati (come l'identità del profilo) tramite codici QR",
|
||||
"localeTr": "Turco \/ Türk",
|
||||
"localeIt": "Italiano \/ Italiano",
|
||||
"fileDownloadUnavailable": "Questo file non sembra disponibile per il download. Il mittente potrebbe aver disabilitato i download per questo file.",
|
||||
"headingReplies": "Risposte",
|
||||
"manageSharedFiles": "Gestisci file condivisi",
|
||||
"messageNoReplies": "Non ci sono risposte a questo messaggio.",
|
||||
"replyingTo": "Risposta a %1",
|
||||
"restartFileShare": "Avvia la condivisione del file",
|
||||
"stopSharingFile": "Interrompi la condivisione del file",
|
||||
"viewReplies": "Visualizza le risposte a questo messaggio",
|
||||
"localeDe": "Tedesco \/ Deutsch",
|
||||
"settingImagePreviewsDescription": "Le immagini e le immagini del profilo verranno scaricate e visualizzate in anteprima automaticamente. Ti consigliamo di non abilitare questo esperimento se usi Cwtch con contatti non attendibili.",
|
||||
"localeNo": "Norvegese \/ Norsk",
|
||||
"localeCy": "Gallese \/ Cymraeg",
|
||||
"localeIt": "Italiano \/ Italiano",
|
||||
"localeFr": "Francese \/ Français",
|
||||
"localePl": "Polacco \/ Polski",
|
||||
"localePt": "Portoghese \/ Portuguesa",
|
||||
|
|
|
@ -1,8 +1,29 @@
|
|||
{
|
||||
"@@locale": "lb",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Tierkesch \/ Türk",
|
||||
"localeIt": "Italienesch",
|
||||
"localeEn": "Englesch \/ English",
|
||||
"localeFr": "Franséisch \/ Français",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Däitsch \/ Deutsch",
|
||||
"localeEn": "Englesch",
|
||||
"localeLb": "Lëtzebuergesch",
|
||||
"localeNo": "Norwegesch",
|
||||
"localeEl": "Griichesch",
|
||||
|
@ -12,8 +33,6 @@
|
|||
"localeEs": "Spuenesch",
|
||||
"localeDa": "Dänesch",
|
||||
"localePt": "Portugisesch",
|
||||
"localeFr": "Franséisch",
|
||||
"localeIt": "Italienesch",
|
||||
"localeCy": "Waliser",
|
||||
"settingImagePreviewsDescription": "Images and Profile Pictures will be downloaded and previewed automatically. We recommend that you do not enable this Experiment if you use Cwtch with untrusted contacts.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
{
|
||||
"@@locale": "nl",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"acknowledgedLabel": "Erkend",
|
||||
"descriptionFileSharing": "Het experiment met het delen van bestanden staat u toe om bestanden van Cwtch-contactpersonen en groepen te verzenden en te ontvangen. Merk op dat het delen van een bestand met een groep tot gevolg zal hebben dat leden van die groep direct via Cwtch verbinding met je maken om het bestand te downloaden.",
|
||||
"descriptionExperimentsGroups": "Het groepsexperiment staat Cwtch toe verbinding te maken met onvertrouwde serverinfrastructuur om communicatie met meer dan één contact te vergemakkelijken.",
|
||||
"notificationPolicyDefaultAll": "Standaard Alle",
|
||||
"conversationNotificationPolicyOptIn": "Opt-In",
|
||||
"acquiringTicketsFromServer": "Antispamuitdaging uitvoeren",
|
||||
"settingAndroidPowerExemption": "Android negeer batterij-optimalisaties",
|
||||
"experimentQRCodeDescription": "Ondersteuning voor QR-codes maakt het delen van gegevens (zoals profielidentiteit) via QR-codes mogelijk",
|
||||
"tooltipSelectACustomProfileImage": "Selecteer een zelf ingestelde profielafbeelding",
|
||||
"settingsAndroidPowerReenablePopup": "Batterijoptimalisatie kan niet opnieuw worden ingeschakeld vanuit Cwtch. Ga naar Android \/ Instellingen \/ Apps \/ Cwtch \/ Batterij en stel Gebruik in op 'Geoptimaliseerd'",
|
||||
"settingAndroidPowerExemptionDescription": "Optioneel: Vraag Android om geen geoptimaliseerd energiebeheer te gebruiken voor Cwtch. Dit zal resulteren in een betere stabiliteit ten koste van meer batterijgebruik.",
|
||||
"acquiredTicketsFromServer": "Antispamuitdaging voltooid",
|
||||
"descriptionExperiments": "Cwtch-experimenten zijn optionele, Opt-In functies die extra functionaliteit toevoegen aan Cwtch die andere privacyoverwegingen kunnen hebben dan traditionele 1: 1 metadata-resistente chat, bijvoorbeeld groepschat, botintegratie enz.",
|
||||
"plainProfileDescription": "We raden aan je Cwtch-profielen te beveiligen met een wachtwoord. Als je geen wachtwoord instelt op dit profiel heeft iedereen die toegang heeft tot dit apparaat mogelijk toegang tot informatie over dit profiel, inclusief gevoelige cryptografische sleutels.",
|
||||
"plainServerDescription": "We raden aan je Cwtch-servers te beveiligen met een wachtwoord. Als je geen wachtwoord instelt op deze server heeft iedereen die toegang heeft tot dit apparaat mogelijk toegang tot informatie over deze server, inclusief gevoelige cryptografische sleutels.",
|
||||
"descriptionStreamerMode": "Wanneer ingeschakeld, maakt deze optie de app visueel meer privé voor streaming of presentatie door bijvoorbeeld profiel- en contactadressen te verbergen",
|
||||
"encryptedProfileDescription": "Het versleutelen van een profiel met een wachtwoord beschermt deze tegen andere mensen die dit apparaat kunnen gebruiken. Versleutelde profielen kunnen niet worden ontsleuteld, weergegeven of geopend totdat het juiste wachtwoord is ingevoerd om ze te ontgrendelen.",
|
||||
"groupInviteSettingsWarning": "Je bent uitgenodigd om lid te worden van een groep! Schakel het Groepschat-experiment in Instellingen in om deze uitnodiging te bekijken.",
|
||||
"descriptionBlockUnknownConnections": "Wanneer ingeschakeld, zal deze optie automatisch verbindingen sluiten van Cwtch gebruikers die niet aan je contactlijst zijn toegevoegd.",
|
||||
"chatHistoryDefault": "Dit gesprek wordt verwijderd wanneer Cwtch wordt gesloten! Berichtgeschiedenis kan per gesprek worden ingeschakeld via het menu Instellingen rechtsboven.",
|
||||
"encryptedServerDescription": "Het versleutelen van een server met een wachtwoord beschermt deze tegen andere mensen die dit apparaat kunnen gebruiken. Versleutelde servers kunnen niet worden ontsleuteld, weergegeven of geopend totdat het juiste wachtwoord is ingevoerd om ze te ontgrendelen.",
|
||||
"settingImagePreviewsDescription": "Afbeeldingen en profielfoto's worden automatisch gedownload en voorvertongingen gemaakt. We raden u aan dit experiment niet in te schakelen als je Cwtch gebruikt met niet-vertrouwde contacten.",
|
||||
"torSettingsEnabledCacheDescription": "Cache de huidige gedownloade Tor-consensus om deze de volgende keer dat Cwtch wordt geopend opnieuw te gebruiken. Hierdoor kan Tor sneller starten. Indien uitgeschakeld, zal Cwtch de gegevens in de cache opschonen bij het opstarten.",
|
||||
"fileSharingSettingsDownloadFolderDescription": "Wanneer bestanden automatisch worden gedownload (bijv. afbeedingen, wanneer voorvertoningen van afbeeldingen zijn ingeschakeld), is een standaardlocatie nodig om de bestanden naar te downloaden.",
|
||||
"torSettingsUseCustomTorServiceConfigurastionDescription": "Overschrijf de standaard tor-configuratie. Waarschuwing: dit kan gevaarlijk zijn. Zet dit alleen aan als je weet wat je doet.",
|
||||
"torSettingsUseCustomTorServiceConfiguration": "Gebruik een zelf ingestelde Tor-serviceconfiguratie (torrc)",
|
||||
"descriptionACNCircuitInfo": "Uitgebreide informatie over het pad dat het anonieme communicatienetwerk gebruikt om verbinding te maken met dit gesprek.",
|
||||
"conversationNotificationPolicySettingDescription": "Meldingsgedrag voor dit gesprek beheren",
|
||||
"notificationContentSimpleEvent": "Generieke melding",
|
||||
"exportProfileTooltip": "Maak een back-up van dit profiel naar een versleuteld bestand. Het versleutelde bestand kan in een andere Cwtch-app worden geïmporteerd.",
|
||||
"blockUnknownConnectionsEnabledDescription": "Verbindingen van onbekende contacten worden geblokkeerd. Je kunt dit wijzigen in Instellingen",
|
||||
"messageEnableFileSharing": "Schakel het experiment voor het delen van bestanden in om dit bericht te bekijken.",
|
||||
"serverAutostartDescription": "Bepaalt of de applicatie de server automatisch start bij het opstarten",
|
||||
"serverDescriptionDescription": "Je beschrijving van de server alleen voor persoonlijk beheer, zal nooit worden gedeeld",
|
||||
"membershipDescription": "Hieronder staat een lijst met gebruikers die berichten naar de groep hebben gestuurd. Deze lijst bevat mogelijk niet alle gebruikers die toegang hebben tot de groep.",
|
||||
"defaultScalingText": "Standaardtekstgrootte (schaalfactor:",
|
||||
"fileSharingSettingsDownloadFolderTooltip": "Bladeren om een andere standaardmap voor gedownloade bestanden te selecteren.",
|
||||
"fileDownloadUnavailable": "Dit bestand lijkt niet beschikbaar om te downloaden. Het kan zijn dat de verzender downlaoden voor dit bestand heeft uitgeschakeld.",
|
||||
"errorDownloadDirectoryDoesNotExist": "Bestanden delen kan niet worden ingeschakeld omdat de downloadmap niet is ingesteld of is ingesteld op een map die niet bestaat.",
|
||||
"settingTheme": "Lichte thema's gebruiken",
|
||||
"noPasswordWarning": "Het niet gebruiken van een wachtwoord voor dit account betekent dat alle lokaal opgeslagen gegevens niet worden versleuteld",
|
||||
"savePeerHistoryDescription": "Bepaalt of geschiedenis gekoppeld aan de contactpersoon moet worden verwijderd.",
|
||||
"dmTooltip": "Klik voor DM",
|
||||
"debugLog": "Zet console debug logging aan",
|
||||
"addContactFirst": "Voeg een contact toe of kies een contact om te beginnen met chatten.",
|
||||
"experimentClickableLinksDescription": "Het klikbare links experiment maakt het mogelijk op URLs te klikken in berichten",
|
||||
"enableExperimentClickableLinks": "Klikbare links inschakelen",
|
||||
"groupsOnThisServerLabel": "Groepen waarin ik zit gehost op deze server",
|
||||
"displayNameTooltip": "Voer een weergavenaam in",
|
||||
"tooltipBackToMessageEditing": "Terug naar bericht bewerken",
|
||||
"editServerTitle": "Server bewerken",
|
||||
"editProfile": "Bewerk profiel",
|
||||
"manageKnownServersButton": "Beheer bekende servers",
|
||||
"manageKnownServersLong": "Beheer bekende servers",
|
||||
"themeNameVampire": "Vampier",
|
||||
"sendAnInvitation": "Je hebt een uitnodiging gestuurd voor: ",
|
||||
"contactSuggestion": "Dit is een contactsuggestie voor: ",
|
||||
"successfullAddedContact": "Succesvol toegevoegd ",
|
||||
"saveProfileBtn": "Profiel opslaan",
|
||||
"deleteProfileBtn": "Verwijder profiel",
|
||||
"clickableLinksWarning": "Het openen van deze URL zal een toepassing buiten Cwtch opstarten en kan metadata onthullen of anderszins de beveiliging van Cwtch in gevaar brengen. Open alleen URL's van mensen die je vertrouwt. Weet je zeker dat je door wilt gaan?",
|
||||
"clickableLinkError": "Fout opgetreden bij het openen van URL",
|
||||
"thisFeatureRequiresGroupExpermientsToBeEnabled": "Voor deze functie moet het Groepen experiment zijn ingeschakeld in Instellingen",
|
||||
"formattingExperiment": "Berichtopmaak",
|
||||
"successfullyImportedProfile": "Profiel succesvol geïmporteerd: %profile",
|
||||
"failedToImportProfile": "Fout bij importeren profiel",
|
||||
"notificationContentContactInfo": "Gespreksinformatie",
|
||||
"notificationPolicySettingLabel": "Beleid voor meldingen",
|
||||
"conversationNotificationPolicySettingLabel": "Beleid voor gespreksmeldingen",
|
||||
"notificationContentSettingDescription": "Regelt de inhoud van gespreksmeldingen",
|
||||
"notificationPolicySettingDescription": "Regelt het standaard meldingsgedrag van de applicatie",
|
||||
"notificationContentSettingLabel": "Inhoud van meldingen",
|
||||
"notificationPolicyOptIn": "Opt In",
|
||||
"torSettingsErrorSettingPort": "Poortnummer moet liggen tussen 1 en 65535",
|
||||
"storageMigrationModalMessage": "Profielen migreren naar een nieuw opslagformaat. Dit kan een paar minuten duren...",
|
||||
"settingImagePreviews": "Voorvertoningen van afbeeldingen en profielfoto's",
|
||||
"settingUIColumnPortrait": "UI-kolommen in portret modus",
|
||||
"settingUIColumnOptionSame": "Zelfde als portret modus instelling",
|
||||
"settingUIColumnLandscape": "UI-kolommen in liggende modus",
|
||||
"tooltipRemoveThisQuotedMessage": "Verwijder geciteerd bericht.",
|
||||
"tooltipReplyToThisMessage": "Reageer op dit bericht",
|
||||
"shutdownCwtchDialog": "Weet je zeker dat je Cwtch wilt afsluiten? Alle verbindingen en de applicatie worden gesloten.",
|
||||
"malformedMessage": "Misvormd bericht",
|
||||
"profileDeleteSuccess": "Profiel succesvol verwijderd",
|
||||
"importProfileTooltip": "Gebruik een versleutelde Cwtch backup om een profiel binnen te halen dat in een andere instantie van Cwtch is aangemaakt.",
|
||||
"unlockProfileTip": "Maak of ontgrendel een profiel om te beginnen!",
|
||||
"unlockServerTip": "Maak of ontgrendel een server om te beginnen!",
|
||||
"createProfileToBegin": "Maak of ontgrendel een profiel om te beginnen",
|
||||
"addServerFirst": "Je moet een server toevoegen voordat je een groep kunt aanmaken",
|
||||
"createProfileBtn": "Profiel aanmaken",
|
||||
"tooltipUnlockProfiles": "Ontgrendel versleutelde profielen door hun wachtwoord in te voeren.",
|
||||
"addNewItem": "Voeg een nieuw item toe aan de lijst",
|
||||
"addListItem": "Een nieuw lijstitem toevoegen",
|
||||
"peerOfflineMessage": "Contact is offline, berichten kunnen nu niet worden afgeleverd",
|
||||
"acceptGroupInviteLabel": "Wil je de uitnodiging accepteren voor",
|
||||
"profileOnionLabel": "Stuur dit adres naar contacten waarmee je in contact wilt komen",
|
||||
"password2Label": "Wachtwoord opnieuw invoeren",
|
||||
"nickChangeSuccess": "Profielnaam succesvol gewijzigd",
|
||||
"inviteToGroup": "Je bent uitgenodigd om lid te worden van een groep:",
|
||||
"messageFormattingDescription": "Rijke tekstopmaak in getoonde berichten inschakelen, bijv. **vetgedrukt** en *cursief*",
|
||||
"labelACNCircuitInfo": "ACN circuitinfo",
|
||||
"torSettingsCustomControlPortDescription": "Gebruik zelf ingestelde poort voor controleverbindingen naar de Tor proxy",
|
||||
"torSettingsCustomControlPort": "Zelf ingestelde control port",
|
||||
"torSettingsCustomSocksPortDescription": "Gebruik een zelf ingestelde poort voor dataverbindingen naar de Tor proxy",
|
||||
"torSettingsCustomSocksPort": "Zelf ingesltelde SOCKS-poort",
|
||||
"torSettingsEnabledAdvancedDescription": "Gebruik een bestaande Tor-service op je systeem of wijzig de parameters van de Cwtch Tor-service",
|
||||
"torSettingsEnabledAdvanced": "Geavanceerde Tor-configuratie inschakelen",
|
||||
"msgAddToAccept": "Voeg dit account toe aan je contacten om dit bestand te accepteren.",
|
||||
"msgConfirmSend": "Weet je zeker dat je wilt verzenden",
|
||||
"msgFileTooBig": "Bestanden mogen niet groter zijn dan 10 GB",
|
||||
"settingDownloadFolder": "Map downloaden",
|
||||
"importLocalServerSelectText": "Selecteer lokale server",
|
||||
"importLocalServerLabel": "Lokaal gehoste server importeren",
|
||||
"verfiyResumeButton": "Verifiëren\/hervatten",
|
||||
"fileCheckingStatus": "Downloadstatus controleren",
|
||||
"fileInterrupted": "Onderbroken",
|
||||
"fileSavedTo": "Opgeslagen in",
|
||||
"deleteServerConfirmBtn": "Server echt verwijderen",
|
||||
"deleteServerSuccess": "Server succesvol verwijderd",
|
||||
"enterCurrentPasswordForDeleteServer": "Voer huidige wachtwoord in om deze server te verwijderen",
|
||||
"settingServersDescription": "Het servers hosten experiment maakt het mogelijk Cwtch-servers te hosten en te beheren",
|
||||
"settingServers": "Servers hosten",
|
||||
"enterServerPassword": "Voer wachtwoord in om server te ontgrendelen",
|
||||
"serversManagerTitleLong": "Servers die je host",
|
||||
"serverAutostartLabel": "Automatisch starten",
|
||||
"serverEnabled": "Server ingeschakeld",
|
||||
"messageFileOffered": "Contact biedt aan om je een bestand te sturen",
|
||||
"contactGoto": "Ga naar gesprek met %1",
|
||||
"tooltipOpenSettings": "Open het instellingenpaneel",
|
||||
"titleManageProfiles": "Cwtch profielen beheren",
|
||||
"passwordChangeError": "Fout bij wijzigen wachtwoord: opgegeven wachtwoord geweigerd",
|
||||
"passwordErrorEmpty": "Wachtwoord mag niet leeg zijn",
|
||||
"peerNotOnline": "Contact is offline. De toepassingen kunnen op dit moment niet worden gebruikt.",
|
||||
"manageSharedFiles": "Gedeelde bestanden beheren",
|
||||
"tooltipPreviewFormatting": "Voorbeeld van berichtopmaak bekijken",
|
||||
"tooltipItalicize": "Cursief",
|
||||
"okButton": "Oké",
|
||||
"tooltipBoldText": "Vetgedrukt",
|
||||
"shareProfileMenuTooltop": "Profiel delen via...",
|
||||
"tooltipUnpinConversation": "Gesprek bovenaan 'Gesprekken' losmaken",
|
||||
"tooltipPinConversation": "Gesprek bovenaan 'Gesprekken' vastprikken",
|
||||
"replyingTo": "Reageren op %1",
|
||||
"viewReplies": "Reacties op dit bericht bekijken",
|
||||
"messageNoReplies": "Er zijn geen reacties op dit bericht.",
|
||||
"stopSharingFile": "Stop delen bestand",
|
||||
"restartFileShare": "Start delen bestand",
|
||||
"shuttingDownApp": "Afsluiten...",
|
||||
"importProfile": "Profiel importeren",
|
||||
"exportProfile": "Profiel exporteren",
|
||||
"localeDa": "Deens \/ Dansk",
|
||||
"localeCy": "Welsh \/ Cymraeg",
|
||||
"rejected": "Geweigerd!",
|
||||
"tooltipRejectContactRequest": "Weiger dit contactverzoek",
|
||||
"tooltipAcceptContactRequest": "Accepteer dit contactverzoek.",
|
||||
"notificationNewMessageFromGroup": "Nieuw bericht in een groep!",
|
||||
"notificationNewMessageFromPeer": "Nieuw bericht van een contact!",
|
||||
"accepted": "Geaccepteerd!",
|
||||
"reallyLeaveThisGroupPrompt": "Weet je zeker dat je dit gesprek wilt verlaten? Alle berichten en attributen worden verwijderd.",
|
||||
"yesLeave": "Ja, verlaat dit gesprek",
|
||||
"leaveConversation": "Verlaat dit gesprek",
|
||||
"titleManageServers": "Servers beheren",
|
||||
"invalidImportString": "Ongeldige import string",
|
||||
"enterCurrentPasswordForDelete": "Voer huidige wachtwoord in om dit profiel te verwijderen.",
|
||||
"enableGroups": "Groepschat inschakelen",
|
||||
"networkStatusConnecting": "Verbinding maken met netwerk en contacten...",
|
||||
"networkStatusAttemptingTor": "Proberen verbinding te maken met het Tor-netwerk",
|
||||
"networkStatusDisconnected": "Verbinding met internet verbroken, controleer je verbinding",
|
||||
"viewGroupMembershipTooltip": "Groepslidmaatschap weergeven",
|
||||
"zoomLabel": "Interface zoom (beïnvloedt vooral de grootte van tekst en knoppen)",
|
||||
"error0ProfilesLoadedForPassword": "0 profielen geladen met dat wachtwoord",
|
||||
"enterProfilePassword": "Voer een wachtwoord in om je profielen te bekijken",
|
||||
"addNewProfileBtn": "Nieuw profiel toevoegen",
|
||||
"deleteProfileConfirmBtn": "Profiel echt verwijderen",
|
||||
"deleteConfirmLabel": "Typ VERWIJDEREN om te bevestigen",
|
||||
"couldNotSendMsgError": "Kan bericht niet verzenden",
|
||||
"retrievingManifestMessage": "Bestandsinformatie ophalen...",
|
||||
"streamerModeLabel": "Streamer-\/presentatiemodus",
|
||||
"archiveConversation": "Archiveer dit gesprek",
|
||||
"blockedMessageMessage": "Dit bericht is van een profiel dat je hebt geblokkeerd.",
|
||||
"placeholderEnterMessage": "Type een bericht...",
|
||||
"deleteProfileSuccess": "Profiel succesvol verwijderd",
|
||||
"sendInvite": "Een contact- of groepsuitnodiging verzenden",
|
||||
"sendMessage": "Bericht versturen",
|
||||
"resetTor": "Resetten",
|
||||
"tooltipAddContact": "Een nieuw contact of gesprek toevoegen",
|
||||
"contactAlreadyExists": "Contact bestaat al",
|
||||
"conversationSettings": "Gespreksinstellingen",
|
||||
"settingFileSharing": "Bestanden delen",
|
||||
"messageFileSent": "Je hebt een bestand verzonden",
|
||||
"tooltipCode": "Code \/ Monospace",
|
||||
"tooltipStrikethrough": "Doorhalen",
|
||||
"tooltipSuperscript": "Superscript",
|
||||
"tooltipSubscript": "Subscript",
|
||||
"localeNl": "Nederlands \/ Dutch",
|
||||
"pendingLabel": "In afwachting",
|
||||
"builddate": "Gebouwd op: %2",
|
||||
"versionTor": "Versie %1 met tor %2",
|
||||
"blockUnknownLabel": "Blokkeer onbekende contacten",
|
||||
"versionBuilddate": "Versie: %1 Gebouwd op: %2",
|
||||
"defaultProfileName": "Alice",
|
||||
"update": "Update",
|
||||
"viewServerInfo": "Serverinfo",
|
||||
"serverNotSynced": "Nieuwe berichten synchroniseren (dit kan even duren)...",
|
||||
"serverConnectivityDisconnected": "Server verbinding verbroken",
|
||||
"pasteAddressToAddContact": "Plak hier een cwtch adres, uitnodiging of sleutelbundel om een nieuw gesprek toe te voegen",
|
||||
"todoPlaceholder": "Todo...",
|
||||
"experimentsEnabled": "Experimenten inschakelen",
|
||||
"settingInterfaceZoom": "Zoomniveau",
|
||||
"yourDisplayName": "Jouw weergavenaam",
|
||||
"profileName": "Weergavenaam",
|
||||
"addProfileTitle": "Nieuw profiel toevoegen",
|
||||
"editProfileTitle": "Bewerk profiel",
|
||||
"copiedToClipboardNotification": "Gekopieerd naar klembord",
|
||||
"puzzleGameBtn": "Puzzelspel",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"addListItemBtn": "Item toevoegen",
|
||||
"searchList": "Zoeklijst",
|
||||
"postNewBulletinLabel": "Nieuw bulletin plaatsen",
|
||||
"newBulletinLabel": "Nieuw bulletin",
|
||||
"joinGroupTab": "Lid worden van een groep",
|
||||
"joinGroup": "Lid worden van groep",
|
||||
"settingsGroupExperiments": "Experimenten",
|
||||
"settingsGroupAppearance": "Uiterlijk",
|
||||
"settingGroupBehaviour": "Gedrag",
|
||||
"torSettingsEnableCache": "Cache Tor-consensus",
|
||||
"serverTotalMessagesLabel": "Totaal aantal berichten",
|
||||
"serverMetricsLabel": "Serverstatistieken",
|
||||
"manageKnownServersShort": "Servers",
|
||||
"newMessagesLabel": "Nieuwe berichten",
|
||||
"localeRU": "Russisch \/ Русский",
|
||||
"copyServerKeys": "Sleutels kopiëren",
|
||||
"shutdownCwtchAction": "Cwtch afsluiten",
|
||||
"shutdownCwtchTooltip": "Cwtch afsluiten",
|
||||
"shutdownCwtchDialogTitle": "Cwtch afsluiten?",
|
||||
"serverSynced": "Gesynchroniseerd",
|
||||
"defaultGroupName": "Geweldige groep",
|
||||
"shareMenuQRCode": "Toon QR-code",
|
||||
"localeTr": "Turks \/ Türk",
|
||||
"localeEl": "Grieks \/ Ελληνικά",
|
||||
"localeNo": "Noors \/ Norsk",
|
||||
"localeLb": "Luxemburgs \/ Lëtzebuergesch",
|
||||
"localeRo": "Roemeens \/ Română",
|
||||
"newMessageNotificationConversationInfo": "Nieuw bericht van %1",
|
||||
"newMessageNotificationSimple": "Nieuw bericht",
|
||||
"notificationPolicyMute": "Dempen",
|
||||
"labelTorNetwork": "Tor netwerk",
|
||||
"btnSendFile": "Bestand versturen",
|
||||
"loadingCwtch": "Cwtch laden...",
|
||||
"themeColorLabel": "Kleurenthema",
|
||||
"themeNameNeon2": "Neon2",
|
||||
"themeNameNeon1": "Neon1",
|
||||
"themeNameMidnight": "Middernacht",
|
||||
"themeNameMermaid": "Zeemeermin",
|
||||
"themeNamePumpkin": "Pompoen",
|
||||
"themeNameGhost": "Geest",
|
||||
"themeNameWitch": "Heks",
|
||||
"themeNameCwtch": "Cwtch",
|
||||
"serverConnectionsLabel": "Verbinding",
|
||||
"copyAddress": "Adres kopiëren",
|
||||
"saveServerButton": "Server opslaan",
|
||||
"serverEnabledDescription": "Start of stop de server",
|
||||
"serverDescriptionLabel": "Server beschrijving",
|
||||
"serverAddress": "Server adres",
|
||||
"titleManageProfilesShort": "Profielen",
|
||||
"tooltipSendFile": "Verstuur bestand",
|
||||
"labelFilesize": "Grootte",
|
||||
"labelFilename": "Bestandsnaam",
|
||||
"openFolderButton": "Open map",
|
||||
"torNetworkStatus": "Tor netwerk status",
|
||||
"localeDe": "Duits \/ Deutsch",
|
||||
"localePt": "Portugees \/ Portuguesa",
|
||||
"localeFr": "Frans \/ Français",
|
||||
"localeEn": "Engels \/ English",
|
||||
"unlock": "Ontgrendelen",
|
||||
"radioNoPassword": "Onversleuteld (Geen wachtwoord)",
|
||||
"newProfile": "Nieuw profiel",
|
||||
"inviteToGroupLabel": "Uitnodigen voor groep",
|
||||
"newGroupBtn": "Nieuwe groep aanmaken",
|
||||
"createGroupBtn": "Aanmaken",
|
||||
"createGroupTitle": "Groep aanmaken",
|
||||
"unblockBtn": "Contact deblokkeren",
|
||||
"cancel": "Annuleren",
|
||||
"serversManagerTitleShort": "Servers",
|
||||
"showMessageButton": "Toon bericht",
|
||||
"settingUIColumnDouble14Ratio": "Dubbel (1:4)",
|
||||
"settingUIColumnDouble12Ratio": "Dubbel (1:2)",
|
||||
"settingUIColumnSingle": "Enkel",
|
||||
"localePl": "Pools \/ Polski",
|
||||
"tooltipHidePassword": "Verberg wachtwoord",
|
||||
"tooltipShowPassword": "Toon wachtwoord",
|
||||
"torStatus": "Tor status",
|
||||
"torVersion": "Tor versie",
|
||||
"newPassword": "Nieuw wachtwoord",
|
||||
"titleManageContacts": "Gesprekken",
|
||||
"localeIt": "Italiaans \/ taliano",
|
||||
"localeEs": "Spaans \/ Español",
|
||||
"newConnectionPaneTitle": "Nieuwe verbinding",
|
||||
"networkStatusOnline": "Online",
|
||||
"loadingTor": "Tor laden...",
|
||||
"smallTextLabel": "Klein",
|
||||
"largeTextLabel": "Groot",
|
||||
"settingLanguage": "Taal",
|
||||
"yourServers": "Jouw servers",
|
||||
"yourProfiles": "Jouw profielen",
|
||||
"password": "Wachtwoord",
|
||||
"passwordErrorMatch": "Wachtwoorden komen niet overeen",
|
||||
"clickableLinksCopy": "Kopieer URL",
|
||||
"clickableLinkOpen": "Open URL",
|
||||
"addServerTooltip": "Nieuwe server toevoegen",
|
||||
"addServerTitle": "Server toevoegen",
|
||||
"importLocalServerButton": "Importeer %1",
|
||||
"headingReplies": "Reacties",
|
||||
"fieldDescriptionLabel": "Beschrijving",
|
||||
"enableExperimentQRCode": "QR-codes",
|
||||
"downloadFileButton": "Download",
|
||||
"deleteConfirmText": "VERWIJDER",
|
||||
"deleteBtn": "Verwijderen",
|
||||
"cwtchSettingsTitle": "Cwtch instellingen",
|
||||
"conversationNotificationPolicyNever": "Nooit",
|
||||
"conversationNotificationPolicyDefault": "Standaard",
|
||||
"addContactConfirm": "Contact %1 toevoegen",
|
||||
"addContact": "Contact toevoegen",
|
||||
"version": "Versie %1",
|
||||
"themeDark": "Donker",
|
||||
"themeLight": "Licht",
|
||||
"currentPasswordLabel": "Huidig wachtwoord",
|
||||
"password1Label": "Wachtwoord",
|
||||
"radioUsePassword": "Wachtwoord",
|
||||
"savePeerHistory": "Geschiedenis opslaan",
|
||||
"dontSavePeerHistory": "Geschiedenis verwijderen",
|
||||
"displayNameLabel": "Weergavenaam",
|
||||
"rejectGroupBtn": "Weigeren",
|
||||
"acceptGroupBtn": "Accepteren",
|
||||
"copyBtn": "Kopieer",
|
||||
"peerBlockedMessage": "Contact is geblokkeerd",
|
||||
"blockBtn": "Blokkeer contact",
|
||||
"saveBtn": "Opslaan",
|
||||
"addressLabel": "Adres",
|
||||
"listsBtn": "Lijsten",
|
||||
"chatBtn": "Chat",
|
||||
"inviteBtn": "Uitnodigen",
|
||||
"groupNameLabel": "Groepsnaam",
|
||||
"serverConnectivityConnected": "Server verbonden",
|
||||
"serverInfo": "Server informatie",
|
||||
"titlePlaceholder": "titel...",
|
||||
"createGroup": "Groep aanmaken",
|
||||
"createGroupTab": "Nieuwe groep",
|
||||
"peerAddress": "Adres",
|
||||
"peerName": "Naam",
|
||||
"blocked": "Geblokkeerd",
|
||||
"search": "Zoeken...",
|
||||
"serverLabel": "Server",
|
||||
"invitationLabel": "Uitnodiging",
|
||||
"addPeer": "Contact toevoegen",
|
||||
"groupAddr": "Adres",
|
||||
"server": "Server",
|
||||
"invitation": "Uitnodiging",
|
||||
"addPeerTab": "Contact toevoegen"
|
||||
}
|
|
@ -1,8 +1,29 @@
|
|||
{
|
||||
"@@locale": "no",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Tyrkisk \/ Türk",
|
||||
"localeIt": "Italiensk",
|
||||
"localeEn": "Engelsk \/ English",
|
||||
"localeFr": "Fransk \/ Français",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Tysk \/ Deutsch",
|
||||
"localeEn": "Engelsk",
|
||||
"localeLb": "Luxemburgsk",
|
||||
"localeNo": "Norsk",
|
||||
"localeEl": "Gresk",
|
||||
|
@ -12,8 +33,6 @@
|
|||
"localeEs": "Spansk",
|
||||
"localeDa": "Dansk",
|
||||
"localePt": "Portugisisk",
|
||||
"localeFr": "Fransk",
|
||||
"localeIt": "Italiensk",
|
||||
"localeCy": "Walisisk",
|
||||
"settingImagePreviewsDescription": "Bilder vil bli lastet ned og forhåndsvist automatisk. Merk at forhåndsvisning av bilder kan medføre en sikkerhetsrisiko og bør ikke tillates dersom du bruker Cwtch med kontakter du ikke stoler på. Profilbilder er planlagt for Cwtch 1.6.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
|
|
|
@ -1,6 +1,27 @@
|
|||
{
|
||||
"@@locale": "pl",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Turecki \/ Türk",
|
||||
"localeIt": "Włoski \/ Italiano",
|
||||
"localeEn": "Angielski \/ English",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Niemiecki \/ Deutsch",
|
||||
"serverLabel": "Server",
|
||||
"deleteBtn": "Usuń",
|
||||
|
@ -19,10 +40,8 @@
|
|||
"localePt": "Portugalski \/ Portuguesa",
|
||||
"settingTheme": "Użyj motywów świetlnych",
|
||||
"localePl": "Polski \/ Polski",
|
||||
"localeIt": "Włoski \/ Italiana",
|
||||
"localeFr": "Francuski \/ Français",
|
||||
"localeDa": "Duński \/ Dansk",
|
||||
"localeEn": "Angielski \/ Angielski",
|
||||
"localeCy": "Walijski \/ Cymraeg",
|
||||
"tooltipStrikethrough": "Przekreślenie",
|
||||
"localeLb": "Luksemburski \/ Lëtzebuergesch",
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
{
|
||||
"@@locale": "pt",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Turco \/ Türk",
|
||||
"localeIt": "Italian \/ Italiano",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Alemao \/ Deutsch",
|
||||
"localeEn": "English \/ English",
|
||||
"localeLb": "Luxembourgish \/ Lëtzebuergesch",
|
||||
|
@ -13,7 +33,6 @@
|
|||
"localeDa": "Danish \/ Dansk",
|
||||
"localePt": "Portuguese \/ Portuguesa",
|
||||
"localeFr": "French \/ Français",
|
||||
"localeIt": "Italian \/ Italiana",
|
||||
"localeCy": "Welsh \/ Cymraeg",
|
||||
"settingImagePreviewsDescription": "Images and Profile Pictures will be downloaded and previewed automatically. We recommend that you do not enable this Experiment if you use Cwtch with untrusted contacts.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
{
|
||||
"@@locale": "ptbr",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "O suporte a QR Code permite o compartilhamento de dados (como identidade de perfil) através dos QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Mostrar QR Code",
|
||||
"shareProfileMenuTooltop": "Compartilhar perfil por...",
|
||||
"acquiredTicketsFromServer": "Desafio anti-spam completo",
|
||||
"acquiringTicketsFromServer": "Realizar o desafio anti-spam",
|
||||
"errorDownloadDirectoryDoesNotExist": "O compartilhamento de arquivos não pode ser ativado porque a Pasta de Download não foi definida, ou está definida para uma pasta que não existe.",
|
||||
"localeTr": "Turco \/ Türk",
|
||||
"localeIt": "Italian \/ Italiano",
|
||||
"tooltipUnpinConversation": "Desafixar conversa a partir do topo de \"Conversations\"",
|
||||
"tooltipPinConversation": "Fixar conversa para o topo de \"Conversations\"",
|
||||
"replyingTo": "Responder para %1",
|
||||
"fileDownloadUnavailable": "Este arquivo aparece indisponível para download. O remetente pode ter desativado os downloads para este arquivo.",
|
||||
"messageNoReplies": "Não há respostas para esta mensagem.",
|
||||
"headingReplies": "Respostas",
|
||||
"viewReplies": "Ver respostas para esta mensagem",
|
||||
"restartFileShare": "Iniciar compartilhamento de arquivo",
|
||||
"stopSharingFile": "Parar compartilhamento de arquivo",
|
||||
"manageSharedFiles": "Gerenciar arquivos compartilhados",
|
||||
"localeDe": "Alemao \/ Deutsch",
|
||||
"localeEn": "English \/ English",
|
||||
"localeLb": "Luxembourgish \/ Lëtzebuergesch",
|
||||
"localeNo": "Norwegian \/ Norsk",
|
||||
"localeEl": "Greek \/ Ελληνικά",
|
||||
"localePl": "Polish \/ Polski",
|
||||
"localeRo": "Romanian \/ Română",
|
||||
"localeRU": "Russian \/ Русский",
|
||||
"localeEs": "Spanish \/ Español",
|
||||
"localeDa": "Danish \/ Dansk",
|
||||
"localePt": "Portuguese \/ Portuguesa",
|
||||
"localePtBr": "Brazilian Portuguese \/ Português do Brasil",
|
||||
"localeFr": "French \/ Français",
|
||||
"localeCy": "Welsh \/ Cymraeg",
|
||||
"settingImagePreviewsDescription": "Imagens e Fotos de Perfil serão baixadas e visualizadas automaticamente. Recomendamos que você não ative esta Experiência se usar Cwtch com contatos não confiáveis.",
|
||||
"tooltipPreviewFormatting": "Pré-visualização da formatação da mensagem",
|
||||
"tooltipCode": "Code \/ Monoespaçado",
|
||||
"tooltipStrikethrough": "Riscado",
|
||||
"tooltipSubscript": "Sobrescrito",
|
||||
"tooltipSuperscript": "Superescrito",
|
||||
"tooltipItalicize": "Itálico",
|
||||
"tooltipBackToMessageEditing": "Voltar a edição de mensagem",
|
||||
"tooltipBoldText": "Negrito",
|
||||
"okButton": "OK",
|
||||
"settingsAndroidPowerReenablePopup": "Não é possível reativar a Otimização da Bateria de dentro da Cwtch. Favor ir para Android \/ Settings \/ Apps \/ Cwtch \/ Battery e definir o uso como 'Otimizado'",
|
||||
"settingAndroidPowerExemptionDescription": "Opcional: Solicite ao Android que isente o Cwtch do gerenciamento otimizado de energia. Isto resultará em melhor estabilidade ao custo de maior uso da bateria.",
|
||||
"settingAndroidPowerExemption": "Ignorar Otimização de Bateria do Android",
|
||||
"thisFeatureRequiresGroupExpermientsToBeEnabled": "Esta característica requer que a experiência de grupo seja habilitada em Configurações",
|
||||
"messageFormattingDescription": "Permitir a formatação de texto rico em mensagens exibidas, por exemplo **negrito** e *itálico*",
|
||||
"formattingExperiment": "Formatação de mensagem",
|
||||
"clickableLinkError": "Erro encontrado durante a tentativa de abrir a URL",
|
||||
"clickableLinksCopy": "Copiar URL",
|
||||
"clickableLinkOpen": "Abrir URL",
|
||||
"clickableLinksWarning": "A abertura deste URL abrirá um aplicativo fora do Cwtch e poderá revelar metadados ou comprometer de outra forma a segurança do Cwtch. Abra somente URLs de pessoas em quem você confia. Você tem certeza de que quer continuar?",
|
||||
"shuttingDownApp": "Desligando...",
|
||||
"successfullyImportedProfile": "Perfil importado com sucesso: %profile",
|
||||
"failedToImportProfile": "Erro ao importar perfil",
|
||||
"importProfileTooltip": "Use um backup criptografado do Cwtch para trazer um perfil criado em outra instância do Cwtch.",
|
||||
"importProfile": "Importar perfil",
|
||||
"exportProfileTooltip": "Faça um backup deste perfil em um arquivo criptografado. O arquivo criptografado pode ser importado para outro aplicativo Cwtch.",
|
||||
"exportProfile": "Exportar Perfil",
|
||||
"newMessageNotificationConversationInfo": "Nova mensagem de %1",
|
||||
"newMessageNotificationSimple": "Nova Mensagem",
|
||||
"notificationContentContactInfo": "Informações da Conversa",
|
||||
"notificationContentSimpleEvent": "Evento Simples",
|
||||
"conversationNotificationPolicySettingDescription": "controle de comportamento de notificação para esta conversa",
|
||||
"conversationNotificationPolicySettingLabel": "Política de Notificação de Conversas",
|
||||
"settingsGroupExperiments": "Experimentos",
|
||||
"settingsGroupAppearance": "Aparência",
|
||||
"settingGroupBehaviour": "Comportamento",
|
||||
"notificationContentSettingDescription": "Controla o conteúdo das notificações de conversas",
|
||||
"notificationPolicySettingDescription": "Controla o comportamento padrão de notificação do aplicativo",
|
||||
"notificationContentSettingLabel": "Conteúdo da Notificação",
|
||||
"notificationPolicySettingLabel": "Política de Notificação",
|
||||
"conversationNotificationPolicyNever": "Nunca",
|
||||
"conversationNotificationPolicyOptIn": "Optar por",
|
||||
"conversationNotificationPolicyDefault": "Padrão",
|
||||
"notificationPolicyDefaultAll": "Todos por padrão",
|
||||
"notificationPolicyOptIn": "Optar por",
|
||||
"notificationPolicyMute": "Silenciar",
|
||||
"tooltipSelectACustomProfileImage": "Selecionar uma imagem de perfil personalizada",
|
||||
"torSettingsEnabledCacheDescription": "Mantém em cache os dados atuais do Tor para reutilizar da próxima vez que o Cwtch for aberto. Isto permitirá que o Tor comece mais rápido. Quando desativado, o Cwtch irá eliminar os dados em cache ao iniciar.",
|
||||
"torSettingsEnableCache": "Consenso de Cache do Tor",
|
||||
"labelTorNetwork": "Rede Tor",
|
||||
"descriptionACNCircuitInfo": "Informações detalhadas sobre o caminho que a rede de comunicação anônima está utilizando para se conectar a esta conversa.",
|
||||
"labelACNCircuitInfo": "Informações do Circuito ACN",
|
||||
"fileSharingSettingsDownloadFolderTooltip": "Navegue para selecionar uma pasta padrão diferente para arquivos baixados.",
|
||||
"fileSharingSettingsDownloadFolderDescription": "Quando os arquivos são baixados automaticamente (por exemplo, prévias de imagem, quando as pré-visualizações de imagem estão habilitadas) é necessário um local padrão para o download destes arquivos.",
|
||||
"torSettingsErrorSettingPort": "O número da porta deve ser entre 1 e 65535",
|
||||
"torSettingsUseCustomTorServiceConfigurastionDescription": "Substituir a configuração padrão do Tor. Atenção: Isto pode ser perigoso. Só use isto se você souber o que está fazendo.",
|
||||
"torSettingsUseCustomTorServiceConfiguration": "Use uma configuração personalizada de serviço do Tor (torrc)",
|
||||
"torSettingsCustomControlPortDescription": "Use uma porta personalizada para conexões de controle para o proxy Tor",
|
||||
"torSettingsCustomControlPort": "Porta de controle personalizada",
|
||||
"torSettingsCustomSocksPortDescription": "Use uma porta personalizada para conexões de dados com o proxy Tor",
|
||||
"torSettingsCustomSocksPort": "Porta SOCKS personalizada",
|
||||
"torSettingsEnabledAdvancedDescription": "Use um serviço Tor existente em seu sistema, ou altere os parâmetros do serviço Cwtch Tor",
|
||||
"torSettingsEnabledAdvanced": "Habilitar configuração avançada do Tor",
|
||||
"msgAddToAccept": "Adicione esta conta a seus contatos para poder aceitar este arquivo.",
|
||||
"btnSendFile": "Enviar arquivo",
|
||||
"msgConfirmSend": "Você tem certeza de que deseja enviar",
|
||||
"msgFileTooBig": "O tamanho do arquivo não pode exceder 10 GB",
|
||||
"storageMigrationModalMessage": "Migração dos perfis para um novo formato de armazenamento. Isto pode levar alguns minutos...",
|
||||
"loadingCwtch": "Carregando o Cwtch...",
|
||||
"themeColorLabel": "Cor do tema",
|
||||
"themeNameNeon2": "Neon2",
|
||||
"themeNameNeon1": "Neon1",
|
||||
"themeNameMidnight": "Meia-noite",
|
||||
"themeNameMermaid": "Sereia",
|
||||
"themeNamePumpkin": "Abóbora",
|
||||
"themeNameGhost": "Fantasma",
|
||||
"themeNameVampire": "Vampiro",
|
||||
"themeNameWitch": "Bruxa",
|
||||
"themeNameCwtch": "Cwtch",
|
||||
"settingDownloadFolder": "Pasta para Download",
|
||||
"settingImagePreviews": "Pré-visualização de Imagens e Fotos de Perfil",
|
||||
"experimentClickableLinksDescription": "O experimento de links clicáveis permite que você clique em URLs compartilhadas em mensagens",
|
||||
"enableExperimentClickableLinks": "Habilitar links clicáveis",
|
||||
"serverConnectionsLabel": "Conexão",
|
||||
"serverTotalMessagesLabel": "Total de mensagens",
|
||||
"serverMetricsLabel": "Métricas do servidor",
|
||||
"manageKnownServersShort": "Servidores",
|
||||
"manageKnownServersLong": "Gerenciar Servidores Conhecidos",
|
||||
"displayNameTooltip": "Por favor, digite um nome de exibição",
|
||||
"manageKnownServersButton": "Gerenciar Servidores Conhecidos",
|
||||
"fieldDescriptionLabel": "Descrição",
|
||||
"groupsOnThisServerLabel": "Grupos nos quais estou hospedado neste servidor",
|
||||
"importLocalServerButton": "Importar %1",
|
||||
"importLocalServerSelectText": "Selecione Servidor Local",
|
||||
"importLocalServerLabel": "Importar um servidor hospedado localmente",
|
||||
"newMessagesLabel": "Novas mensagens",
|
||||
"copyServerKeys": "Copiar chaves",
|
||||
"verfiyResumeButton": "Verify\/resume",
|
||||
"fileCheckingStatus": "Verificando o status do download",
|
||||
"fileInterrupted": "Interrompido",
|
||||
"fileSavedTo": "Salvar em",
|
||||
"encryptedServerDescription": "Criptografar um servidor com uma senha o protege de outras pessoas que também podem usar este dispositivo. Os servidores criptografados não podem ser descriptografados, exibidos ou acessados até que a senha correta seja inserida para desbloqueá-los.",
|
||||
"plainServerDescription": "Recomendamos que você proteja seus servidores Cwtch com uma senha. Se você não definir uma senha neste servidor, qualquer pessoa que tenha acesso a este dispositivo poderá acessar informações sobre este servidor, incluindo chaves criptográficas sensíveis.",
|
||||
"deleteServerConfirmBtn": "Realmente excluir servidor",
|
||||
"deleteServerSuccess": "Servidor excluído com sucesso",
|
||||
"enterCurrentPasswordForDeleteServer": "Por favor, digite a senha atual para excluir este servidor",
|
||||
"copyAddress": "Copiar endereço",
|
||||
"settingServersDescription": "A experiência com servidores de hospedagem permite hospedar e gerenciar servidores Cwtch",
|
||||
"settingServers": "Servidores Hospedados",
|
||||
"enterServerPassword": "Digite a senha para desbloquear o servidor",
|
||||
"unlockProfileTip": "Por favor, crie ou desbloqueie um perfil para começar!",
|
||||
"unlockServerTip": "Por favor, crie ou desbloqueie um servidor para começar!",
|
||||
"addServerTooltip": "Adicionar novo servidor",
|
||||
"serversManagerTitleShort": "Servidores",
|
||||
"serversManagerTitleLong": "Servidor que você hospeda",
|
||||
"saveServerButton": "Salvar servidor",
|
||||
"serverAutostartDescription": "Controla se o aplicativo iniciará automaticamente o servidor no início",
|
||||
"serverAutostartLabel": "Autoinício",
|
||||
"serverEnabledDescription": "Iniciar ou parar servidor",
|
||||
"serverEnabled": "Servidor ativado",
|
||||
"serverDescriptionDescription": "Sua descrição do servidor é apenas para uso de gerenciamento pessoal, nunca será compartilhada",
|
||||
"serverDescriptionLabel": "Descrição do servidor",
|
||||
"serverAddress": "Endereço do servidor",
|
||||
"editServerTitle": "Editar servidor",
|
||||
"addServerTitle": "Adicionar servidor",
|
||||
"titleManageProfilesShort": "Perfis",
|
||||
"descriptionFileSharing": "O experimento de compartilhamento de arquivos permite enviar e receber arquivos de contatos e grupos do Cwtch. Note que compartilhar um arquivo com um grupo resultará em membros desse grupo conectando-se diretamente com você através do Cwtch para baixá-lo.",
|
||||
"settingFileSharing": "Compartilhar arquivo",
|
||||
"tooltipSendFile": "Mandar arquivo",
|
||||
"messageFileOffered": "Contato está oferecendo mandar um arquivo para você",
|
||||
"messageFileSent": "Você mandou um arquivo",
|
||||
"messageEnableFileSharing": "Habilite o experimento de compartilhamento de arquivos para visualizar esta mensagem.",
|
||||
"labelFilesize": "Tamanho",
|
||||
"labelFilename": "Nome do arquivo",
|
||||
"downloadFileButton": "Download",
|
||||
"openFolderButton": "Abrir pasta",
|
||||
"retrievingManifestMessage": "Obtendo informações do arquivo...",
|
||||
"descriptionStreamerMode": "Se ativada, esta opção torna o aplicativo mais privado visualmente para streaming ou apresentação com, por exemplo, perfil e endereços de contato ocultos.",
|
||||
"streamerModeLabel": "Streamer\/Modo de apresentação",
|
||||
"archiveConversation": "Arquivar esta conversa",
|
||||
"blockUnknownConnectionsEnabledDescription": "As conexões de contatos desconhecidos são bloqueadas. Você pode mudar isto em Configurações",
|
||||
"showMessageButton": "Mostrar mensagem",
|
||||
"blockedMessageMessage": "Esta mensagem é de um perfil que você bloqueou.",
|
||||
"placeholderEnterMessage": "Digitar a mensagem...",
|
||||
"plainProfileDescription": "Recomendamos que você proteja seus perfis Cwtch com uma senha. Se você não definir uma senha neste perfil, qualquer pessoa que tenha acesso a este dispositivo poderá acessar informações sobre este perfil, incluindo contatos, mensagens e chaves criptográficas sensíveis.",
|
||||
"encryptedProfileDescription": "Criptografar um perfil com uma senha o protege de outras pessoas que também podem usar este dispositivo. Os perfis criptografados não podem ser descriptografados, exibidos ou acessados até que a senha correta seja inserida para desbloqueá-los.",
|
||||
"addContactConfirm": "Adicionar contato %1",
|
||||
"addContact": "Adicionar contato",
|
||||
"contactGoto": "Vá para conversa com %1",
|
||||
"settingUIColumnOptionSame": "O mesmo que a configuração do modo retrato",
|
||||
"settingUIColumnDouble14Ratio": "Duplo (1:4)",
|
||||
"settingUIColumnDouble12Ratio": "Duplo (1:2)",
|
||||
"settingUIColumnSingle": "Único",
|
||||
"settingUIColumnLandscape": "Colunas da interface em Modo Paisagem",
|
||||
"settingUIColumnPortrait": "Colunas da interface em Modo Retrato",
|
||||
"tooltipRemoveThisQuotedMessage": "Remover mensagem mencionada",
|
||||
"tooltipReplyToThisMessage": "Responder esta mensagem",
|
||||
"tooltipRejectContactRequest": "Rejeitar pedido de contato",
|
||||
"tooltipAcceptContactRequest": "Aceitar pedido de contato",
|
||||
"notificationNewMessageFromGroup": "Nova mensagem de um grupo!",
|
||||
"notificationNewMessageFromPeer": "Nova mensagem de um contato!",
|
||||
"tooltipHidePassword": "Ocultar Senha",
|
||||
"tooltipShowPassword": "Mostrar Senha",
|
||||
"groupInviteSettingsWarning": "Você foi convidado a fazer parte de um grupo! Por favor, habilite a Experiência de Bate-papo em Grupo em Configurações para ver este convite.",
|
||||
"shutdownCwtchAction": "Desligar Cwtch",
|
||||
"shutdownCwtchDialog": "Você tem certeza que quer encerrar o Cwtch? Isto fechará todas as conexões, e sairá do aplicativo.",
|
||||
"shutdownCwtchDialogTitle": "Desligar o Cwtch?",
|
||||
"shutdownCwtchTooltip": "Desligar o Cwtch",
|
||||
"malformedMessage": "Mensagem malformada",
|
||||
"profileDeleteSuccess": "Perfil deletado com sucesso",
|
||||
"debugLog": "Ative o console de depuração de logs",
|
||||
"torNetworkStatus": "Status da rede Tor",
|
||||
"addContactFirst": "Adicione ou escolha um contato para começar a conversar.",
|
||||
"createProfileToBegin": "Por favor, crie ou desbloqueie um perfil para começar",
|
||||
"nickChangeSuccess": "Nome do perfil alterado com sucesso",
|
||||
"addServerFirst": "Você precisa adicionar um servidor antes de poder criar um grupo",
|
||||
"deleteProfileSuccess": "Perfil deletado com sucesso!",
|
||||
"sendInvite": "Mandar um contato ou convite de grupo",
|
||||
"sendMessage": "Mandar mensagem",
|
||||
"cancel": "Cancelar",
|
||||
"resetTor": "Resetar",
|
||||
"torStatus": "Tor Status",
|
||||
"torVersion": "Versão do Tor",
|
||||
"sendAnInvitation": "Você enviou um convite para: ",
|
||||
"contactSuggestion": "Esta é uma sugestão de contato para: ",
|
||||
"rejected": "Rejeitado!",
|
||||
"accepted": "Aceito!",
|
||||
"chatHistoryDefault": "Esta conversa será excluída quando o Cwtch for encerrado! O histórico de mensagens pode ser habilitado por conversa através do menu Configurações, no canto superior direito.",
|
||||
"newPassword": "Nova senha",
|
||||
"yesLeave": "Sim, deixa esta conversa",
|
||||
"reallyLeaveThisGroupPrompt": "Você tem certeza que quer deixar esta conversa? Todas as mensagens e atributos serão apagados.",
|
||||
"leaveConversation": "Deixar esta conversa",
|
||||
"inviteToGroup": "Você foi convidado a se juntar a um grupo:",
|
||||
"titleManageServers": "Gerenciar Servidores",
|
||||
"successfullAddedContact": "Adicionado com sucesso ",
|
||||
"descriptionBlockUnknownConnections": "Se ativada, esta opção fechará automaticamente as conexões dos usuários Cwtch que não tenham sido adicionadas à sua lista de contatos.",
|
||||
"descriptionExperimentsGroups": "O experimento de grupo permite ao Cwtch conectar-se com uma infra-estrutura de servidor não confiável para facilitar a comunicação com mais de um contato.",
|
||||
"descriptionExperiments": "Os experimentos Cwtch são opcionais, características opt-in que adicionam funcionalidades adicionais ao Cwtch que podem ter considerações de privacidade diferentes das tradicionais conversas resistentes a metadados 1:1, por exemplo, conversas em grupo, integração de bot, etc.",
|
||||
"titleManageProfiles": "Gerencie perfis do Cwtch",
|
||||
"tooltipUnlockProfiles": "Desbloqueie perfis criptografados digitando sua senha.",
|
||||
"titleManageContacts": "Conversas",
|
||||
"tooltipAddContact": "Adicionar novo contato a conversa",
|
||||
"tooltipOpenSettings": "Abra o painel de ajustes",
|
||||
"contactAlreadyExists": "Contato já existe",
|
||||
"invalidImportString": "Importação de string inválido",
|
||||
"conversationSettings": "Configurações da Conversa",
|
||||
"enterCurrentPasswordForDelete": "Por favor entre sua senha atual para deletar este perfil.",
|
||||
"enableGroups": "Ativar chat em grupo",
|
||||
"todoPlaceholder": "Afazer…",
|
||||
"addNewItem": "Adicionar novo item à lista",
|
||||
"addListItem": "Adicionar Item à Lista",
|
||||
"newConnectionPaneTitle": "Nova Conexão",
|
||||
"networkStatusOnline": "Online",
|
||||
"networkStatusConnecting": "Conectando à rede e contatos...",
|
||||
"networkStatusAttemptingTor": "Tentando conectar à rede Tor",
|
||||
"networkStatusDisconnected": "Desconectado da internet, confira a sua conexão",
|
||||
"viewGroupMembershipTooltip": "Ver Participação em Grupo",
|
||||
"loadingTor": "Carregando Tor...",
|
||||
"smallTextLabel": "Pequeno",
|
||||
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
|
||||
"builddate": "Construído em: %2",
|
||||
"version": "Versão %1",
|
||||
"versionTor": "Versão %1 com Tor %2",
|
||||
"experimentsEnabled": "Ativar experimentos",
|
||||
"themeDark": "Escuro",
|
||||
"themeLight": "Claro",
|
||||
"settingTheme": "Use temas claros",
|
||||
"largeTextLabel": "Grande",
|
||||
"settingInterfaceZoom": "Nível de zoom",
|
||||
"settingLanguage": "Linguagem",
|
||||
"blockUnknownLabel": "Bloquear Contatos Desconhecidos",
|
||||
"zoomLabel": "Zoom da interface (afeta principalmente tamanho de texto e botões)",
|
||||
"versionBuilddate": "Versão: %1 Construído em: %2",
|
||||
"cwtchSettingsTitle": "Configurações do Cwtch",
|
||||
"unlock": "Desbloquear",
|
||||
"yourServers": "Seus servidores",
|
||||
"yourProfiles": "Seus perfis",
|
||||
"error0ProfilesLoadedForPassword": "0 perfis carregados com esta senha",
|
||||
"password": "Senha",
|
||||
"enterProfilePassword": "Coloque uma senha para ver seus perfis",
|
||||
"addNewProfileBtn": "Adicionar novo perfil",
|
||||
"deleteConfirmText": "DELETE",
|
||||
"deleteProfileConfirmBtn": "Realmente deletar o perfil",
|
||||
"deleteConfirmLabel": "digite DELETE para confirmar",
|
||||
"deleteProfileBtn": "Deletar Perfil",
|
||||
"passwordChangeError": "Erro ao mudar a senha: senha fornecida rejeitada",
|
||||
"passwordErrorMatch": "Senhas não são iguais",
|
||||
"saveProfileBtn": "Salvar Perfil",
|
||||
"createProfileBtn": "Criar Perfil",
|
||||
"passwordErrorEmpty": "Senha não pode ser vazia",
|
||||
"password2Label": "Recoloque a senha",
|
||||
"password1Label": "Senha",
|
||||
"currentPasswordLabel": "Senha Atual",
|
||||
"yourDisplayName": "Seu nome de exibição",
|
||||
"profileOnionLabel": "Envie este endereço para contatos que você deseja se conectar",
|
||||
"noPasswordWarning": "Não usar uma senha nesta conta significa que todos os dados armazenados localmente não serão criptografados",
|
||||
"radioNoPassword": "Descriptografado (Sem senha)",
|
||||
"radioUsePassword": "Senha",
|
||||
"editProfile": "Editar Perfil",
|
||||
"newProfile": "Novo Perfil",
|
||||
"defaultProfileName": "Alice",
|
||||
"profileName": "Nome de exibição",
|
||||
"editProfileTitle": "Editar perfil",
|
||||
"addProfileTitle": "Adicionar novo perfil",
|
||||
"deleteBtn": "Deletar",
|
||||
"unblockBtn": "Desbloquear Contato",
|
||||
"dontSavePeerHistory": "Deletar histórico",
|
||||
"savePeerHistoryDescription": "Determina se deve excluir algum histórico associado com o contato.",
|
||||
"savePeerHistory": "Salvar histórico",
|
||||
"blockBtn": "Bloquear Contato",
|
||||
"saveBtn": "Salvar",
|
||||
"displayNameLabel": "Nome de Exibição",
|
||||
"copiedToClipboardNotification": "Copiado",
|
||||
"addressLabel": "Endereço",
|
||||
"puzzleGameBtn": "Jogo de Adivinhação",
|
||||
"bulletinsBtn": "Boletins",
|
||||
"listsBtn": "Listas",
|
||||
"chatBtn": "Chat",
|
||||
"rejectGroupBtn": "Recusar",
|
||||
"acceptGroupBtn": "Aceitar",
|
||||
"acceptGroupInviteLabel": "Você quer aceitar o convite para",
|
||||
"newGroupBtn": "Criar novo grupo",
|
||||
"copyBtn": "Copiar",
|
||||
"peerOfflineMessage": "Contato está off-line, mensagens não podem ser entregues agora.",
|
||||
"peerBlockedMessage": "Contato está bloquado",
|
||||
"pendingLabel": "Pendente",
|
||||
"acknowledgedLabel": "Confirmada",
|
||||
"couldNotSendMsgError": "Não deu para enviar esta mensagem",
|
||||
"dmTooltip": "Clique para DM",
|
||||
"membershipDescription": "A lista abaixo é de usuários que enviaram mensagens ao grupo. Essa lista pode não refletir todos os usuários que têm acesso ao grupo.",
|
||||
"addListItemBtn": "Adicionar Item",
|
||||
"peerNotOnline": "Contato está off-line. Não pode receber mensagens agora.",
|
||||
"searchList": "Lista de Pesquisa",
|
||||
"update": "Atualizar",
|
||||
"inviteBtn": "Convidar",
|
||||
"inviteToGroupLabel": "Convidar ao grupo",
|
||||
"groupNameLabel": "Nome do Grupo",
|
||||
"viewServerInfo": "Server Info",
|
||||
"serverNotSynced": "Sincronizando novas mensagens (Isto pode levar um tempo)...",
|
||||
"serverSynced": "Sincronizado",
|
||||
"serverConnectivityDisconnected": "Servidor Desconectado",
|
||||
"serverConnectivityConnected": "Servidor Conectado",
|
||||
"serverInfo": "Informação do Servidor",
|
||||
"invitationLabel": "Convite",
|
||||
"serverLabel": "Servidor",
|
||||
"search": "Pesquisar...",
|
||||
"blocked": "Bloqueado",
|
||||
"pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…",
|
||||
"titlePlaceholder": "título…",
|
||||
"postNewBulletinLabel": "Postar novo boletim",
|
||||
"newBulletinLabel": "Novo Boletim",
|
||||
"joinGroup": "Entrar no grupo",
|
||||
"createGroup": "Criar grupo",
|
||||
"addPeer": "Adicionar Contato",
|
||||
"groupAddr": "Endereços",
|
||||
"invitation": "Convite",
|
||||
"server": "Servidor",
|
||||
"peerName": "Nome",
|
||||
"peerAddress": "Endereço",
|
||||
"joinGroupTab": "Juntar-se a um grupo",
|
||||
"createGroupTab": "Criar um grupo",
|
||||
"addPeerTab": "Adicionar um contato",
|
||||
"createGroupBtn": "Criar",
|
||||
"defaultGroupName": "Grupo incrível",
|
||||
"createGroupTitle": "Criar Grupo"
|
||||
}
|
|
@ -1,8 +1,29 @@
|
|||
{
|
||||
"@@locale": "ro",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Turcă \/ Türk",
|
||||
"localeIt": "Italiană",
|
||||
"localeEn": "Engleză \/ English",
|
||||
"localeFr": "Franceză \/ Français",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"localeDe": "Germană",
|
||||
"localeEn": "Engleză",
|
||||
"localeLb": "Luxemburgheză",
|
||||
"localeNo": "Norvegiană",
|
||||
"localeEl": "Greacă",
|
||||
|
@ -12,8 +33,6 @@
|
|||
"localeEs": "Spaniolă",
|
||||
"localeDa": "Daneză",
|
||||
"localePt": "Portugheză",
|
||||
"localeFr": "Franceză",
|
||||
"localeIt": "Italiană",
|
||||
"localeCy": "Velşă",
|
||||
"settingImagePreviewsDescription": "Imaginile vor fi descărcate și previzualizate automat. Vă rugăm să rețineți că previzualizările imaginilor pot duce adesea la vulnerabilități de securitate și nu ar trebui să activați acest Experiment dacă utilizați Cwtch cu contacte care nu sunt de încredere. Imaginile de profil sunt planificate pentru Cwtch 1.6.",
|
||||
"tooltipPreviewFormatting": "Preview Message Formatting",
|
||||
|
|
|
@ -1,11 +1,42 @@
|
|||
{
|
||||
"@@locale": "ru",
|
||||
"@@last_modified": "2022-06-22T00:46:01+02:00",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"localeNl": "Dutch \/ Dutch",
|
||||
"experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes",
|
||||
"enableExperimentQRCode": "QR Codes",
|
||||
"shareMenuQRCode": "Show QR Code",
|
||||
"shareProfileMenuTooltop": "Share profile via...",
|
||||
"acquiredTicketsFromServer": "Antispam Challenge Complete",
|
||||
"acquiringTicketsFromServer": "Performing Antispam Challenge",
|
||||
"errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.",
|
||||
"localeTr": "Турецкий \/ Türk",
|
||||
"localeIt": "Итальянский \/ Italiano",
|
||||
"tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"",
|
||||
"tooltipPinConversation": "Pin conversation to the top of \"Conversations\"",
|
||||
"replyingTo": "Replying to %1",
|
||||
"fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.",
|
||||
"messageNoReplies": "There are no replies to this message.",
|
||||
"headingReplies": "Replies",
|
||||
"viewReplies": "View replies to this message",
|
||||
"restartFileShare": "Start Sharing File",
|
||||
"stopSharingFile": "Stop Sharing File",
|
||||
"manageSharedFiles": "Manage Shared Files",
|
||||
"exportProfile": "Экспорт профиля",
|
||||
"notificationContentContactInfo": "Показать текст сообщения",
|
||||
"notificationContentSimpleEvent": "Без подробностей",
|
||||
"settingsGroupExperiments": "ЭКСПЕРИМЕНТЫ",
|
||||
"settingsGroupAppearance": "НАСТРОЙКИ ОТОБРАЖЕНИЯ",
|
||||
"settingGroupBehaviour": "ПОВЕДЕНИЕ",
|
||||
"notificationContentSettingDescription": "Управление уведомлениями чатов",
|
||||
"conversationNotificationPolicyNever": "Отключить",
|
||||
"notificationPolicyDefaultAll": "По-умолчанию",
|
||||
"descriptionFileSharing": "Данная функция позволяет обмениваться файлами напрямую с контактами и группами в Cwtch. Отправляемый файл будет напрямую скачиваться с вашего устройства через Cwtch, внутри сети Tor",
|
||||
"descriptionExperiments": "Экспериментальные функции Cwtch это необязательные дополнительные функции, которые добавляют некоторые возможности, но не имеют такой же устойчивости к метаданным как если бы вы общались через традиционный чат 1 на 1.",
|
||||
"profileOnionLabel": "Send this address to contacts you want to connect with",
|
||||
"localeDe": "Немецкий \/ Deutsch",
|
||||
"localeDa": "Датский язык \/ Dansk",
|
||||
"settingImagePreviewsDescription": "Автоматическая загрузка изображений. Обратите внимание, что предварительный просмотр изображений часто может использоваться для взлома или деаномизации. Не используйте данную функцию если Вы контактируете с ненадежными контактами.",
|
||||
"localePt": "Португальский язык \/ Portuguesa",
|
||||
"localeIt": "Итальянский \/ Italiana",
|
||||
"tooltipBackToMessageEditing": "Назад к редактированию сообщений",
|
||||
"tooltipItalicize": "Курсив",
|
||||
"tooltipCode": "Код \/ Монопространство",
|
||||
|
@ -42,19 +73,13 @@
|
|||
"importProfileTooltip": "Используйте зашифрованную резервную копию Cwtch, чтобы перенести профиль, созданный на другом устройстве где установлен Cwtch..",
|
||||
"importProfile": "Загрузить профиль",
|
||||
"exportProfileTooltip": "Сделать зашифрованную резервную копию в файл. Его потом потом можно импортировать на других устройствах где установлен Cwtch.",
|
||||
"exportProfile": "Сохранить профиль",
|
||||
"notificationContentContactInfo": "Информация о разговоре",
|
||||
"notificationContentSimpleEvent": "Обычное событие",
|
||||
"conversationNotificationPolicySettingDescription": "Настройка уведомлений",
|
||||
"conversationNotificationPolicySettingLabel": "Настройка уведомлений",
|
||||
"settingsGroupAppearance": "Настройки отображения",
|
||||
"notificationContentSettingDescription": "Управление уведомлениями в данной теме",
|
||||
"notificationPolicySettingDescription": "Настройка уведомлений по-умолчанию",
|
||||
"notificationContentSettingLabel": "Содержимое уведомления",
|
||||
"notificationPolicySettingLabel": "Уведомления",
|
||||
"conversationNotificationPolicyOptIn": "Включить",
|
||||
"conversationNotificationPolicyDefault": "По-умолчанию",
|
||||
"notificationPolicyDefaultAll": "Всё по-умолчанию",
|
||||
"notificationPolicyOptIn": "Включить",
|
||||
"notificationPolicyMute": "Без звука",
|
||||
"tooltipSelectACustomProfileImage": "Сменить изображение профиля",
|
||||
|
@ -81,7 +106,6 @@
|
|||
"unlockServerTip": "Создайте или импортируйте сервер, чтобы начать",
|
||||
"saveServerButton": "Сохранить",
|
||||
"serverEnabled": "Состояние сервера",
|
||||
"descriptionFileSharing": "Данная функция позволяет обмениваться файлами напрямую с контактами и группами в Cwtch. Отправляемый файл будет напрямую скачиваться с вашего устройства через Cwtch, поверх скрытой сети Tor",
|
||||
"settingUIColumnOptionSame": "Как в портретном режиме",
|
||||
"settingUIColumnSingle": "Один столбец",
|
||||
"createProfileToBegin": "Пожалуйста, создайте или импортируйте профиль, чтобы начать",
|
||||
|
@ -90,15 +114,11 @@
|
|||
"enableGroups": "Групповые чаты",
|
||||
"settingTheme": "Ночной режим",
|
||||
"addNewProfileBtn": "Создать новый профиль",
|
||||
"profileOnionLabel": "Send this address to contacts you want to connect with",
|
||||
"savePeerHistoryDescription": "Определяет политику хранения или удаления сообщений с данным контактом",
|
||||
"savePeerHistory": "Настройка истории",
|
||||
"deleteConfirmLabel": "Введите УДАЛИТЬ, чтобы продолжить",
|
||||
"deleteConfirmText": "УДАЛИТЬ",
|
||||
"settingGroupBehaviour": "Поведение",
|
||||
"settingsGroupExperiments": "Эксперименты",
|
||||
"labelTorNetwork": "Сеть Tor",
|
||||
"conversationNotificationPolicyNever": "Никогда",
|
||||
"newMessageNotificationConversationInfo": "Новое сообщение от %1",
|
||||
"newMessageNotificationSimple": "Новое сообщение",
|
||||
"msgAddToAccept": "Добавьте учетную запись в контакты, чтобы принять этот файл.",
|
||||
|
@ -117,7 +137,6 @@
|
|||
"resetTor": "Сброс",
|
||||
"descriptionBlockUnknownConnections": "Если включить этот параметр, все соединения от людей, не состоящих в ваших контактах будут отклонены.",
|
||||
"descriptionExperimentsGroups": "Данная экспериментальная функция позволяет создавать группы в Cwtch, чтобы облегчить Вам общение с более чем одним контактом. Для создания групп необходимо включить функцию создания сервера и создать сервер в главном меню программы.",
|
||||
"descriptionExperiments": "Экспериментальные функции Cwtch это необязательные дополнительные функции, которые добавляют некоторые возможности, но не имеют такой же устойчивости к метаданным как если бы вы общались через традиционный чат 1 на 1..",
|
||||
"settingLanguage": "Выбрать язык",
|
||||
"profileName": "Введите имя...",
|
||||
"themeNameNeon2": "Неон2",
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
{
|
||||
"@@locale": "tr",
|
||||
"@@last_modified": "2022-09-15T03:18:37+02:00",
|
||||
"experimentQRCodeDescription": "QR Kod desteği profil kimliği gibi verilerin QR Kodla paylaşılmasına olanak tanır",
|
||||
"acquiringTicketsFromServer": "Spame Karşı Sınama",
|
||||
"acquiredTicketsFromServer": "Spame Karşı Sınama Tamamlandı",
|
||||
"shareProfileMenuTooltop": "Profili paylaş...",
|
||||
"shareMenuQRCode": "QR Kodunu Göster",
|
||||
"enableExperimentQRCode": "QR Kodları",
|
||||
"localeNl": "Flemenkçe \/ Dutch",
|
||||
"errorDownloadDirectoryDoesNotExist": "İndirilenler Klasörü ayarlanmadığı veya mevcut olmayan bir klasöre ayarlandığı için dosya paylaşımı etkinleştirilemiyor.",
|
||||
"radioNoPassword": "Şifrelenmemiş (Parola yok)",
|
||||
"msgAddToAccept": "Dosyayı kabul etmek için bu hesabı kişilerinize ekleyin.",
|
||||
"fileSharingSettingsDownloadFolderDescription": "Dosyalar (örn. görsel önizlemeleri etkinleştirildiğinde görsel dosyaları) otomatik olarak indirildiğinde, dosyaların indirileceği varsayılan bir konum gereklidir.",
|
||||
"torSettingsEnabledCacheDescription": "İndirilmiş Tor uzlaşmasını Cwtch'un bir sonraki açılışında yeniden kullanmak için önbelleğe alın. Bu Tor'un daha hızlı açılmasını sağlar. Devre dışı bırakıldığında Cwtch açılırken önbelleğe alınmış verileri siler.",
|
||||
"notificationContentSimpleEvent": "Yalın Bildiri",
|
||||
"exportProfileTooltip": "Bu profili şifrelenmiş bir dosyaya yedekle. Şifrelenmiş dosya başka bir Cwtch uygulamasına aktarılabilir.",
|
||||
"importProfileTooltip": "Başka Cwtch oluşumunda oluşturulmuş bir profili içeri aktarmak için şifrelenmiş Cwtch yedeği kullanın.",
|
||||
"clickableLinksWarning": "Bu URL'yi açmak Cwtch dışında bir uygulama başlatacak ve metadatanız teşhir olabilir veya Cwtch'un güvenliği tehlikeye girebilir. Yalnızca güvendiğiniz kişilerden gelen URL'leri açın. Devam etmek istediğinize emin misiniz?",
|
||||
"settingAndroidPowerExemptionDescription": "Opsiyonel: Android'den Cwtch'u optimize edilmiş güç yönetiminden muaf tutmasını isteyin. Bu, daha fazla pil kullanımı pahasına uygulamanın daha stabil çalışmasını sağlayacaktır.",
|
||||
"localeTr": "Türkçe \/ Türkçe",
|
||||
"defaultGroupName": "Muhteşem Grup",
|
||||
"defaultProfileName": "Alice",
|
||||
"localeDe": "Almanca \/ Deutsch",
|
||||
"localePl": "Lehçe \/ Polski",
|
||||
"localeDa": "Danca \/ Dansk",
|
||||
"acceptGroupInviteLabel": "Daveti kabul etmek istiyor musunuz",
|
||||
"pendingLabel": "Beklemede",
|
||||
"chatBtn": "Sohbet",
|
||||
"yourDisplayName": "Kullanıcı Adınız",
|
||||
"localeEn": "İngilizce \/ English",
|
||||
"localeFr": "Fransızca \/ Français",
|
||||
"localePt": "Portekizce \/ Portuguesa",
|
||||
"networkStatusAttemptingTor": "Tor ağına bağlanılıyor",
|
||||
"localeEs": "İspanyolca \/ Español",
|
||||
"localeIt": "İtalyanca \/ Italiano",
|
||||
"debugLog": "Konsol hata ayıklama kaydını başlat",
|
||||
"localeRU": "Rusça \/ Русский",
|
||||
"serverMetricsLabel": "Sunucu Bilgileri",
|
||||
"themeNameCwtch": "Cwtch",
|
||||
"themeNameWitch": "Cadı",
|
||||
"themeNameVampire": "Vampir",
|
||||
"themeNameGhost": "Hayalet",
|
||||
"themeNamePumpkin": "Balkabağı",
|
||||
"themeNameMermaid": "Denizkızı",
|
||||
"themeNameMidnight": "Gece",
|
||||
"themeNameNeon1": "Neon1",
|
||||
"themeNameNeon2": "Neon2",
|
||||
"descriptionACNCircuitInfo": "Anonim iletişim ağının (ACN) bu konuşmaya bağlanmak için kullandığı yol hakkında ayrıntılı bilgi.",
|
||||
"tooltipSelectACustomProfileImage": "Profil Resmi Seçin",
|
||||
"notificationPolicyMute": "Sessiz",
|
||||
"localeRo": "Romence \/ Română",
|
||||
"localeLb": "Lüksemburgca \/ Lëtzebuergesch",
|
||||
"localeNo": "Norveççe \/ Norsk",
|
||||
"localeEl": "Yunanca \/ Ελληνικά",
|
||||
"localeCy": "Galce \/ Cymraeg",
|
||||
"notificationPolicyOptIn": "Mümkünse Al",
|
||||
"conversationNotificationPolicyOptIn": "Mümkünse Al",
|
||||
"tooltipCode": "Kod \/ Monospace",
|
||||
"createGroupTitle": "Grup Oluştur",
|
||||
"serverLabel": "Sunucu",
|
||||
"createGroupBtn": "Oluştur",
|
||||
"profileOnionLabel": "Bu adresi bağlantı kurmak istediğiniz insanlara gönderin",
|
||||
"addPeerTab": "Kişi ekle",
|
||||
"createGroupTab": "Grup oluştur",
|
||||
"joinGroupTab": "Gruba katıl",
|
||||
"peerAddress": "Adres",
|
||||
"peerName": "İsim",
|
||||
"server": "Sunucu",
|
||||
"invitation": "Davet",
|
||||
"groupAddr": "Adres",
|
||||
"addPeer": "Kişi Ekle",
|
||||
"createGroup": "Grup oluştur",
|
||||
"joinGroup": "Gruba katıl",
|
||||
"newBulletinLabel": "Yeni Bülten",
|
||||
"postNewBulletinLabel": "Yeni bülten yayınla",
|
||||
"titlePlaceholder": "başlık...",
|
||||
"pasteAddressToAddContact": "Yeni konuşma eklemek için buraya bir cwtch adresi, davetiye veya anahtar paketi yapıştırın",
|
||||
"blocked": "Engelli",
|
||||
"search": "Ara...",
|
||||
"invitationLabel": "Davet",
|
||||
"serverInfo": "Sunucu Bilgileri",
|
||||
"serverConnectivityConnected": "Sunucu Bağlandı",
|
||||
"serverConnectivityDisconnected": "Sunucu Bağlantısı Kesildi",
|
||||
"serverSynced": "Senkronize Edildi",
|
||||
"serverNotSynced": "Yeni Mesajlar Senkronize Oluyor (Biraz zaman alabilir)...",
|
||||
"viewServerInfo": "Sunucu Bilgileri",
|
||||
"groupNameLabel": "Grup İsmi",
|
||||
"saveBtn": "Kaydet",
|
||||
"inviteToGroupLabel": "Gruba davet et",
|
||||
"inviteBtn": "Davet Et",
|
||||
"deleteBtn": "Sil",
|
||||
"update": "Güncelleştir",
|
||||
"searchList": "Listede Ara",
|
||||
"peerNotOnline": "Kişi çevrimdışı. Uygulamalar şu anda kullanılamıyor.",
|
||||
"addListItemBtn": "Öğe Ekle",
|
||||
"membershipDescription": "Aşağıda gruba ileti gönderen kullanıcıların listesi verilmiştir. Bu liste gruba erişimi olan tüm kullanıcıları yansıtmayabilir.",
|
||||
"dmTooltip": "DM için tıklayın",
|
||||
"couldNotSendMsgError": "Mesaj gönderilemedi",
|
||||
"acknowledgedLabel": "Onaylandı",
|
||||
"peerBlockedMessage": "Kişi engelli",
|
||||
"peerOfflineMessage": "Kişi çevrimdışı, mesajlar şu anda iletilemiyor",
|
||||
"copyBtn": "Kopyala",
|
||||
"newGroupBtn": "Yeni grup oluştur",
|
||||
"acceptGroupBtn": "Kabul Et",
|
||||
"rejectGroupBtn": "Reddet",
|
||||
"listsBtn": "Listeler",
|
||||
"bulletinsBtn": "Bültenler",
|
||||
"puzzleGameBtn": "Yapboz",
|
||||
"addressLabel": "Adres",
|
||||
"copiedToClipboardNotification": "Panoya kopyalandı",
|
||||
"displayNameLabel": "Lütfen bir ad girin",
|
||||
"blockBtn": "Kişiyi Engelle",
|
||||
"savePeerHistory": "Geçmişi Kaydet",
|
||||
"savePeerHistoryDescription": "Kişi ile ilgili tüm geçmişin silinip silinmeyeceğini belirler.",
|
||||
"dontSavePeerHistory": "Geçmişi Sil",
|
||||
"unblockBtn": "Kişi Engelini Kaldır",
|
||||
"addProfileTitle": "Yeni profil ekle",
|
||||
"editProfileTitle": "Profili Düzenle",
|
||||
"profileName": "Kullanıcı adı",
|
||||
"newProfile": "Yeni Profil",
|
||||
"editProfile": "Profili Düzenle",
|
||||
"noPasswordWarning": "Bu hesapta parola kullanılmaması yerel olarak depolanan verilerin şifrelenmeyeceği anlamına gelir",
|
||||
"currentPasswordLabel": "Mevcut Parola",
|
||||
"password2Label": "Parolayı yeniden gir",
|
||||
"passwordErrorEmpty": "Parola boş bırakılamaz",
|
||||
"createProfileBtn": "Profil Oluştur",
|
||||
"saveProfileBtn": "Profili Kaydet",
|
||||
"passwordErrorMatch": "Parolalar eşleşmiyor",
|
||||
"passwordChangeError": "Parola değiştirilirken hata oluştu: Verilen parola reddedildi",
|
||||
"deleteProfileBtn": "Profili Sil",
|
||||
"deleteConfirmLabel": "Onaylamak için DELETE yazın",
|
||||
"deleteProfileConfirmBtn": "Profili Gerçekten Sil",
|
||||
"deleteConfirmText": "SİL",
|
||||
"addNewProfileBtn": "Yeni profil ekle",
|
||||
"enterProfilePassword": "Profillerinizi görmek için parolayı girin",
|
||||
"error0ProfilesLoadedForPassword": "Bu parolayla 0 profil yüklendi",
|
||||
"yourProfiles": "Profilleriniz",
|
||||
"yourServers": "Sunucularınız",
|
||||
"unlock": "Kilidi Aç",
|
||||
"cwtchSettingsTitle": "Cwtch Ayarları",
|
||||
"versionBuilddate": "Sürüm: %1 Derlendiği tarih: %2",
|
||||
"zoomLabel": "Arayüz yakınlaştırma (aslen metin ve buton boyutlarını etkiler)",
|
||||
"blockUnknownLabel": "Tanınmayan Kişileri Engelle",
|
||||
"settingLanguage": "Dil",
|
||||
"settingInterfaceZoom": "Yakınlaştırma seviyesi",
|
||||
"largeTextLabel": "Büyük",
|
||||
"settingTheme": "Açık Tema Kullan",
|
||||
"themeLight": "Açık",
|
||||
"themeDark": "Koyu",
|
||||
"experimentsEnabled": "Deneyleri Etkinleştir",
|
||||
"versionTor": "Sürüm %1 ve tor %2",
|
||||
"version": "Sürüm %1",
|
||||
"builddate": "Derlendiği tarih: %2",
|
||||
"defaultScalingText": "Varsayılan metin boyutu (ölçek faktörü: ",
|
||||
"smallTextLabel": "Küçük",
|
||||
"loadingTor": "Tor yükleniyor...",
|
||||
"viewGroupMembershipTooltip": "Grup Üyeliğini Görüntüle",
|
||||
"networkStatusDisconnected": "İnternet bağlantısı kesildi, bağlantınızı kontrol edin",
|
||||
"networkStatusConnecting": "Ağa ve kişilere bağlanıyor...",
|
||||
"networkStatusOnline": "Çevrimiçi",
|
||||
"newConnectionPaneTitle": "Yeni Bağlantı",
|
||||
"addListItem": "Yeni Liste Öğesi Ekle",
|
||||
"addNewItem": "Listeye yeni bir öğe ekle",
|
||||
"todoPlaceholder": "Yapılacaklar...",
|
||||
"enableGroups": "Grup Sohbetini Etkinleştir",
|
||||
"enterCurrentPasswordForDelete": "Profili silmek için parolayı girin.",
|
||||
"conversationSettings": "Sohbet Ayarları",
|
||||
"invalidImportString": "Geçersiz içe aktarma girdisi",
|
||||
"contactAlreadyExists": "Kişi Zaten Ekli",
|
||||
"tooltipOpenSettings": "Ayarlar bölmesini aç",
|
||||
"descriptionExperiments": "Cwtch deneyleri, Cwtch'a grup sohbeti, bot entegrasyonu vb. gibi 1:1 meta veriye dayanıklılıktan farklı gizlilik önceliklerine sahip olabilen işlevler ekleyen opsiyonel özelliklerdir.",
|
||||
"tooltipAddContact": "Yeni bir kişi veya sohbet ekle",
|
||||
"titleManageContacts": "Sohbetler",
|
||||
"tooltipUnlockProfiles": "Parolalarını girerek şifrelenmiş profillerin kilidini açın.",
|
||||
"titleManageProfiles": "Cwtch Profillerini Yönet",
|
||||
"descriptionExperimentsGroups": "Grup deneyi, Cwtch'un birden fazla kişiyle bağlantısını kolaylaştırmak için güvenilmeyen sunucu altyapısına bağlanmasına olanak tanır.",
|
||||
"descriptionBlockUnknownConnections": "Bu seçenek etkinse, kişi listenizde olmayan kullanıcılardan gelen bağlantılar otomatik olarak kapatılır.",
|
||||
"successfullAddedContact": "Başarıyla eklendi",
|
||||
"titleManageServers": "Sunucuları Yönet",
|
||||
"inviteToGroup": "Bir gruba katılma daveti aldınız:",
|
||||
"leaveConversation": "Sohbetten Ayrıl",
|
||||
"reallyLeaveThisGroupPrompt": "Bu görüşmeden ayrılmak istediğinize emin misiniz? Tüm mesajlar silinecek.",
|
||||
"yesLeave": "Evet, Sohbetten Ayrıl",
|
||||
"chatHistoryDefault": "Cwtch kapatıldığında bu konuşma silinecek! Mesaj geçmişi farklı sohbetler için sağ üstteki Ayarlar menüsünden etkinleştirilebilir.",
|
||||
"accepted": "Kabul edildi!",
|
||||
"rejected": "Reddedildi!",
|
||||
"contactSuggestion": "İletişim önerileri: ",
|
||||
"sendAnInvitation": "Bir davetiye gönderdiniz: ",
|
||||
"torVersion": "Tor Sürümü",
|
||||
"torStatus": "Tor Durumu",
|
||||
"resetTor": "Sıfırla",
|
||||
"cancel": "İptal",
|
||||
"sendMessage": "Mesaj Gönder",
|
||||
"sendInvite": "Kişi veya grup daveti gönderme",
|
||||
"deleteProfileSuccess": "Profil başarıyla silindi",
|
||||
"addServerFirst": "Grup oluşturmadan önce sunucu eklemeniz gerekir",
|
||||
"nickChangeSuccess": "Profil kullanıcı adı başarıyla değiştirildi",
|
||||
"createProfileToBegin": "Başlamak için bir profil oluşturun veya kilidini açın",
|
||||
"addContactFirst": "Sohbete başlamak için bir kişi ekleyin veya seçin.",
|
||||
"torNetworkStatus": "Tor ağ durumu",
|
||||
"profileDeleteSuccess": "Profil başarıyla silindi",
|
||||
"malformedMessage": "Hatalı biçimlendirilmiş mesaj",
|
||||
"shutdownCwtchTooltip": "Cwtch'u Kapat",
|
||||
"shutdownCwtchDialogTitle": "Cwtch'u Kapat?",
|
||||
"shutdownCwtchDialog": "Cwtch'i kapatmak istediğinize emin misiniz? Bu tüm bağlantıları kapatacak, ve uygulamadan çıkacaktır.",
|
||||
"shutdownCwtchAction": "Cwtch'u Kapat",
|
||||
"groupInviteSettingsWarning": "Gruba katılma daveti aldınız! Bu Daveti görüntülemek için lütfen Ayarlar'dan Grup Sohbeti Deneyini etkinleştirin.",
|
||||
"tooltipHidePassword": "Parolayı Gizle",
|
||||
"tooltipShowPassword": "Parolayı Göster",
|
||||
"newPassword": "Yeni Parola",
|
||||
"radioUsePassword": "Parola",
|
||||
"password1Label": "Parola",
|
||||
"password": "Parola",
|
||||
"notificationNewMessageFromPeer": "Yeni mesaj!",
|
||||
"notificationNewMessageFromGroup": "Yeni grup mesajı!",
|
||||
"tooltipAcceptContactRequest": "Bağlantı isteğini kabul et",
|
||||
"tooltipRejectContactRequest": "Bağlantı isteğini reddet",
|
||||
"tooltipReplyToThisMessage": "Bu mesajı yanıtla",
|
||||
"tooltipRemoveThisQuotedMessage": "Alıntılanan mesajı kaldır.",
|
||||
"settingUIColumnPortrait": "UI Sütunları Portre Modu",
|
||||
"settingUIColumnLandscape": "UI Sütunları Yatay Modu",
|
||||
"settingUIColumnSingle": "Tek",
|
||||
"settingUIColumnDouble12Ratio": "Çift (1:2)",
|
||||
"settingUIColumnDouble14Ratio": "Çift (1:4)",
|
||||
"settingUIColumnOptionSame": "Portre modu ayarı ile aynı",
|
||||
"contactGoto": "%1 ile olan sohbete git",
|
||||
"addContact": "Kişi ekle",
|
||||
"addContactConfirm": "%1 kişisini ekle",
|
||||
"encryptedProfileDescription": "Bir profili parola ile şifrelemek, profili bu aygıtı kullanabilecek diğer kişilerden korur. Doğru şifre girilene kadar şifrelenmiş profiller görüntülenemez veya erişilemez.",
|
||||
"plainProfileDescription": "Cwtch profillerinizi parola ile korumanızı öneririz. Bir parola belirlemezseniz, bu cihaza erişimi olan herkes kişiler, mesajlar ve kriptografik anahtarlar da dahil olmak üzere hassas bilgilerinize erişebilir.",
|
||||
"placeholderEnterMessage": "Bir mesaj yazın...",
|
||||
"labelFilesize": "Boyut",
|
||||
"blockedMessageMessage": "Bu mesaj blokladığınız bir profilden gönderilmiş",
|
||||
"showMessageButton": "Mesajı Görüntüle",
|
||||
"blockUnknownConnectionsEnabledDescription": "Bilinmeyen kişilerden gelen bağlantılar engelli. Bu özelliği Ayarlar'dan değiştirebilirsiniz",
|
||||
"archiveConversation": "Bu Sohbeti Arşivle",
|
||||
"streamerModeLabel": "Yayıncı\/Sunum Modu",
|
||||
"descriptionStreamerMode": "Bu seçenek etkinleştirildiğinde profiller, iletişim adresleri gibi bilgiler saklanarak uygulama daha gizli hale getirilir.",
|
||||
"retrievingManifestMessage": "Dosya bilgileri alınıyor...",
|
||||
"openFolderButton": "Klasörü Aç",
|
||||
"downloadFileButton": "İndir",
|
||||
"labelFilename": "Dosya Adı",
|
||||
"messageEnableFileSharing": "Bu mesajı görüntüleyebilmek için dosya paylaşma deneyini etkinleştirin.",
|
||||
"settingFileSharing": "Dosya Paylaşma",
|
||||
"messageFileSent": "Bir dosya gönderdiniz",
|
||||
"messageFileOffered": "Kişi size bir dosya göndermek istiyor",
|
||||
"tooltipSendFile": "Dosya Gönder",
|
||||
"descriptionFileSharing": "Dosya paylaşım deneyi, Cwtch kişileri ve gruplarından dosya gönderip almanızı sağlar. Bir dosyayı bir grupla paylaşmanın, o grubun üyelerinin dosyayı indirmek için doğrudan Cwtch üzerinden sizinle bağlantı kurmasıyla sonuçlanacağını unutmayın.",
|
||||
"titleManageProfilesShort": "Profiller",
|
||||
"addServerTitle": "Sunucu Ekle",
|
||||
"editServerTitle": "Sunucuyu Düzenle",
|
||||
"serverAddress": "Sunucu Adresi",
|
||||
"serverDescriptionLabel": "Sunucu Açıklaması",
|
||||
"serverDescriptionDescription": "Kişisel yönetiminiz için sunucu açıklaması, dışarıyla asla paylaşılmayacaktır",
|
||||
"serverEnabled": "Sunucu Etkin",
|
||||
"serverEnabledDescription": "Sunucuyu başlat veya durdur",
|
||||
"serverAutostartLabel": "Otomatik başlatma",
|
||||
"serverAutostartDescription": "Uygulamanın açılışta sunucuyu otomatik olarak başlatıp başlatmayacağını belirler",
|
||||
"saveServerButton": "Sunucuyu Kaydet",
|
||||
"serversManagerTitleLong": "Barındırdığınız Sunucular",
|
||||
"serversManagerTitleShort": "Sunucular",
|
||||
"addServerTooltip": "Yeni sunucu ekle",
|
||||
"unlockServerTip": "Başlamak için bir sunucu oluşturun veya sunucunuzun kilidini açın",
|
||||
"unlockProfileTip": "Başlamak için bir profil oluşturun veya profilinizin kilidini açın",
|
||||
"enterServerPassword": "Sunucuyu açmak için şifre girin",
|
||||
"settingServersDescription": "Sunucu barındırma deneyi Cwtch sunucularını barındırmayı ve yönetmeyi sağlar",
|
||||
"settingServers": "Sunucu Barındırma",
|
||||
"copyAddress": "Adresi Kopyala",
|
||||
"enterCurrentPasswordForDeleteServer": "Lütfen sunucuyu silmek için şifreyi girin",
|
||||
"deleteServerSuccess": "Sunucu başarıyla silindi",
|
||||
"deleteServerConfirmBtn": "Sunucuyu gerçekten sil",
|
||||
"plainServerDescription": "Cwtch sunucularınızı bir parola ile korumanızı öneririz. Bir parola belirlemezseniz, bu cihaza erişimi olan herkes kriptografik anahtarlar da dahil olmak üzere sunucunun hassas bilgilerine erişebilir.",
|
||||
"encryptedServerDescription": "Bir sunucuyu parola ile şifrelemek, sunucuyu bu aygıtı kullanabilecek diğer kişilerden korur. Doğru şifre girilene kadar şifrelenmiş sunucular görüntülenemez veya erişilemez.",
|
||||
"fileSavedTo": "Şuraya kaydedildi",
|
||||
"fileInterrupted": "Kesildi",
|
||||
"fileCheckingStatus": "İndirme durumunu kontrol ediyor",
|
||||
"verfiyResumeButton": "Doğrula\/devam et",
|
||||
"copyServerKeys": "Anahtarları kopyala",
|
||||
"newMessagesLabel": "Yeni Mesajlar",
|
||||
"importLocalServerLabel": "Yerel bir sunucuyu içeri aktar",
|
||||
"importLocalServerSelectText": "Yerel Sunucu Seç",
|
||||
"importLocalServerButton": "%1'i içeri aktar",
|
||||
"groupsOnThisServerLabel": "Bu sunucuda içinde bulunduğum gruplar",
|
||||
"fieldDescriptionLabel": "Açıklama",
|
||||
"manageKnownServersButton": "Bilinen Sunucuları Yönet",
|
||||
"displayNameTooltip": "Lütfen bir ad girin",
|
||||
"manageKnownServersLong": "Bilinen Sunucuları Yönet",
|
||||
"manageKnownServersShort": "Sunucular",
|
||||
"serverTotalMessagesLabel": "Toplam Mesaj",
|
||||
"serverConnectionsLabel": "Bağlantı",
|
||||
"enableExperimentClickableLinks": "Tıklanabilir Linkleri Etkinleştir",
|
||||
"experimentClickableLinksDescription": "Tıklanabilir bağlantılar deneyi, mesajlarda paylaşılan URL'lere tıklamanıza olanak tanır",
|
||||
"settingImagePreviewsDescription": "Görseller ve Profil Resimleri otomatik olarak indirilir ve görüntülenir. Cwtch'u güvenmediğiniz kişilerle iletişim kurmak için kullanıyorsanız bu deneysel özelliği etkinleştirmemenizi öneririz.",
|
||||
"settingDownloadFolder": "İndirilenler Klasörü",
|
||||
"themeColorLabel": "Renk Teması",
|
||||
"loadingCwtch": "Cwtch yükleniyor...",
|
||||
"storageMigrationModalMessage": "Profiller yeni depolama biçimine taşınıyor. Bu işlem birkaç dakika sürebilir...",
|
||||
"msgFileTooBig": "Dosya boyutu 10 GB'ı geçemez",
|
||||
"msgConfirmSend": "Göndermek istediğinize emin misiniz",
|
||||
"btnSendFile": "Dosya Gönder",
|
||||
"torSettingsUseCustomTorServiceConfigurastionDescription": "Varsayılan tor konfigürasyonunu geçersiz kıl. Uyarı: Bu tehlikeli olabilir. Yalnızca ne yaptığınızı biliyorsanız açın.",
|
||||
"torSettingsEnabledAdvanced": "Gelişmiş Tor Konfigürasyonunu Etkinleştir",
|
||||
"torSettingsUseCustomTorServiceConfiguration": "Özel Tor Hizmeti Konfigürasyonunu (torrc) Kullan",
|
||||
"torSettingsEnabledAdvancedDescription": "Sisteminizde mevcut bir Tor hizmetini kullanın, veya Cwtch Tor Hizmeti'nin parametrelerini değiştirin",
|
||||
"torSettingsCustomSocksPort": "Özel SOCKS Portu",
|
||||
"torSettingsCustomControlPortDescription": "Tor proxy'sine kontrol bağlantıları için özel bir port kullan",
|
||||
"torSettingsCustomSocksPortDescription": "Tor proxy'sine veri bağlantıları için özel bir port kullan",
|
||||
"torSettingsCustomControlPort": "Özel Kontrol Portu",
|
||||
"torSettingsErrorSettingPort": "Port Numarası 1 ile 65535 arasında olmalıdır",
|
||||
"settingImagePreviews": "Görsel Önizlemeleri ve Profil Resimleri",
|
||||
"fileSharingSettingsDownloadFolderTooltip": "İndirilen dosyalara farklı bir varsayılan klasör seçmek için gözat.",
|
||||
"labelACNCircuitInfo": "ACN Ağ Bilgisi",
|
||||
"labelTorNetwork": "Tor Ağı",
|
||||
"torSettingsEnableCache": "Tor Uzlaşmasını Önbelleğe Al",
|
||||
"notificationPolicyDefaultAll": "Tümü Varsayılan",
|
||||
"conversationNotificationPolicyDefault": "Varsayılan",
|
||||
"conversationNotificationPolicyNever": "Asla",
|
||||
"notificationPolicySettingLabel": "Bildirim İlkeleri",
|
||||
"notificationContentSettingLabel": "Bildirim İçeriği",
|
||||
"notificationPolicySettingDescription": "Varsayılan uygulama bildirim davranışını belirler",
|
||||
"notificationContentSettingDescription": "Sohbet bildirimlerinin içeriğini belirler",
|
||||
"tooltipUnpinConversation": "Sohbetin \"Sohbetler\"in üstüne sabitlemesini kaldır",
|
||||
"tooltipPinConversation": "Sohbeti \"Sohbetler\"in üstüne sabitle",
|
||||
"newMessageNotificationConversationInfo": "%1 Sohbetinde Yeni Mesaj",
|
||||
"notificationContentContactInfo": "Sohbet Bilgileri",
|
||||
"conversationNotificationPolicySettingLabel": "Sohbet Bildirim İlkeleri",
|
||||
"conversationNotificationPolicySettingDescription": "Bu sohbet için bildirim ayarlarını kontrol et",
|
||||
"settingGroupBehaviour": "Davranış",
|
||||
"settingsGroupAppearance": "Görünüş",
|
||||
"settingsGroupExperiments": "Deneyler",
|
||||
"newMessageNotificationSimple": "Yeni Mesaj",
|
||||
"exportProfile": "Profili Dışa Aktar",
|
||||
"importProfile": "Profili İçe Aktar",
|
||||
"clickableLinkError": "URL açılmaya çalışılırken hata oluştu",
|
||||
"failedToImportProfile": "Profil İçe Aktarılırken Hata Oluştu",
|
||||
"successfullyImportedProfile": "Profil Başarıyla İçe Aktarıldı: %profile",
|
||||
"shuttingDownApp": "Kapanıyor...",
|
||||
"clickableLinkOpen": "URL'yi aç",
|
||||
"clickableLinksCopy": "URL'yi kopyala",
|
||||
"formattingExperiment": "Mesaj Biçimlendirme",
|
||||
"messageFormattingDescription": "Görüntülenen mesajlarda zengin metin biçimlendirmesini etkinleştirin, örneğin **kalın** ve *italik*",
|
||||
"thisFeatureRequiresGroupExpermientsToBeEnabled": "Bu özellik Gruplar Özelliği'nin Ayarlar'dan etkinleştirilmesini gerektirir",
|
||||
"settingAndroidPowerExemption": "Android Pil Optimizasyonlarını Yoksay",
|
||||
"settingsAndroidPowerReenablePopup": "Cwtch içinden Pil Optimizasyonu yeniden etkinleştirilemiyor. Lütfen Android \/ Ayarlar \/ Uygulamalar \/ Cwtch \/ Pil sayfasına gidin ve 'Pil Kullanımını Yönet' bölümünün altında 'Optimize edilmiş'e basın",
|
||||
"okButton": "OK",
|
||||
"tooltipBoldText": "Kalın",
|
||||
"tooltipBackToMessageEditing": "Mesaj Düzenlemeye Geri Dön",
|
||||
"tooltipItalicize": "İtalik",
|
||||
"tooltipSuperscript": "Üst Simge",
|
||||
"tooltipSubscript": "Alt Simge",
|
||||
"tooltipStrikethrough": "Üstü Çizili",
|
||||
"tooltipPreviewFormatting": "Mesaj Biçimlendirmesini Önizle",
|
||||
"manageSharedFiles": "Paylaşılan Dosyaları Yönet",
|
||||
"stopSharingFile": "Dosya Paylaşımını Durdur",
|
||||
"restartFileShare": "Dosya Paylaşımını Başlat",
|
||||
"viewReplies": "Mesaja gelen yanıtları görüntüle",
|
||||
"headingReplies": "Yanıtlar",
|
||||
"messageNoReplies": "Bu mesaja yanıt gelmemiş.",
|
||||
"fileDownloadUnavailable": "Bu dosya indirmeye uygun görünmüyor. Gönderen dosyanın indirilmesini engellemiş olabilir.",
|
||||
"replyingTo": "%1 hesabına yanıt veriliyor"
|
||||
}
|
|
@ -132,6 +132,7 @@ class FlwtchState extends State<Flwtch> with WindowListener {
|
|||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
title: 'Cwtch',
|
||||
showSemanticsDebugger: settings.useSemanticDebugger,
|
||||
theme: mkThemeData(settings),
|
||||
home: (!appState.cwtchInit || appState.modalState != ModalState.none) ? SplashView() : ProfileMgrView(),
|
||||
),
|
||||
|
|
|
@ -42,6 +42,7 @@ class AppState extends ChangeNotifier {
|
|||
|
||||
String? get selectedProfile => _selectedProfile;
|
||||
set selectedProfile(String? newVal) {
|
||||
this._selectedConversation = null;
|
||||
this._selectedProfile = newVal;
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import 'package:cwtch/main.dart';
|
||||
import 'package:cwtch/models/profile.dart';
|
||||
import 'package:cwtch/widgets/messagerow.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
import 'message.dart';
|
||||
|
@ -51,8 +54,11 @@ class ContactInfoState extends ChangeNotifier {
|
|||
late bool _isGroup;
|
||||
String? _server;
|
||||
late bool _archived;
|
||||
late bool _pinned;
|
||||
|
||||
int _antispamTickets = 0;
|
||||
String? _acnCircuit;
|
||||
String? _messageDraft;
|
||||
|
||||
ContactInfoState(this.profileOnion, this.identifier, this.onion,
|
||||
{nickname = "",
|
||||
|
@ -68,7 +74,8 @@ class ContactInfoState extends ChangeNotifier {
|
|||
lastMessageTime,
|
||||
server,
|
||||
archived = false,
|
||||
notificationPolicy = "ConversationNotificationPolicy.Default"}) {
|
||||
notificationPolicy = "ConversationNotificationPolicy.Default",
|
||||
pinned = false}) {
|
||||
this._nickname = nickname;
|
||||
this._isGroup = isGroup;
|
||||
this._accepted = accepted;
|
||||
|
@ -84,15 +91,25 @@ class ContactInfoState extends ChangeNotifier {
|
|||
this._archived = archived;
|
||||
this._notificationPolicy = notificationPolicyFromString(notificationPolicy);
|
||||
this.messageCache = new MessageCache(_totalMessages);
|
||||
this._pinned = pinned;
|
||||
keys = Map<String, GlobalKey<MessageRowState>>();
|
||||
}
|
||||
|
||||
String get nickname => this._nickname;
|
||||
String get nickname => this._nickname + (this._messageDraft != null && this._messageDraft != "" ? "*" : "");
|
||||
|
||||
String get savePeerHistory => this._savePeerHistory;
|
||||
|
||||
String? get acnCircuit => this._acnCircuit;
|
||||
|
||||
String? get messageDraft => this._messageDraft;
|
||||
|
||||
set antispamTickets(int antispamTickets) {
|
||||
this._antispamTickets = antispamTickets;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
int get antispamTickets => this._antispamTickets;
|
||||
|
||||
set acnCircuit(String? acnCircuit) {
|
||||
this._acnCircuit = acnCircuit;
|
||||
notifyListeners();
|
||||
|
@ -146,6 +163,11 @@ class ContactInfoState extends ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
set messageDraft(String? newVal) {
|
||||
this._messageDraft = newVal;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void selected() {
|
||||
this._newMarkerMsgIndex = this._unreadMessages - 1;
|
||||
this._unreadMessages = 0;
|
||||
|
@ -285,4 +307,31 @@ class ContactInfoState extends ChangeNotifier {
|
|||
}
|
||||
return ConversationNotificationPolicy.Never;
|
||||
}
|
||||
|
||||
bool get pinned {
|
||||
return _pinned;
|
||||
}
|
||||
|
||||
// Pin the conversation to the top of the conversation list
|
||||
// Requires caller tree to contain a FlwtchState and ProfileInfoState provider.
|
||||
void pin(context) {
|
||||
_pinned = true;
|
||||
var profileHandle = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileHandle, identifier, "profile.pinned", "true");
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Unpin the conversation from the top of the conversation list
|
||||
// Requires caller tree to contain a FlwtchState and ProfileInfoState provider.
|
||||
void unpin(context) {
|
||||
_pinned = false;
|
||||
var profileHandle = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileHandle, identifier, "profile.pinned", "false");
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// returns true only if the conversation has been accepted, and has not been blocked
|
||||
bool isAccepted() {
|
||||
return _accepted && !_blocked;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,9 @@ class ContactListState extends ChangeNotifier {
|
|||
// return -1 = a first in list
|
||||
// return 1 = b first in list
|
||||
|
||||
// pinned contacts first
|
||||
if (a.pinned != true && b.pinned == true) return 1;
|
||||
if (a.pinned == true && b.pinned != true) return -1;
|
||||
// blocked contacts last
|
||||
if (a.isBlocked == true && b.isBlocked != true) return 1;
|
||||
if (a.isBlocked != true && b.isBlocked == true) return -1;
|
||||
|
|
|
@ -7,8 +7,10 @@ class FileDownloadProgress {
|
|||
String? downloadedTo;
|
||||
DateTime? timeStart;
|
||||
DateTime? timeEnd;
|
||||
DateTime? requested;
|
||||
|
||||
FileDownloadProgress(this.chunksTotal, this.timeStart);
|
||||
|
||||
double progress() {
|
||||
return 1.0 * chunksDownloaded / chunksTotal;
|
||||
}
|
||||
|
|
|
@ -201,6 +201,42 @@ class ByContentHash implements CacheHandler {
|
|||
}
|
||||
}
|
||||
|
||||
List<Message> getReplies(MessageCache cache, int messageIdentifier) {
|
||||
List<Message> replies = List.empty(growable: true);
|
||||
|
||||
try {
|
||||
MessageInfo original = cache.cache[messageIdentifier]!;
|
||||
String hash = original.metadata.contenthash;
|
||||
|
||||
cache.cache.forEach((key, messageInfo) {
|
||||
// only bother searching for identifiers that came *after*
|
||||
if (key > messageIdentifier) {
|
||||
try {
|
||||
dynamic message = jsonDecode(messageInfo.wrapper);
|
||||
var content = message['d'] as dynamic;
|
||||
dynamic qmessage = jsonDecode(content);
|
||||
if (qmessage["body"] == null || qmessage["quotedHash"] == null) {
|
||||
return;
|
||||
}
|
||||
if (qmessage["quotedHash"] == hash) {
|
||||
replies.add(compileOverlay(messageInfo));
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
EnvironmentConfig.debugLog("message handler exception on get from cache: $e");
|
||||
}
|
||||
|
||||
replies.sort((a, b) {
|
||||
return a.getMetadata().messageID.compareTo(b.getMetadata().messageID);
|
||||
});
|
||||
|
||||
return replies;
|
||||
}
|
||||
|
||||
Future<Message> messageHandler(BuildContext context, String profileOnion, int conversationIdentifier, CacheHandler cacheHandler) async {
|
||||
var malformedMetadata = MessageMetadata(profileOnion, conversationIdentifier, 0, DateTime.now(), "", "", "", <String, String>{}, false, true, false, "");
|
||||
var cwtch = Provider.of<FlwtchState>(context, listen: false).cwtch;
|
||||
|
|
|
@ -36,7 +36,6 @@ class QuotedMessage extends Message {
|
|||
var content = message["body"];
|
||||
return Text(
|
||||
content,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
} catch (e) {
|
||||
return MalformedBubble();
|
||||
|
|
|
@ -67,6 +67,7 @@ class ProfileInfoState extends ChangeNotifier {
|
|||
server: contact["groupServer"],
|
||||
archived: contact["isArchived"] == true,
|
||||
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
|
||||
pinned: contact["attributes"]?["local.profile.pinned"] == "true",
|
||||
notificationPolicy: contact["notificationPolicy"] ?? "ConversationNotificationPolicy.Default");
|
||||
}));
|
||||
|
||||
|
@ -291,12 +292,27 @@ class ProfileInfoState extends ChangeNotifier {
|
|||
}
|
||||
|
||||
bool downloadInterrupted(String fileKey) {
|
||||
return this._downloads.containsKey(fileKey) && this._downloads[fileKey]!.interrupted;
|
||||
if (this._downloads.containsKey(fileKey)) {
|
||||
if (this._downloads[fileKey]!.interrupted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._downloads[fileKey]!.requested != null) {
|
||||
if (DateTime.now().difference(this._downloads[fileKey]!.requested!) > Duration(minutes: 1)) {
|
||||
this._downloads[fileKey]!.requested = null;
|
||||
this._downloads[fileKey]!.interrupted = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void downloadMarkResumed(String fileKey) {
|
||||
if (this._downloads.containsKey(fileKey)) {
|
||||
this._downloads[fileKey]!.interrupted = false;
|
||||
this._downloads[fileKey]!.requested = DateTime.now();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cwtch/config.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import 'contact.dart';
|
||||
|
@ -13,7 +14,7 @@ class RemoteServerInfoState extends ChangeNotifier {
|
|||
DateTime lastPreSyncMessagTime = new DateTime(2020);
|
||||
|
||||
RemoteServerInfoState(this.onion, this.identifier, this.description, this._status, {lastPreSyncMessageTime, mostRecentMessageTime}) {
|
||||
if (_status == "Authenticated") {
|
||||
if (_status == "Authenticated" || _status == "Synced") {
|
||||
this.lastPreSyncMessagTime = lastPreSyncMessageTime;
|
||||
updateSyncProgressFor(mostRecentMessageTime);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ const FileSharingExperiment = "filesharing";
|
|||
const ImagePreviewsExperiment = "filesharing-images";
|
||||
const ClickableLinksExperiment = "clickable-links";
|
||||
const FormattingExperiment = "message-formatting";
|
||||
const QRCodeExperiment = "qrcode-support";
|
||||
|
||||
enum DualpaneMode {
|
||||
Single,
|
||||
|
@ -63,9 +64,17 @@ class Settings extends ChangeNotifier {
|
|||
String _customTorAuth = "";
|
||||
bool _useTorCache = false;
|
||||
String _torCacheDir = "";
|
||||
bool _useSemanticDebugger = false;
|
||||
|
||||
String get torCacheDir => _torCacheDir;
|
||||
|
||||
set useSemanticDebugger(bool newval) {
|
||||
this._useSemanticDebugger = newval;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool get useSemanticDebugger => _useSemanticDebugger;
|
||||
|
||||
void setTheme(String themeId, String mode) {
|
||||
theme = getTheme(themeId, mode);
|
||||
notifyListeners();
|
||||
|
|
|
@ -174,7 +174,6 @@ ThemeData mkThemeData(Settings opaque) {
|
|||
? opaque.current().defaultButtonDisabledColor
|
||||
: null),
|
||||
enableFeedback: true,
|
||||
splashFactory: InkRipple.splashFactory,
|
||||
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
|
|
|
@ -36,6 +36,9 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
final ctrlrContact = TextEditingController(text: "");
|
||||
final ctrlrGroupName = TextEditingController(text: "");
|
||||
String server = "";
|
||||
// flutter textfield onChange often fires twice and since we need contexts, we can't easily use a controler/listener
|
||||
String lastContactValue = "";
|
||||
bool failedImport = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -130,7 +133,7 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
onPressed: _copyOnion,
|
||||
readonly: true,
|
||||
icon: Icon(
|
||||
CwtchIcons.address_copy_2,
|
||||
CwtchIcons.address_copy,
|
||||
size: 32,
|
||||
),
|
||||
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||
|
@ -144,34 +147,34 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
),
|
||||
CwtchTextField(
|
||||
testKey: Key("txtAddP2P"),
|
||||
key: Key("txtAddP2P"),
|
||||
controller: ctrlrContact,
|
||||
validator: (value) {
|
||||
if (value == "") {
|
||||
return null;
|
||||
}
|
||||
if (globalErrorHandler.invalidImportStringError) {
|
||||
if (failedImport) {
|
||||
return AppLocalizations.of(context)!.invalidImportString;
|
||||
} else if (globalErrorHandler.contactAlreadyExistsError) {
|
||||
return AppLocalizations.of(context)!.contactAlreadyExists;
|
||||
} else if (globalErrorHandler.explicitAddContactSuccess) {}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: (String importBundle) async {
|
||||
var profileOnion = Provider.of<ProfileInfoState>(bcontext, listen: false).onion;
|
||||
Provider.of<FlwtchState>(bcontext, listen: false).cwtch.ImportBundle(profileOnion, importBundle.replaceFirst("cwtch:", ""));
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
if (globalErrorHandler.importBundleSuccess) {
|
||||
// TODO: This isn't ideal, but because onChange can be fired during this future check
|
||||
// and because the context can change after being popped we have this kind of double assertion...
|
||||
// There is probably a better pattern to handle this...
|
||||
if (AppLocalizations.of(bcontext) != null) {
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(bcontext)!.successfullAddedContact + importBundle));
|
||||
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
||||
Navigator.popUntil(bcontext, (route) => route.settings.name == "conversations");
|
||||
if (lastContactValue != importBundle) {
|
||||
lastContactValue = importBundle;
|
||||
var profileOnion = Provider.of<ProfileInfoState>(bcontext, listen: false).onion;
|
||||
Provider.of<FlwtchState>(bcontext, listen: false).cwtch.ImportBundle(profileOnion, importBundle.replaceFirst("cwtch:", "")).then((result) {
|
||||
if (result == "importBundle.success") {
|
||||
failedImport = false;
|
||||
if (AppLocalizations.of(bcontext) != null) {
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(bcontext)!.successfullAddedContact + importBundle));
|
||||
ScaffoldMessenger.of(bcontext).showSnackBar(snackBar);
|
||||
Navigator.popUntil(bcontext, (route) => route.settings.name == "conversations");
|
||||
}
|
||||
} else {
|
||||
failedImport = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
hintText: '',
|
||||
)
|
||||
|
|
|
@ -162,7 +162,7 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
onPressed: _copyOnion,
|
||||
readonly: true,
|
||||
icon: Icon(
|
||||
CwtchIcons.address_copy_2,
|
||||
CwtchIcons.address_copy,
|
||||
size: 32,
|
||||
),
|
||||
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||
|
@ -279,8 +279,8 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
ElevatedButton(
|
||||
onPressed: _createPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size(400, 50),
|
||||
maximumSize: Size(800, 50),
|
||||
minimumSize: Size(400, 75),
|
||||
maximumSize: Size(800, 75),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
child: Text(
|
||||
|
@ -297,8 +297,8 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
message: AppLocalizations.of(context)!.exportProfileTooltip,
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size(400, 50),
|
||||
maximumSize: Size(800, 50),
|
||||
minimumSize: Size(400, 75),
|
||||
maximumSize: Size(800, 75),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
onPressed: () {
|
||||
|
@ -328,8 +328,8 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
message: AppLocalizations.of(context)!.enterCurrentPasswordForDelete,
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size(400, 50),
|
||||
maximumSize: Size(800, 50),
|
||||
minimumSize: Size(400, 75),
|
||||
maximumSize: Size(800, 75),
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: Provider.of<Settings>(context).theme.defaultButtonActiveColor, width: 2.0),
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cwtch/cwtch/cwtch.dart';
|
||||
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||
import 'package:cwtch/models/appstate.dart';
|
||||
|
@ -17,9 +19,12 @@ import '../main.dart';
|
|||
import '../settings.dart';
|
||||
import 'addcontactview.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
import 'messageview.dart';
|
||||
|
||||
enum ShareMenu { copyCode, qrcode }
|
||||
|
||||
class ContactsView extends StatefulWidget {
|
||||
const ContactsView({Key? key}) : super(key: key);
|
||||
|
||||
|
@ -29,6 +34,9 @@ class ContactsView extends StatefulWidget {
|
|||
|
||||
// selectConversation can be called from anywhere to set the active conversation
|
||||
void selectConversation(BuildContext context, int handle) {
|
||||
if (handle == Provider.of<AppState>(context, listen: false).selectedConversation) {
|
||||
return;
|
||||
}
|
||||
// requery instead of using contactinfostate directly because sometimes listview gets confused about data that resorts
|
||||
var unread = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(handle)!.unreadMessages;
|
||||
var previouslySelected = Provider.of<AppState>(context, listen: false).selectedConversation;
|
||||
|
@ -120,8 +128,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
}),
|
||||
)
|
||||
]),
|
||||
title: RepaintBoundary(
|
||||
child: Row(children: [
|
||||
title: Row(children: [
|
||||
ProfileImage(
|
||||
imagePath: Provider.of<Settings>(context).isExperimentEnabled(ImagePreviewsExperiment)
|
||||
? Provider.of<ProfileInfoState>(context).imagePath
|
||||
|
@ -139,7 +146,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
Expanded(
|
||||
child: Text("%1 » %2".replaceAll("%1", Provider.of<ProfileInfoState>(context).nickname).replaceAll("%2", AppLocalizations.of(context)!.titleManageContacts),
|
||||
overflow: TextOverflow.ellipsis, style: TextStyle(color: Provider.of<Settings>(context).current().mainTextColor))),
|
||||
])),
|
||||
]),
|
||||
actions: getActions(context),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
|
@ -159,16 +166,49 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
actions.add(Tooltip(message: AppLocalizations.of(context)!.blockUnknownConnectionsEnabledDescription, child: Icon(CwtchIcons.block_unknown)));
|
||||
}
|
||||
|
||||
// Copy profile onion
|
||||
actions.add(IconButton(
|
||||
icon: Icon(CwtchIcons.address_copy_2),
|
||||
tooltip: AppLocalizations.of(context)!.copyAddress,
|
||||
if (Provider.of<Settings>(context, listen: false).isExperimentEnabled(QRCodeExperiment)) {
|
||||
actions.add(PopupMenuButton<ShareMenu>(
|
||||
icon: Icon(CwtchIcons.address_copy),
|
||||
tooltip: AppLocalizations.of(context)!.shareProfileMenuTooltop,
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
onPressed: () {
|
||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}));
|
||||
onSelected: (ShareMenu item) {
|
||||
switch (item) {
|
||||
case ShareMenu.copyCode:
|
||||
{
|
||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
break;
|
||||
case ShareMenu.qrcode:
|
||||
{
|
||||
_showQRCode("cwtch:" + Provider.of<ProfileInfoState>(context, listen: false).onion);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<ShareMenu>>[
|
||||
PopupMenuItem<ShareMenu>(
|
||||
value: ShareMenu.copyCode,
|
||||
child: Text(AppLocalizations.of(context)!.copyAddress),
|
||||
),
|
||||
PopupMenuItem<ShareMenu>(
|
||||
value: ShareMenu.qrcode,
|
||||
child: Text(AppLocalizations.of(context)!.shareMenuQRCode),
|
||||
),
|
||||
],
|
||||
));
|
||||
} else {
|
||||
actions.add(IconButton(
|
||||
icon: Icon(CwtchIcons.address_copy),
|
||||
tooltip: AppLocalizations.of(context)!.copyAddress,
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
onPressed: () {
|
||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}));
|
||||
}
|
||||
|
||||
// Manage known Servers
|
||||
if (Provider.of<Settings>(context, listen: false).isExperimentEnabled(TapirGroupsExperiment) || Provider.of<Settings>(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) {
|
||||
|
@ -213,7 +253,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
ChangeNotifierProvider.value(value: contact),
|
||||
ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context).serverList),
|
||||
],
|
||||
builder: (context, child) => RepaintBoundary(child: ContactRow()),
|
||||
builder: (context, child) => ContactRow(),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -225,11 +265,11 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
|
||||
var contactList = ScrollablePositionedList.separated(
|
||||
itemScrollController: Provider.of<ProfileInfoState>(context).contactListScrollController,
|
||||
itemCount: Provider.of<ContactListState>(context).num,
|
||||
itemCount: Provider.of<ContactListState>(context).numFiltered,
|
||||
initialScrollIndex: initialScroll,
|
||||
shrinkWrap: true,
|
||||
physics: BouncingScrollPhysics(),
|
||||
semanticChildCount: Provider.of<ContactListState>(context).num,
|
||||
semanticChildCount: Provider.of<ContactListState>(context).numFiltered,
|
||||
itemBuilder: (context, index) {
|
||||
return tiles.elementAt(index);
|
||||
},
|
||||
|
@ -238,7 +278,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
},
|
||||
);
|
||||
|
||||
return RepaintBoundary(child: contactList);
|
||||
return contactList;
|
||||
}
|
||||
|
||||
void _pushAddContact(bool newGroup) {
|
||||
|
@ -289,7 +329,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
padding: MediaQuery.of(context).viewInsets,
|
||||
child: RepaintBoundary(
|
||||
child: Container(
|
||||
height: 200, // bespoke value courtesy of the [TextField] docs
|
||||
height: Platform.isAndroid ? 250 : 200, // bespoke value courtesy of the [TextField] docs
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(2.0),
|
||||
|
@ -306,7 +346,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
message: AppLocalizations.of(context)!.tooltipAddContact,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.fromWidth(double.infinity),
|
||||
minimumSize: Size.fromWidth(399),
|
||||
maximumSize: Size.fromWidth(400),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
|
@ -328,7 +368,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
message: groupsEnabled ? AppLocalizations.of(context)!.addServerTooltip : AppLocalizations.of(context)!.thisFeatureRequiresGroupExpermientsToBeEnabled,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.fromWidth(double.infinity),
|
||||
minimumSize: Size.fromWidth(399),
|
||||
maximumSize: Size.fromWidth(400),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
|
@ -353,7 +393,7 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
message: groupsEnabled ? AppLocalizations.of(context)!.createGroupTitle : AppLocalizations.of(context)!.thisFeatureRequiresGroupExpermientsToBeEnabled,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.fromWidth(double.infinity),
|
||||
minimumSize: Size.fromWidth(399),
|
||||
maximumSize: Size.fromWidth(400),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
|
@ -377,4 +417,24 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
)));
|
||||
});
|
||||
}
|
||||
|
||||
void _showQRCode(String profile_code) {
|
||||
showModalBottomSheet<dynamic>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Wrap(children: <Widget>[
|
||||
Center(
|
||||
child: QrImage(
|
||||
data: profile_code,
|
||||
version: QrVersions.auto,
|
||||
size: 400.0,
|
||||
backgroundColor: Provider.of<Settings>(context).theme.backgroundPaneColor,
|
||||
foregroundColor: Provider.of<Settings>(context).theme.mainTextColor,
|
||||
gapless: false,
|
||||
),
|
||||
)
|
||||
]);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cwtch/config.dart';
|
||||
import 'package:cwtch/cwtch/cwtch.dart';
|
||||
import 'package:cwtch/main.dart';
|
||||
import 'package:cwtch/models/appstate.dart';
|
||||
import 'package:cwtch/models/contact.dart';
|
||||
import 'package:cwtch/models/profile.dart';
|
||||
import 'package:cwtch/settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
import '../cwtch_icons_icons.dart';
|
||||
|
||||
class FileSharingView extends StatefulWidget {
|
||||
@override
|
||||
_FileSharingViewState createState() => _FileSharingViewState();
|
||||
}
|
||||
|
||||
class _FileSharingViewState extends State<FileSharingView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var handle = Provider.of<ContactInfoState>(context).nickname;
|
||||
if (handle.isEmpty) {
|
||||
handle = Provider.of<ContactInfoState>(context).onion;
|
||||
}
|
||||
|
||||
var profileHandle = Provider.of<ProfileInfoState>(context).onion;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(handle + " » " + AppLocalizations.of(context)!.manageSharedFiles),
|
||||
),
|
||||
body: FutureBuilder(
|
||||
future: Provider.of<FlwtchState>(context, listen: false).cwtch.GetSharedFiles(profileHandle, Provider.of<ContactInfoState>(context).identifier),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
List<dynamic> sharedFiles = jsonDecode(snapshot.data as String);
|
||||
sharedFiles.sort((a, b) {
|
||||
return a["DateShared"].toString().compareTo(b["DateShared"].toString());
|
||||
});
|
||||
|
||||
var fileList = ScrollablePositionedList.separated(
|
||||
itemScrollController: ItemScrollController(),
|
||||
itemCount: sharedFiles.length,
|
||||
shrinkWrap: true,
|
||||
physics: BouncingScrollPhysics(),
|
||||
semanticChildCount: sharedFiles.length,
|
||||
itemBuilder: (context, index) {
|
||||
String filekey = sharedFiles[index]["FileKey"];
|
||||
EnvironmentConfig.debugLog("$sharedFiles " + sharedFiles[index].toString());
|
||||
return SwitchListTile(
|
||||
title: Text(sharedFiles[index]["Path"]),
|
||||
subtitle: Text(sharedFiles[index]["DateShared"]),
|
||||
value: sharedFiles[index]["Active"],
|
||||
activeTrackColor: Provider.of<Settings>(context).theme.defaultButtonColor,
|
||||
inactiveTrackColor: Provider.of<Settings>(context).theme.defaultButtonDisabledColor,
|
||||
secondary: Icon(CwtchIcons.attached_file_2, color: Provider.of<Settings>(context).current().mainTextColor),
|
||||
onChanged: (newValue) {
|
||||
setState(() {
|
||||
if (newValue) {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.RestartSharing(profileHandle, filekey);
|
||||
} else {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.StopSharing(profileHandle, filekey);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) {
|
||||
return Divider(height: 1);
|
||||
},
|
||||
);
|
||||
return fileList;
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -393,7 +393,12 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
value: settings.isExperimentEnabled(FileSharingExperiment),
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
settings.enableExperiment(FileSharingExperiment);
|
||||
if (checkDownloadDirectory(context, settings)) {
|
||||
settings.enableExperiment(FileSharingExperiment);
|
||||
} else {
|
||||
settings.disableExperiment(FileSharingExperiment);
|
||||
settings.disableExperiment(ImagePreviewsExperiment);
|
||||
}
|
||||
} else {
|
||||
settings.disableExperiment(FileSharingExperiment);
|
||||
settings.disableExperiment(ImagePreviewsExperiment);
|
||||
|
@ -402,7 +407,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
},
|
||||
activeTrackColor: settings.theme.defaultButtonColor,
|
||||
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
|
||||
secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor),
|
||||
secondary: Icon(CwtchIcons.attached_file_2, color: settings.current().mainTextColor),
|
||||
),
|
||||
Visibility(
|
||||
visible: settings.isExperimentEnabled(FileSharingExperiment),
|
||||
|
@ -413,8 +418,11 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
value: settings.isExperimentEnabled(ImagePreviewsExperiment),
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
settings.enableExperiment(ImagePreviewsExperiment);
|
||||
settings.downloadPath = Provider.of<FlwtchState>(context, listen: false).cwtch.defaultDownloadPath();
|
||||
if (checkDownloadDirectory(context, settings)) {
|
||||
settings.enableExperiment(ImagePreviewsExperiment);
|
||||
} else {
|
||||
settings.disableExperiment(ImagePreviewsExperiment);
|
||||
}
|
||||
} else {
|
||||
settings.disableExperiment(ImagePreviewsExperiment);
|
||||
}
|
||||
|
@ -460,6 +468,24 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
|
||||
secondary: Icon(Icons.link, color: settings.current().mainTextColor),
|
||||
)),
|
||||
Visibility(
|
||||
visible: settings.experimentsEnabled,
|
||||
child: SwitchListTile(
|
||||
title: Text(AppLocalizations.of(context)!.enableExperimentQRCode, style: TextStyle(color: settings.current().mainTextColor)),
|
||||
subtitle: Text(AppLocalizations.of(context)!.experimentQRCodeDescription),
|
||||
value: settings.isExperimentEnabled(QRCodeExperiment),
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
settings.enableExperiment(QRCodeExperiment);
|
||||
} else {
|
||||
settings.disableExperiment(QRCodeExperiment);
|
||||
}
|
||||
saveSettings(context);
|
||||
},
|
||||
activeTrackColor: settings.theme.defaultButtonActiveColor,
|
||||
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
|
||||
secondary: Icon(Icons.qr_code, color: settings.current().mainTextColor),
|
||||
)),
|
||||
AboutListTile(
|
||||
icon: appIcon,
|
||||
applicationIcon: Padding(padding: EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)),
|
||||
|
@ -472,6 +498,24 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
child: SelectableText(AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE)),
|
||||
)
|
||||
]),
|
||||
Visibility(
|
||||
visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
|
||||
child: SwitchListTile(
|
||||
title: Text("Show Semantic Debugger", style: TextStyle(color: settings.current().mainTextColor)),
|
||||
subtitle: Text("Show Accessibility Debugging View"),
|
||||
value: settings.useSemanticDebugger,
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
settings.useSemanticDebugger = value;
|
||||
} else {
|
||||
settings.useSemanticDebugger = value;
|
||||
}
|
||||
saveSettings(context);
|
||||
},
|
||||
activeTrackColor: settings.theme.defaultButtonActiveColor,
|
||||
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
|
||||
secondary: Icon(Icons.settings_accessibility, color: settings.current().mainTextColor),
|
||||
)),
|
||||
Visibility(
|
||||
visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
|
||||
child: FutureBuilder(
|
||||
|
@ -521,6 +565,30 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
}
|
||||
}
|
||||
|
||||
bool checkDownloadDirectory(context, settings) {
|
||||
bool showError = false;
|
||||
if (settings.downloadPath != "") {
|
||||
} else {
|
||||
// check if the default download path exists
|
||||
var path = Provider.of<FlwtchState>(context, listen: false).cwtch.defaultDownloadPath();
|
||||
if (path != null) {
|
||||
settings.downloadPath = path;
|
||||
} else {
|
||||
showError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!showError && Directory(settings.downloadPath).existsSync()) {
|
||||
return true;
|
||||
} else {
|
||||
final snackBar = SnackBar(
|
||||
content: Text(AppLocalizations.of(context)!.errorDownloadDirectoryDoesNotExist),
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a version string from Package Info
|
||||
String constructVersionString(PackageInfo pinfo) {
|
||||
if (pinfo == null) {
|
||||
|
@ -574,6 +642,12 @@ String getLanguageFull(context, String languageCode) {
|
|||
if (languageCode == "da") {
|
||||
return AppLocalizations.of(context)!.localeDa;
|
||||
}
|
||||
if (languageCode == "tr") {
|
||||
return AppLocalizations.of(context)!.localeTr;
|
||||
}
|
||||
if (languageCode == "nl") {
|
||||
return AppLocalizations.of(context)!.localeNl;
|
||||
}
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import '../constants.dart';
|
|||
import '../main.dart';
|
||||
import '../settings.dart';
|
||||
import '../widgets/messagelist.dart';
|
||||
import 'filesharingview.dart';
|
||||
import 'groupsettingsview.dart';
|
||||
|
||||
class MessageView extends StatefulWidget {
|
||||
|
@ -64,6 +65,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
showDown = false;
|
||||
}
|
||||
});
|
||||
ctrlrCompose.text = Provider.of<ContactInfoState>(context, listen: false).messageDraft ?? "";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -97,11 +99,17 @@ class _MessageViewState extends State<MessageView> {
|
|||
var showMessageFormattingPreview = Provider.of<Settings>(context).isExperimentEnabled(FormattingExperiment);
|
||||
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
|
||||
var appBarButtons = <Widget>[];
|
||||
|
||||
if (showFileSharing) {
|
||||
appBarButtons.add(IconButton(
|
||||
splashRadius: Material.defaultSplashRadius / 2, icon: Icon(CwtchIcons.manage_files), tooltip: AppLocalizations.of(context)!.manageSharedFiles, onPressed: _pushFileSharingSettings));
|
||||
}
|
||||
|
||||
if (Provider.of<ContactInfoState>(context).isOnline()) {
|
||||
if (showFileSharing) {
|
||||
appBarButtons.add(IconButton(
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
icon: Icon(Icons.attach_file, size: 24, color: Provider.of<Settings>(context).theme.mainTextColor),
|
||||
icon: Icon(CwtchIcons.attached_file_2, size: 26, color: Provider.of<Settings>(context).theme.mainTextColor),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipSendFile,
|
||||
onPressed: Provider.of<AppState>(context).disableFilePicker
|
||||
? null
|
||||
|
@ -119,6 +127,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
},
|
||||
));
|
||||
}
|
||||
|
||||
appBarButtons.add(IconButton(
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
icon: Icon(CwtchIcons.send_invite, size: 24),
|
||||
|
@ -160,14 +169,39 @@ class _MessageViewState extends State<MessageView> {
|
|||
: null,
|
||||
title: Row(children: [
|
||||
ProfileImage(
|
||||
imagePath: Provider.of<Settings>(context).isExperimentEnabled(ImagePreviewsExperiment)
|
||||
? Provider.of<ContactInfoState>(context).imagePath
|
||||
: Provider.of<ContactInfoState>(context).defaultImagePath,
|
||||
diameter: 42,
|
||||
border: Provider.of<Settings>(context).current().portraitOnlineBorderColor,
|
||||
badgeTextColor: Colors.red,
|
||||
badgeColor: Colors.red,
|
||||
),
|
||||
imagePath: Provider.of<Settings>(context).isExperimentEnabled(ImagePreviewsExperiment)
|
||||
? Provider.of<ContactInfoState>(context).imagePath
|
||||
: Provider.of<ContactInfoState>(context).defaultImagePath,
|
||||
diameter: 42,
|
||||
border: Provider.of<Settings>(context).current().portraitOnlineBorderColor,
|
||||
badgeTextColor: Colors.red,
|
||||
badgeColor: Provider.of<Settings>(context).theme.portraitContactBadgeColor,
|
||||
badgeIcon: Provider.of<ContactInfoState>(context).isGroup
|
||||
? (Tooltip(
|
||||
message: Provider.of<ContactInfoState>(context).isOnline()
|
||||
? Provider.of<ContactInfoState>(context).antispamTickets == 0
|
||||
? AppLocalizations.of(context)!.acquiringTicketsFromServer
|
||||
: AppLocalizations.of(context)!.acquiredTicketsFromServer
|
||||
: AppLocalizations.of(context)!.serverConnectivityDisconnected,
|
||||
child: Provider.of<ContactInfoState>(context).isOnline()
|
||||
? Provider.of<ContactInfoState>(context).antispamTickets == 0
|
||||
? Icon(
|
||||
CwtchIcons.anti_spam_3,
|
||||
size: 14.0,
|
||||
semanticLabel: AppLocalizations.of(context)!.acquiringTicketsFromServer,
|
||||
color: Provider.of<Settings>(context).theme.portraitContactBadgeTextColor,
|
||||
)
|
||||
: Icon(
|
||||
CwtchIcons.anti_spam_2,
|
||||
color: Provider.of<Settings>(context).theme.portraitContactBadgeTextColor,
|
||||
size: 14.0,
|
||||
)
|
||||
: Icon(
|
||||
CwtchIcons.onion_off,
|
||||
color: Provider.of<Settings>(context).theme.portraitContactBadgeTextColor,
|
||||
size: 14.0,
|
||||
)))
|
||||
: null),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
|
@ -200,6 +234,23 @@ class _MessageViewState extends State<MessageView> {
|
|||
return true;
|
||||
}
|
||||
|
||||
void _pushFileSharingSettings() {
|
||||
var profileInfoState = Provider.of<ProfileInfoState>(context, listen: false);
|
||||
var contactInfoState = Provider.of<ContactInfoState>(context, listen: false);
|
||||
Navigator.of(context).push(
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (builderContext, a1, a2) {
|
||||
return MultiProvider(
|
||||
providers: [ChangeNotifierProvider.value(value: profileInfoState), ChangeNotifierProvider.value(value: contactInfoState)],
|
||||
child: FileSharingView(),
|
||||
);
|
||||
},
|
||||
transitionsBuilder: (c, anim, a2, child) => FadeTransition(opacity: anim, child: child),
|
||||
transitionDuration: Duration(milliseconds: 200),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _pushContactSettings() {
|
||||
var profileInfoState = Provider.of<ProfileInfoState>(context, listen: false);
|
||||
var contactInfoState = Provider.of<ContactInfoState>(context, listen: false);
|
||||
|
@ -246,12 +297,12 @@ class _MessageViewState extends State<MessageView> {
|
|||
|
||||
// Do this after we trim to preserve enter-behaviour...
|
||||
bool isOffline = Provider.of<ContactInfoState>(context, listen: false).isOnline() == false;
|
||||
if (isOffline) {
|
||||
bool performingAntiSpam = Provider.of<ContactInfoState>(context).antispamTickets == 0;
|
||||
bool isGroup = Provider.of<ContactInfoState>(context).isGroup;
|
||||
if (isOffline || (isGroup && performingAntiSpam)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isGroup = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(Provider.of<AppState>(context, listen: false).selectedConversation!)!.isGroup;
|
||||
|
||||
// peers and groups currently have different length constraints (servers can store less)...
|
||||
var actualMessageLength = ctrlrCompose.value.text.length;
|
||||
var lengthOk = (isGroup && actualMessageLength < GroupMessageLengthMax) || actualMessageLength <= P2PMessageLengthMax;
|
||||
|
@ -303,6 +354,12 @@ class _MessageViewState extends State<MessageView> {
|
|||
}
|
||||
|
||||
void _sendMessageHandler(dynamic messageJson) {
|
||||
if (Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context, listen: false).antispamTickets == 0) {
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.acquiringTicketsFromServer));
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
return;
|
||||
}
|
||||
|
||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||
var profile = Provider.of<ProfileInfoState>(context, listen: false);
|
||||
|
@ -323,6 +380,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
);
|
||||
}
|
||||
|
||||
Provider.of<ContactInfoState>(context, listen: false).messageDraft = null;
|
||||
ctrlrCompose.clear();
|
||||
focusNode.requestFocus();
|
||||
|
||||
|
@ -520,6 +578,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
enabled: true, // always allow editing...
|
||||
|
||||
onChanged: (String x) {
|
||||
Provider.of<ContactInfoState>(context, listen: false).messageDraft = x;
|
||||
setState(() {
|
||||
// we need to force a rerender here to update the max length count
|
||||
});
|
||||
|
@ -533,8 +592,14 @@ class _MessageViewState extends State<MessageView> {
|
|||
suffixIcon: ElevatedButton(
|
||||
key: Key("btnSend"),
|
||||
style: ElevatedButton.styleFrom(padding: EdgeInsets.all(0.0), shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(45.0))),
|
||||
child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of<Settings>(context).theme.defaultButtonTextColor),
|
||||
onPressed: isOffline ? null : _sendMessage,
|
||||
child: Tooltip(
|
||||
message: isOffline
|
||||
? (isGroup ? AppLocalizations.of(context)!.serverNotSynced : AppLocalizations.of(context)!.peerOfflineMessage)
|
||||
: (isGroup && Provider.of<ContactInfoState>(context, listen: false).antispamTickets == 0)
|
||||
? AppLocalizations.of(context)!.acquiringTicketsFromServer
|
||||
: AppLocalizations.of(context)!.sendMessage,
|
||||
child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of<Settings>(context).theme.defaultButtonTextColor)),
|
||||
onPressed: isOffline || (isGroup && Provider.of<ContactInfoState>(context, listen: false).antispamTickets == 0) ? null : _sendMessage,
|
||||
))),
|
||||
)));
|
||||
|
||||
|
@ -555,6 +620,9 @@ class _MessageViewState extends State<MessageView> {
|
|||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var message = snapshot.data! as Message;
|
||||
var qTextColor = message.getMetadata().senderHandle != Provider.of<AppState>(context).selectedProfile
|
||||
? Provider.of<Settings>(context).theme.messageFromOtherTextColor
|
||||
: Provider.of<Settings>(context).theme.messageFromMeTextColor;
|
||||
return Container(
|
||||
margin: EdgeInsets.all(5),
|
||||
padding: EdgeInsets.all(5),
|
||||
|
@ -563,6 +631,26 @@ class _MessageViewState extends State<MessageView> {
|
|||
: Provider.of<Settings>(context).theme.messageFromMeBackgroundColor,
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Stack(children: [
|
||||
Container(
|
||||
margin: EdgeInsets.all(5),
|
||||
padding: EdgeInsets.all(5),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: message.getMetadata().senderHandle != Provider.of<AppState>(context).selectedProfile
|
||||
? Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor
|
||||
: Provider.of<Settings>(context).theme.messageFromMeBackgroundColor,
|
||||
),
|
||||
height: 75,
|
||||
child: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
Padding(padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), child: Icon(Icons.reply, size: 32, color: qTextColor)),
|
||||
Flexible(
|
||||
child: DefaultTextStyle(
|
||||
textWidthBasis: TextWidthBasis.parent,
|
||||
child: message.getPreviewWidget(context),
|
||||
style: TextStyle(color: qTextColor),
|
||||
overflow: TextOverflow.fade,
|
||||
))
|
||||
])),
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: IconButton(
|
||||
|
@ -573,16 +661,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
Provider.of<AppState>(context, listen: false).selectedIndex = null;
|
||||
},
|
||||
)),
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(padding: EdgeInsets.all(2.0), child: Icon(Icons.reply)),
|
||||
)
|
||||
]),
|
||||
Wrap(
|
||||
runAlignment: WrapAlignment.spaceEvenly,
|
||||
alignment: WrapAlignment.center,
|
||||
runSpacing: 1.0,
|
||||
children: [Center(widthFactor: 1.0, child: Padding(padding: EdgeInsets.all(10.0), child: message.getPreviewWidget(context)))]),
|
||||
]));
|
||||
} else {
|
||||
return MessageLoadingBubble();
|
||||
|
@ -603,6 +682,10 @@ class _MessageViewState extends State<MessageView> {
|
|||
var data = event.data;
|
||||
if (event is RawKeyUpEvent) {
|
||||
if ((data.logicalKey == LogicalKeyboardKey.enter && !event.isShiftPressed) || data.logicalKey == LogicalKeyboardKey.numpadEnter && !event.isShiftPressed) {
|
||||
// Don't send when inserting a new line that is not at the end of the message
|
||||
if (ctrlrCompose.selection.baseOffset != ctrlrCompose.text.length) {
|
||||
return;
|
||||
}
|
||||
_sendMessage();
|
||||
}
|
||||
}
|
||||
|
@ -625,6 +708,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Text(AppLocalizations.of(bcontext)!.invitationLabel),
|
||||
SizedBox(
|
||||
|
@ -633,10 +717,10 @@ class _MessageViewState extends State<MessageView> {
|
|||
ChangeNotifierProvider.value(
|
||||
value: Provider.of<ProfileInfoState>(ctx, listen: false),
|
||||
child: DropdownContacts(filter: (contact) {
|
||||
return contact.onion != Provider.of<ContactInfoState>(context).onion;
|
||||
return contact.onion != Provider.of<ContactInfoState>(ctx).onion;
|
||||
}, onChanged: (newVal) {
|
||||
setState(() {
|
||||
this.selectedContact = Provider.of<ProfileInfoState>(context, listen: false).contactList.findContact(newVal)!.identifier;
|
||||
this.selectedContact = Provider.of<ProfileInfoState>(ctx, listen: false).contactList.findContact(newVal)!.identifier;
|
||||
});
|
||||
})),
|
||||
SizedBox(
|
||||
|
|
|
@ -140,7 +140,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
|
|||
CwtchButtonTextField(
|
||||
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
|
||||
onPressed: _copyOnion,
|
||||
icon: Icon(CwtchIcons.address_copy_2),
|
||||
icon: Icon(CwtchIcons.address_copy),
|
||||
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||
)
|
||||
]),
|
||||
|
|
|
@ -206,7 +206,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
padding: MediaQuery.of(context).viewInsets,
|
||||
child: RepaintBoundary(
|
||||
child: Container(
|
||||
height: 200, // bespoke value courtesy of the [TextField] docs
|
||||
height: Platform.isAndroid ? 250 : 200, // bespoke value courtesy of the [TextField] docs
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
|
@ -221,7 +221,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
Expanded(
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size(double.infinity, 20),
|
||||
minimumSize: Size(399, 20),
|
||||
maximumSize: Size(400, 20),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
),
|
||||
|
@ -242,15 +242,16 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
message: AppLocalizations.of(context)!.importProfileTooltip,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size(double.infinity, 20),
|
||||
minimumSize: Size(399, 20),
|
||||
maximumSize: Size(400, 20),
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide(color: Provider.of<Settings>(context).theme.defaultButtonActiveColor, width: 2.0),
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(180), right: Radius.circular(180))),
|
||||
primary: Provider.of<Settings>(context).theme.backgroundMainColor,
|
||||
),
|
||||
child:
|
||||
Text(AppLocalizations.of(context)!.importProfile, semanticsLabel: AppLocalizations.of(context)!.importProfile, style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
child: Text(AppLocalizations.of(context)!.importProfile,
|
||||
semanticsLabel: AppLocalizations.of(context)!.importProfile,
|
||||
style: TextStyle(color: Provider.of<Settings>(context).theme.mainTextColor, fontWeight: FontWeight.bold)),
|
||||
onPressed: () {
|
||||
// 10GB profiles should be enough for anyone?
|
||||
showFilePicker(context, MaxGeneralFileSharingSize, (file) {
|
||||
|
@ -287,7 +288,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
padding: MediaQuery.of(context).viewInsets,
|
||||
child: RepaintBoundary(
|
||||
child: Container(
|
||||
height: 200, // bespoke value courtesy of the [TextField] docs
|
||||
height: Platform.isAndroid ? 250 : 200, // bespoke value courtesy of the [TextField] docs
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
|
@ -339,7 +340,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
(ProfileInfoState profile) {
|
||||
return ChangeNotifierProvider<ProfileInfoState>.value(
|
||||
value: profile,
|
||||
builder: (context, child) => RepaintBoundary(child: ProfileRow()),
|
||||
builder: (context, child) => ProfileRow(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ class _ProfileServersView extends State<ProfileServersView> {
|
|||
(RemoteServerInfoState server) {
|
||||
return ChangeNotifierProvider<RemoteServerInfoState>.value(
|
||||
value: server,
|
||||
builder: (context, child) => RepaintBoundary(child: RemoteServerRow()),
|
||||
builder: (context, child) => RemoteServerRow(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -29,6 +29,7 @@ class _DropdownContactsState extends State<DropdownContacts> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButton(
|
||||
isExpanded: true, // magic property
|
||||
value: this.selected,
|
||||
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.where(widget.filter).map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
||||
return DropdownMenuItem<String>(value: contact.onion, child: Text(contact.nickname));
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:cwtch/models/appstate.dart';
|
||||
import 'package:cwtch/models/contact.dart';
|
||||
import 'package:cwtch/models/contactlist.dart';
|
||||
import 'package:cwtch/models/profile.dart';
|
||||
import 'package:cwtch/views/contactsview.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -18,6 +19,8 @@ class ContactRow extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ContactRowState extends State<ContactRow> {
|
||||
bool isHover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var contact = Provider.of<ContactInfoState>(context);
|
||||
|
@ -34,12 +37,11 @@ class _ContactRowState extends State<ContactRow> {
|
|||
));
|
||||
}
|
||||
|
||||
return Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: Provider.of<AppState>(context).selectedConversation == contact.identifier ? Provider.of<Settings>(context).theme.backgroundHilightElementColor : null,
|
||||
borderOnForeground: true,
|
||||
margin: EdgeInsets.all(0.0),
|
||||
child: InkWell(
|
||||
return InkWell(
|
||||
enableFeedback: true,
|
||||
splashFactory: InkSplash.splashFactory,
|
||||
child: Ink(
|
||||
color: Provider.of<AppState>(context).selectedConversation == contact.identifier ? Provider.of<Settings>(context).theme.backgroundHilightElementColor : Colors.transparent,
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(6.0), //border size
|
||||
|
@ -123,11 +125,38 @@ class _ContactRowState extends State<ContactRow> {
|
|||
),
|
||||
],
|
||||
))),
|
||||
]),
|
||||
onTap: () {
|
||||
selectConversation(context, contact.identifier);
|
||||
},
|
||||
));
|
||||
Visibility(
|
||||
// only allow pinning for non-blocked and accepted conversations,
|
||||
visible: contact.isAccepted() && (Platform.isAndroid || (!Platform.isAndroid && isHover) || contact.pinned),
|
||||
child: IconButton(
|
||||
tooltip: contact.pinned ? AppLocalizations.of(context)!.tooltipUnpinConversation : AppLocalizations.of(context)!.tooltipPinConversation,
|
||||
icon: Icon(
|
||||
contact.pinned ? Icons.push_pin : Icons.push_pin_outlined,
|
||||
color: Provider.of<Settings>(context).theme.mainTextColor,
|
||||
),
|
||||
onPressed: () {
|
||||
if (contact.pinned) {
|
||||
contact.unpin(context);
|
||||
} else {
|
||||
contact.pin(context);
|
||||
}
|
||||
Provider.of<ContactListState>(context, listen: false).resort();
|
||||
},
|
||||
))
|
||||
])),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectConversation(context, contact.identifier);
|
||||
});
|
||||
},
|
||||
onHover: (hover) {
|
||||
if (isHover != hover) {
|
||||
setState(() {
|
||||
isHover = hover;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _btnApprove() {
|
||||
|
|
|
@ -266,7 +266,7 @@ class FileBubbleState extends State<FileBubble> {
|
|||
var manifestPath = file.path + ".manifest";
|
||||
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "file-downloaded", "true");
|
||||
ContactInfoState? contact = Provider.of<ProfileInfoState>(context, listen: false).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
|
||||
ContactInfoState? contact = Provider.of<ProfileInfoState>(context, listen: false).contactList.findContact(Provider.of<MessageMetadata>(context, listen: false).senderHandle);
|
||||
if (contact != null) {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DownloadFile(profileOnion, contact.identifier, file.path, manifestPath, widget.fileKey());
|
||||
}
|
||||
|
|
|
@ -32,15 +32,18 @@ class _MessageListState extends State<MessageList> {
|
|||
var initi = Provider.of<AppState>(outerContext, listen: false).initialScrollIndex;
|
||||
bool isP2P = !Provider.of<ContactInfoState>(context).isGroup;
|
||||
bool isGroupAndSyncing = Provider.of<ContactInfoState>(context).isGroup == true && Provider.of<ContactInfoState>(context).status == "Authenticated";
|
||||
bool isGroupAndSynced = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status == "Synced";
|
||||
bool isGroupAndNotAuthenticated = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status != "Authenticated";
|
||||
|
||||
// Older checks, no longer used, kept for reference.
|
||||
//bool isGroupAndSynced = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status == "Synced";
|
||||
//bool isGroupAndNotAuthenticated = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status != "Authenticated";
|
||||
|
||||
bool showEphemeralWarning = (isP2P && Provider.of<ContactInfoState>(context).savePeerHistory != "SaveHistory");
|
||||
bool showOfflineWarning = Provider.of<ContactInfoState>(context).isOnline() == false;
|
||||
bool showSyncing = isGroupAndSyncing;
|
||||
bool showMessageWarning = showEphemeralWarning || showOfflineWarning || showSyncing;
|
||||
// Only load historical messages when the conversation is with a p2p contact OR the conversation is a server and *not* syncing.
|
||||
bool loadMessages = isP2P || (isGroupAndSynced || isGroupAndNotAuthenticated);
|
||||
// We used to only load historical messages when the conversation is with a p2p contact OR the conversation is a server and *not* syncing.
|
||||
// With the message cache in place this is no longer necessary
|
||||
bool loadMessages = true;
|
||||
|
||||
return RepaintBoundary(
|
||||
child: Container(
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cwtch/models/contact.dart';
|
|||
import 'package:cwtch/models/message.dart';
|
||||
import 'package:cwtch/models/profile.dart';
|
||||
import 'package:cwtch/views/contactsview.dart';
|
||||
import 'package:cwtch/widgets/staticmessagebubble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cwtch/widgets/profileimage.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
|
@ -15,6 +16,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
import '../main.dart';
|
||||
import '../models/messagecache.dart';
|
||||
import '../settings.dart';
|
||||
|
||||
class MessageRow extends StatefulWidget {
|
||||
|
@ -74,7 +76,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
}
|
||||
}
|
||||
|
||||
Widget wdgIcons = Platform.isAndroid
|
||||
Widget wdgReply = Platform.isAndroid
|
||||
? SizedBox.shrink()
|
||||
: Visibility(
|
||||
visible: EnvironmentConfig.TEST_MODE || Provider.of<AppState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
|
||||
|
@ -90,13 +92,37 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
},
|
||||
icon: Icon(Icons.reply, color: Provider.of<Settings>(context).theme.dropShadowColor)));
|
||||
|
||||
var settings = Provider.of<Settings>(context);
|
||||
var pis = Provider.of<ProfileInfoState>(context);
|
||||
var cis = Provider.of<ContactInfoState>(context);
|
||||
var borderColor = Provider.of<Settings>(context).theme.portraitOnlineBorderColor;
|
||||
var messageID = Provider.of<MessageMetadata>(context).messageID;
|
||||
var cache = Provider.of<ContactInfoState>(context).messageCache;
|
||||
|
||||
Widget wdgSeeReplies = Platform.isAndroid
|
||||
? SizedBox.shrink()
|
||||
: Visibility(
|
||||
visible: EnvironmentConfig.TEST_MODE || Provider.of<AppState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
|
||||
maintainSize: true,
|
||||
maintainAnimation: true,
|
||||
maintainState: true,
|
||||
maintainInteractivity: false,
|
||||
child: IconButton(
|
||||
tooltip: AppLocalizations.of(context)!.viewReplies,
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
onPressed: () {
|
||||
modalShowReplies(context, AppLocalizations.of(context)!.headingReplies, AppLocalizations.of(context)!.messageNoReplies, settings, pis, cis, borderColor, cache, messageID);
|
||||
},
|
||||
icon: Icon(CwtchIcons.view_replies, color: Provider.of<Settings>(context).theme.dropShadowColor)));
|
||||
|
||||
Widget wdgSpacer = Flexible(flex: 1, child: SizedBox(width: Platform.isAndroid ? 20 : 60, height: 10));
|
||||
var widgetRow = <Widget>[];
|
||||
|
||||
if (fromMe) {
|
||||
widgetRow = <Widget>[
|
||||
wdgSpacer,
|
||||
wdgIcons,
|
||||
wdgSeeReplies,
|
||||
wdgReply,
|
||||
actualMessage,
|
||||
];
|
||||
} else if (isBlocked && !showBlockedMessage) {
|
||||
|
@ -143,7 +169,8 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
});
|
||||
})),
|
||||
]))),
|
||||
wdgIcons,
|
||||
wdgReply,
|
||||
wdgSeeReplies,
|
||||
wdgSpacer,
|
||||
];
|
||||
} else {
|
||||
|
@ -179,7 +206,8 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
widgetRow = <Widget>[
|
||||
wdgPortrait,
|
||||
actualMessage,
|
||||
wdgIcons,
|
||||
wdgReply,
|
||||
wdgSeeReplies,
|
||||
wdgSpacer,
|
||||
];
|
||||
}
|
||||
|
@ -212,6 +240,9 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
_runAnimation(details.velocity.pixelsPerSecond, size);
|
||||
Provider.of<AppState>(context, listen: false).selectedIndex = Provider.of<MessageMetadata>(context, listen: false).messageID;
|
||||
},
|
||||
onLongPress: () async {
|
||||
modalShowReplies(context, AppLocalizations.of(context)!.headingReplies, AppLocalizations.of(context)!.messageNoReplies, settings, pis, cis, borderColor, cache, messageID);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(2),
|
||||
child: Align(
|
||||
|
@ -332,3 +363,89 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
void modalShowReplies(
|
||||
BuildContext ctx, String replyHeader, String noRepliesText, Settings settings, ProfileInfoState profile, ContactInfoState cis, Color borderColor, MessageCache cache, int messageID,
|
||||
{bool showImage = true}) {
|
||||
showModalBottomSheet<void>(
|
||||
context: ctx,
|
||||
builder: (BuildContext bcontext) {
|
||||
List<Message> replies = getReplies(cache, messageID);
|
||||
|
||||
return ChangeNotifierProvider.value(
|
||||
value: profile,
|
||||
builder: (bcontext, child) {
|
||||
return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
|
||||
var replyWidgets = replies.map((e) {
|
||||
var fromMe = e.getMetadata().senderHandle == profile.onion;
|
||||
|
||||
var bubble = StaticMessageBubble(profile, settings, e.getMetadata(), Row(children: [Flexible(child: e.getPreviewWidget(context))]));
|
||||
|
||||
String imagePath = e.getMetadata().senderImage!;
|
||||
var sender = profile.contactList.findContact(e.getMetadata().senderHandle);
|
||||
if (sender != null) {
|
||||
imagePath = showImage ? sender.imagePath : sender.defaultImagePath;
|
||||
}
|
||||
|
||||
if (fromMe) {
|
||||
imagePath = profile.imagePath;
|
||||
}
|
||||
|
||||
var image = Padding(
|
||||
padding: EdgeInsets.all(4.0),
|
||||
child: ProfileImage(
|
||||
imagePath: imagePath,
|
||||
diameter: 48.0,
|
||||
border: borderColor,
|
||||
badgeTextColor: Colors.red,
|
||||
badgeColor: Colors.red,
|
||||
));
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [image, Flexible(child: bubble)],
|
||||
));
|
||||
}).toList();
|
||||
|
||||
var withHeader = replyWidgets;
|
||||
|
||||
var original =
|
||||
StaticMessageBubble(profile, settings, cache.cache[messageID]!.metadata, Row(children: [Flexible(child: compileOverlay(cache.cache[messageID]!).getPreviewWidget(context))]));
|
||||
|
||||
withHeader.insert(0, Padding(padding: EdgeInsets.fromLTRB(10.0, 10.0, 2.0, 15.0), child: Center(child: original)));
|
||||
|
||||
withHeader.insert(
|
||||
1,
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(10.0, 10.0, 2.0, 15.0),
|
||||
child: Divider(
|
||||
color: settings.theme.mainTextColor,
|
||||
)));
|
||||
|
||||
if (replies.isNotEmpty) {
|
||||
withHeader.insert(2, Padding(padding: EdgeInsets.fromLTRB(10.0, 10.0, 2.0, 15.0), child: Text(replyHeader, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold))));
|
||||
} else {
|
||||
withHeader.insert(
|
||||
2, Padding(padding: EdgeInsets.fromLTRB(10.0, 10.0, 2.0, 15.0), child: Center(child: Text(noRepliesText, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)))));
|
||||
}
|
||||
|
||||
return Scrollbar(
|
||||
isAlwaysShown: true,
|
||||
child: SingleChildScrollView(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 0.0, horizontal: 20.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: withHeader,
|
||||
)))));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ class ProfileImage extends StatefulWidget {
|
|||
required this.badgeTextColor,
|
||||
this.maskOut = false,
|
||||
this.tooltip = "",
|
||||
this.badgeEdit = false});
|
||||
this.badgeEdit = false,
|
||||
this.badgeIcon = null});
|
||||
final double diameter;
|
||||
final String imagePath;
|
||||
final Color border;
|
||||
|
@ -27,6 +28,7 @@ class ProfileImage extends StatefulWidget {
|
|||
final bool maskOut;
|
||||
final bool badgeEdit;
|
||||
final String tooltip;
|
||||
final Widget? badgeIcon;
|
||||
|
||||
@override
|
||||
_ProfileImageState createState() => _ProfileImageState();
|
||||
|
@ -81,7 +83,7 @@ class _ProfileImageState extends State<ProfileImage> {
|
|||
padding: const EdgeInsets.all(2.0), //border size
|
||||
child: ClipOval(clipBehavior: Clip.antiAlias, child: widget.tooltip == "" ? image : Tooltip(message: widget.tooltip, child: image))))),
|
||||
Visibility(
|
||||
visible: widget.badgeEdit || widget.badgeCount > 0,
|
||||
visible: widget.badgeIcon != null || widget.badgeEdit || widget.badgeCount > 0,
|
||||
child: Positioned(
|
||||
bottom: 0.0,
|
||||
right: 0.0,
|
||||
|
@ -93,7 +95,7 @@ class _ProfileImageState extends State<ProfileImage> {
|
|||
Icons.edit,
|
||||
color: widget.badgeTextColor,
|
||||
)
|
||||
: Text(widget.badgeCount > 99 ? "99+" : widget.badgeCount.toString(), style: TextStyle(color: widget.badgeTextColor, fontSize: 8.0)),
|
||||
: (widget.badgeIcon != null ? widget.badgeIcon : Text(widget.badgeCount > 99 ? "99+" : widget.badgeCount.toString(), style: TextStyle(color: widget.badgeTextColor, fontSize: 8.0))),
|
||||
),
|
||||
)),
|
||||
]));
|
||||
|
|
|
@ -58,7 +58,7 @@ class _ServerRowState extends State<ServerRow> {
|
|||
enableFeedback: true,
|
||||
splashRadius: Material.defaultSplashRadius / 2,
|
||||
tooltip: AppLocalizations.of(context)!.copyServerKeys,
|
||||
icon: Icon(CwtchIcons.address_copy_2, color: Provider.of<Settings>(context).current().mainTextColor),
|
||||
icon: Icon(CwtchIcons.address_copy, color: Provider.of<Settings>(context).current().mainTextColor),
|
||||
onPressed: () {
|
||||
Clipboard.setData(new ClipboardData(text: server.serverBundle));
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.copiedToClipboardNotification));
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import 'package:cwtch/models/contact.dart';
|
||||
import 'package:cwtch/models/message.dart';
|
||||
import 'package:cwtch/models/profile.dart';
|
||||
import 'package:cwtch/widgets/malformedbubble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../settings.dart';
|
||||
import 'messagebubbledecorations.dart';
|
||||
|
||||
class StaticMessageBubble extends StatefulWidget {
|
||||
final ProfileInfoState profile;
|
||||
final Settings settings;
|
||||
final MessageMetadata metadata;
|
||||
final Widget child;
|
||||
|
||||
StaticMessageBubble(this.profile, this.settings, this.metadata, this.child);
|
||||
|
||||
@override
|
||||
StaticMessageBubbleState createState() => StaticMessageBubbleState();
|
||||
}
|
||||
|
||||
class StaticMessageBubbleState extends State<StaticMessageBubble> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var fromMe = widget.metadata.senderHandle == widget.profile.onion;
|
||||
var borderRadiousEh = 15.0;
|
||||
DateTime messageDate = widget.metadata.timestamp;
|
||||
|
||||
// If the sender is not us, then we want to give them a nickname...
|
||||
var senderDisplayStr = "";
|
||||
if (!fromMe) {
|
||||
ContactInfoState? contact = widget.profile.contactList.findContact(widget.metadata.senderHandle);
|
||||
if (contact != null) {
|
||||
senderDisplayStr = contact.nickname;
|
||||
} else {
|
||||
senderDisplayStr = widget.metadata.senderHandle;
|
||||
}
|
||||
} else {
|
||||
senderDisplayStr = widget.profile.nickname;
|
||||
}
|
||||
|
||||
var wdgSender = SelectableText(senderDisplayStr, style: TextStyle(fontSize: 9.0, color: fromMe ? widget.settings.theme.messageFromMeTextColor : widget.settings.theme.messageFromOtherTextColor));
|
||||
|
||||
var wdgDecorations = MessageBubbleDecoration(ackd: widget.metadata.ackd, errored: widget.metadata.error, fromMe: fromMe, messageDate: messageDate);
|
||||
|
||||
var error = widget.metadata.error;
|
||||
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
//print(constraints.toString()+", "+constraints.maxWidth.toString());
|
||||
return RepaintBoundary(
|
||||
child: Container(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: error ? malformedColor : (fromMe ? widget.settings.theme.messageFromMeBackgroundColor : widget.settings.theme.messageFromOtherBackgroundColor),
|
||||
border: Border.all(color: error ? malformedColor : (fromMe ? widget.settings.theme.messageFromMeBackgroundColor : widget.settings.theme.messageFromOtherBackgroundColor), width: 1),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(borderRadiousEh),
|
||||
topRight: Radius.circular(borderRadiousEh),
|
||||
bottomLeft: Radius.zero,
|
||||
bottomRight: Radius.circular(borderRadiousEh),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(9.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [wdgSender, widget.child, wdgDecorations])))));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -8,4 +8,4 @@ cp linux/cwtch build/linux/x64/release/bundle/
|
|||
cp README.md build/linux/x64/release/bundle/
|
||||
cp linux/cwtch.png build/linux/x64/release/bundle/
|
||||
cp linux/libCwtch.so build/linux/x64/release/bundle/lib/
|
||||
cp linux/tor build/linux/x64/release/bundle/lib
|
||||
cp -r linux/Tor build/linux/x64/release/bundle/lib
|
||||
|
|
66
pubspec.lock
66
pubspec.lock
|
@ -21,7 +21,7 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.11"
|
||||
version: "3.3.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -35,7 +35,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.9.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -105,14 +105,7 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.2.1"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -140,7 +133,7 @@ packages:
|
|||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -168,7 +161,7 @@ packages:
|
|||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -210,7 +203,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -262,7 +255,7 @@ packages:
|
|||
name: flutter_gherkin
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0-rc.9"
|
||||
version: "3.0.0-rc.17"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -331,7 +324,7 @@ packages:
|
|||
name: gherkin
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "3.1.0"
|
||||
glob:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -420,21 +413,21 @@ packages:
|
|||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.12"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
version: "0.1.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.8.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -511,7 +504,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -617,6 +610,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: qr
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
qr_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: qr_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -663,7 +670,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.9.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -691,28 +698,28 @@ packages:
|
|||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
sync_http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sync_http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.3.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.9"
|
||||
version: "0.4.12"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -733,7 +740,7 @@ packages:
|
|||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -790,6 +797,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -803,7 +817,7 @@ packages:
|
|||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.2.2"
|
||||
version: "9.0.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
12
pubspec.yaml
12
pubspec.yaml
|
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.8.0+30
|
||||
version: 1.9.0+35
|
||||
|
||||
environment:
|
||||
sdk: ">=2.15.0 <3.0.0"
|
||||
|
@ -34,7 +34,7 @@ dependencies:
|
|||
cupertino_icons: ^1.0.0
|
||||
ffi: ^1.2.1
|
||||
path_provider: ^2.0.0
|
||||
crypto: 3.0.1
|
||||
crypto: ^3.0.2
|
||||
|
||||
glob: any
|
||||
scrollable_positioned_list: ^0.3.2
|
||||
|
@ -46,11 +46,13 @@ dependencies:
|
|||
win_toast: ^0.0.2
|
||||
flutter_local_notifications: ^9.6.1
|
||||
desktop_notifications: ^0.6.3
|
||||
qr_flutter: ^4.0.0
|
||||
|
||||
dev_dependencies:
|
||||
msix: ^3.6.2
|
||||
flutter_gherkin: ^3.0.0-rc.9
|
||||
build_runner: any
|
||||
flutter_gherkin: ^3.0.0-rc.17
|
||||
|
||||
# integration_test: any
|
||||
# Uncomment to update lokalise translations (see README for list of deps to comment out bc incompatibilities)
|
||||
#dev_dependencies:
|
||||
|
@ -94,9 +96,9 @@ flutter:
|
|||
- assets/servers/
|
||||
|
||||
fonts:
|
||||
- family: CwtchIcons
|
||||
- family: Cwtch
|
||||
fonts:
|
||||
- asset: assets/fonts/CwtchIcons.ttf
|
||||
- asset: assets/fonts/Cwtch.ttf
|
||||
- family: RobotoMono
|
||||
fonts:
|
||||
- asset: assets/fonts/RobotoMono-Regular.ttf
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# https://stackoverflow.com/questions/48509114/how-to-create-a-working-trusted-and-or-self-signed-certificate-for-a-windows-10
|
||||
# https://docs.microsoft.com/en-us/powershell/module/pki/new-selfsignedcertificate?view=windowsserver2022-ps
|
||||
|
||||
|
||||
# -FriendlyName
|
||||
# Specifies a friendly name for the new certificate.
|
||||
# -CertStoreLocation cert:\CurrentUser\My
|
||||
# So we don't need elevated privs
|
||||
New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=Open Privacy Research Society,O=Open Privacy Research Society,0=Open Privacy Research Society,C=CA,ST=British Columbia,L=Vancouver" -TextExtension @("2.5.29.19={text}false") -KeyUsage DigitalSignature -KeyLength 4096 -NotAfter (Get-Date).AddMonths(33) -FriendlyName OPCodeCert -CertStoreLocation cert:\CurrentUser\My
|
||||
|
||||
> Thumbprint Subject
|
||||
> ---------- -------
|
||||
> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx CN="Open Privacy Research Society,O=Open Privacy Research Society,0=Open Privacy Research Society,C=CA,ST=British Columbia,L=Vancouver"
|
||||
|
||||
$pwd = ConvertTo-SecureString -String <Your Password> -Force -AsPlainText
|
||||
|
||||
Export-PfxCertificate -cert "cert:\CurrentUser\My\<Certificate Thumbprint>" -FilePath opcodecertselfsign2022.pfx -Password $pwd
|
Loading…
Reference in New Issue