Merge branch 'trunk' into assetsDir
continuous-integration/drone/pr Build is passing
Details
continuous-integration/drone/pr Build is passing
Details
This commit is contained in:
commit
07e8c49d7b
|
@ -59,7 +59,8 @@ steps:
|
|||
- cp linux/cwtch.desktop deploy/linux
|
||||
- cp linux/cwtch.png deploy/linux
|
||||
- cp linux/libCwtch.so deploy/linux/lib/
|
||||
- cp /sdks/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat deploy/linux
|
||||
# should not be needed, should be in data/flutter_assets and work from there
|
||||
#- cp /sdks/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat deploy/linux
|
||||
- cp tor deploy/linux
|
||||
- cd deploy
|
||||
- mv linux cwtch
|
||||
|
@ -230,6 +231,12 @@ steps:
|
|||
- mkdir deploy
|
||||
- move build\\windows\\runner\\Release $Env:builddir
|
||||
- copy windows\libCwtch.dll $Env:builddir
|
||||
# flutter hasn't worked out it's packaging of required dll's so we have to resort to this manual nonsense
|
||||
# https://github.com/google/flutter-desktop-embedding/issues/587
|
||||
# https://github.com/flutter/flutter/issues/53167
|
||||
- copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140.dll $Env:builddir
|
||||
- copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:builddir
|
||||
- copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:builddir
|
||||
- powershell -command "Expand-Archive -Path tor.zip -DestinationPath $Env:builddir\Tor"
|
||||
- powershell -command "Compress-Archive -Path $Env:builddir -DestinationPath $Env:zip"
|
||||
- powershell -command "(Get-FileHash *.zip -Algorithm sha512).Hash" > $Env:sha
|
||||
|
|
|
@ -1 +1 @@
|
|||
v0.0.2-49-g6a0e839-2021-06-02-19-40
|
||||
v0.0.2-63-g033de73-2021-06-11-21-41
|
25
README.md
25
README.md
|
@ -32,14 +32,24 @@ After adding a new key and providing/obtaining translations for it, follow the n
|
|||
|
||||
### Updating translations
|
||||
|
||||
Only Open Privacy staff members can update translations automatically:
|
||||
Only Open Privacy staff members can update translations.
|
||||
|
||||
```
|
||||
flutter pub run flutter_lokalise download -v --api-token "<X>" --project-id "<Y>"
|
||||
```
|
||||
In Lokalise, hit Download and make sure:
|
||||
|
||||
This will download a bundle of translations from Lokalise and convert it to resource files in `lib/l10n/intl_*.arb`.
|
||||
The next time Flwtch is built, Flutter will notice the changes and update `app_localizations.dart` accordingly (thanks to `generate:true` in `pubspec.yaml`).
|
||||
* Format is set to "Flutter (.arb)
|
||||
* Output filename is set to `l10n/intl_%LANG_ISO%.%FORMAT%`
|
||||
* Empty translations is set to "Replace with base language"
|
||||
|
||||
Build, download and unzip the output, overwriting `lib/l10n`. The next time Flwtch is built, Flutter will notice the changes and update `app_localizations.dart` accordingly (thanks to `generate:true` in `pubspec.yaml`).
|
||||
|
||||
### Adding a language
|
||||
|
||||
If a new language has been added to the Lokalise project, two additional manual steps need to be done:
|
||||
|
||||
* Create a new key called `localeXX` for the name of the language
|
||||
* Add it to the settings pane by updating `getLanguageFull()` in `lib/views/globalsettingsview.dart`
|
||||
|
||||
Then rebuild as normal.
|
||||
|
||||
### Using a string
|
||||
|
||||
|
@ -57,6 +67,5 @@ Text(AppLocalizations.of(context)!.stringIdentifer),
|
|||
|
||||
### Configuration
|
||||
|
||||
API tokens are only available to Open Privacy staff at this time, who will perform the translation updates for you as part of merging your PRs.
|
||||
|
||||
With `generate: true` in `pubspec.yaml`, the Flutter build process checks `l10n.yaml` for input/output filenames.
|
||||
|
||||
|
|
|
@ -69,6 +69,15 @@ android {
|
|||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
|
@ -82,4 +91,30 @@ dependencies {
|
|||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
|
||||
implementation "com.airbnb.android:lottie:3.5.0"
|
||||
implementation "com.android.support.constraint:constraint-layout:2.0.4"
|
||||
|
||||
// WorkManager
|
||||
|
||||
// (Java only)
|
||||
//implementation("androidx.work:work-runtime:$work_version")
|
||||
|
||||
// Kotlin + coroutines
|
||||
implementation("androidx.work:work-runtime-ktx:2.5.0")
|
||||
|
||||
// optional - RxJava2 support
|
||||
//implementation("androidx.work:work-rxjava2:$work_version")
|
||||
|
||||
// optional - GCMNetworkManager support
|
||||
//implementation("androidx.work:work-gcm:$work_version")
|
||||
|
||||
// optional - Test helpers
|
||||
//androidTestImplementation("androidx.work:work-testing:$work_version")
|
||||
|
||||
// optional - Multiprocess support
|
||||
implementation "androidx.work:work-multiprocess:2.5.0"
|
||||
|
||||
// end of workmanager deps
|
||||
|
||||
// needed to prevent a ListenableFuture dependency conflict/bug
|
||||
// see https://github.com/google/ExoPlayer/issues/7905#issuecomment-692637059
|
||||
implementation 'com.google.guava:guava:any'
|
||||
}
|
||||
|
|
|
@ -43,4 +43,9 @@
|
|||
<!--Needed to access Tor socket-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<!--Needed to run in background (lol)-->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<!--Meeded to check if activity is foregrounded or if messages from the service should be queued-->
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
</manifest>
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
package im.cwtch.flwtch
|
||||
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Context.ACTIVITY_SERVICE
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
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 cwtch.Cwtch
|
||||
import io.flutter.FlutterInjector
|
||||
import org.json.JSONObject
|
||||
|
||||
|
||||
class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
||||
CoroutineWorker(context, parameters) {
|
||||
private val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as
|
||||
NotificationManager
|
||||
|
||||
private var notificationID: MutableMap<String, Int> = mutableMapOf()
|
||||
private var notificationIDnext: Int = 1;
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val method = inputData.getString(KEY_METHOD)
|
||||
?: return Result.failure()
|
||||
val args = inputData.getString(KEY_ARGS)
|
||||
?: return Result.failure()
|
||||
// Mark the Worker as important
|
||||
val progress = "Trying to do a Flwtch"//todo:translate
|
||||
setForeground(createForegroundInfo(progress))
|
||||
return handleCwtch(method, args)
|
||||
}
|
||||
|
||||
private fun getNotificationID(profile: String, contact: String): Int {
|
||||
val k = "$profile $contact"
|
||||
if (!notificationID.containsKey(k)) {
|
||||
notificationID[k] = notificationIDnext++
|
||||
}
|
||||
return notificationID[k] ?: -1
|
||||
}
|
||||
|
||||
private suspend fun handleCwtch(method: String, args: String): Result {
|
||||
val a = JSONObject(args);
|
||||
when (method) {
|
||||
"Start" -> {
|
||||
Log.i("FlwtchWorker.kt", "handleAppInfo Start")
|
||||
val appDir = (a.get("appDir") as? String) ?: ""
|
||||
val torPath = (a.get("torPath") as? String) ?: "tor"
|
||||
Log.i("FlwtchWorker.kt", "appDir: '$appDir' torPath: '$torPath'")
|
||||
|
||||
if (Cwtch.startCwtch(appDir, torPath) != 0.toByte()) return Result.failure()
|
||||
|
||||
// infinite coroutine :)
|
||||
while(true) {
|
||||
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
|
||||
if (evt.EventType == "NewMessageFromPeer") {
|
||||
val data = JSONObject(evt.Data)
|
||||
val channelId =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createMessageNotificationChannel(data.getString("RemotePeer"), data.getString("RemotePeer"))
|
||||
} else {
|
||||
// If earlier version channel ID is not used
|
||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||
""
|
||||
}
|
||||
|
||||
val loader = FlutterInjector.instance().flutterLoader()
|
||||
val key = loader.getLookupKeyForAsset("assets/"+data.getString("Picture"))//"assets/profiles/001-centaur.png")
|
||||
val fh = applicationContext.assets.open(key)
|
||||
|
||||
val clickIntent = Intent(applicationContext, MainActivity::class.java).also { intent ->
|
||||
intent.setAction(Intent.ACTION_RUN)
|
||||
intent.putExtra("EventType", "NotificationClicked")
|
||||
intent.putExtra("ProfileOnion", data.getString("ProfileOnion"))
|
||||
intent.putExtra("RemotePeer", data.getString("RemotePeer"))
|
||||
}
|
||||
|
||||
val newNotification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle(data.getString("Nick"))
|
||||
.setContentText("New message")
|
||||
.setLargeIcon(BitmapFactory.decodeStream(fh))
|
||||
.setSmallIcon(R.mipmap.knott)
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
notificationManager.notify(getNotificationID(data.getString("ProfileOnion"), data.getString("RemotePeer")), newNotification)
|
||||
}
|
||||
|
||||
Intent().also { intent ->
|
||||
intent.setAction("im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS")
|
||||
intent.putExtra("EventType", evt.EventType)
|
||||
intent.putExtra("Data", evt.Data)
|
||||
intent.putExtra("EventID", evt.EventID)
|
||||
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
"ReconnectCwtchForeground" -> {
|
||||
Cwtch.reconnectCwtchForeground()
|
||||
}
|
||||
"SelectProfile" -> {
|
||||
val onion = (a.get("profile") as? String) ?: "";
|
||||
Cwtch.selectProfile(onion)
|
||||
}
|
||||
"CreateProfile" -> {
|
||||
val nick = (a.get("nick") as? String) ?: "";
|
||||
val pass = (a.get("pass") as? String) ?: "";
|
||||
Cwtch.createProfile(nick, pass)
|
||||
}
|
||||
"LoadProfiles" -> {
|
||||
val pass = (a.get("pass") as? String) ?: "";
|
||||
Cwtch.loadProfiles(pass)
|
||||
}
|
||||
"GetProfiles" -> Result.success(Data.Builder().putString("result", Cwtch.getProfiles()).build())
|
||||
// "ACNEvents" -> result.success(Cwtch.acnEvents())
|
||||
"ContactEvents" -> Result.success(Data.Builder().putString("result", Cwtch.contactEvents()).build())
|
||||
"NumMessages" -> {
|
||||
val profile = (a.get("profile") as? String) ?: "";
|
||||
val handle = (a.get("contact") as? String) ?: "";
|
||||
return Result.success(Data.Builder().putLong("result", Cwtch.numMessages(profile, handle)).build())
|
||||
}
|
||||
"GetMessage" -> {
|
||||
val profile = (a.get("profile") as? String) ?: "";
|
||||
val handle = (a.get("contact") as? String) ?: "";
|
||||
val indexI = a.getInt("index") ?: 0;
|
||||
Log.i("FlwtchWorker.kt", "indexI = " + indexI)
|
||||
return Result.success(Data.Builder().putString("result", Cwtch.getMessage(profile, handle, indexI.toLong())).build())
|
||||
}
|
||||
"GetMessages" -> {
|
||||
val profile = (a.get("profile") as? String) ?: "";
|
||||
val handle = (a.get("contact") as? String) ?: "";
|
||||
val start = (a.get("start") as? Long) ?: 0;
|
||||
val end = (a.get("end") as? Long) ?: 0;
|
||||
return Result.success(Data.Builder().putString("result", Cwtch.getMessages(profile, handle, start, end)).build())
|
||||
}
|
||||
"UpdateMessageFlags" -> {
|
||||
val profile = (a.get("profile") as? String) ?: "";
|
||||
val handle = (a.get("contact") as? String) ?: "";
|
||||
val midx = (a.get("midx") as? Long) ?: 0;
|
||||
val flags = (a.get("flags") as? Long) ?: 0;
|
||||
Cwtch.updateMessageFlags(profile, handle, midx, flags);
|
||||
}
|
||||
"AcceptContact" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val handle = (a.get("handle") as? String) ?: "";
|
||||
Cwtch.acceptContact(profile, handle);
|
||||
}
|
||||
"BlockContact" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val handle = (a.get("handle") as? String) ?: "";
|
||||
Cwtch.blockContact(profile, handle);
|
||||
}
|
||||
"DebugResetContact" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val handle = (a.get("handle") as? String) ?: "";
|
||||
Cwtch.debugResetContact(profile, handle);
|
||||
}
|
||||
"SendMessage" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val handle = (a.get("handle") as? String) ?: "";
|
||||
val message = (a.get("message") as? String) ?: "";
|
||||
Cwtch.sendMessage(profile, handle, message);
|
||||
}
|
||||
"SendInvitation" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val handle = (a.get("handle") as? String) ?: "";
|
||||
val target = (a.get("target") as? String) ?: "";
|
||||
Cwtch.sendInvitation(profile, handle, target);
|
||||
}
|
||||
"SendProfileEvent" -> {
|
||||
val onion = (a.get("onion") as? String) ?: "";
|
||||
val jsonEvent = (a.get("jsonEvent") as? String) ?: "";
|
||||
Cwtch.sendProfileEvent(onion, jsonEvent);
|
||||
}
|
||||
"SendAppEvent" -> {
|
||||
val jsonEvent = (a.get("jsonEvent") as? String) ?: "";
|
||||
Cwtch.sendAppEvent(jsonEvent);
|
||||
}
|
||||
"ResetTor" -> {
|
||||
Cwtch.resetTor();
|
||||
}
|
||||
"ImportBundle" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val bundle = (a.get("bundle") as? String) ?: "";
|
||||
Cwtch.importBundle(profile, bundle);
|
||||
}
|
||||
"SetGroupAttribute" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (a.get("groupHandle") as? String) ?: "";
|
||||
val key = (a.get("key") as? String) ?: "";
|
||||
val value = (a.get("value") as? String) ?: "";
|
||||
Cwtch.setGroupAttribute(profile, groupHandle, key, value);
|
||||
}
|
||||
"CreateGroup" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val server = (a.get("server") as? String) ?: "";
|
||||
val groupName = (a.get("groupname") as? String) ?: "";
|
||||
Cwtch.createGroup(profile, server, groupName);
|
||||
}
|
||||
"LeaveGroup" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (a.get("groupHandle") as? String) ?: "";
|
||||
Log.i("FlwtchWorker.kt", "LeaveGroup: need to recompile aar and uncomment this line")//todo
|
||||
//Cwtch.leaveGroup(profile, groupHandle);
|
||||
}
|
||||
"RejectInvite" -> {
|
||||
val profile = (a.get("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (a.get("groupHandle") as? String) ?: "";
|
||||
Cwtch.rejectInvite(profile, groupHandle);
|
||||
}
|
||||
else -> return Result.failure()
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
// Creates an instance of ForegroundInfo which can be used to update the
|
||||
// ongoing notification.
|
||||
private fun createForegroundInfo(progress: String): ForegroundInfo {
|
||||
val id = "flwtch"
|
||||
val title = "Flwtch"
|
||||
val cancel = "Nevermind"//todo: translate
|
||||
// This PendingIntent can be used to cancel the worker
|
||||
val intent = WorkManager.getInstance(applicationContext)
|
||||
.createCancelPendingIntent(getId())
|
||||
|
||||
val channelId =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createNotificationChannel(id, id)
|
||||
} else {
|
||||
// If earlier version channel ID is not used
|
||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||
""
|
||||
}
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, id)
|
||||
.setContentTitle(title)
|
||||
.setTicker(title)
|
||||
.setContentText(progress)
|
||||
.setSmallIcon(R.mipmap.knott)
|
||||
.setOngoing(true)
|
||||
// Add the cancel action to the notification which can
|
||||
// be used to cancel the worker
|
||||
.addAction(android.R.drawable.ic_delete, cancel, intent)
|
||||
.build()
|
||||
|
||||
return ForegroundInfo(101, notification)
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createNotificationChannel(channelId: String, channelName: String): String{
|
||||
val chan = NotificationChannel(channelId,
|
||||
channelName, NotificationManager.IMPORTANCE_NONE)
|
||||
chan.lightColor = Color.MAGENTA
|
||||
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||
notificationManager.createNotificationChannel(chan)
|
||||
return channelId
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createMessageNotificationChannel(channelId: String, channelName: String): String{
|
||||
val chan = NotificationChannel(channelId,
|
||||
channelName, NotificationManager.IMPORTANCE_HIGH)
|
||||
chan.lightColor = Color.MAGENTA
|
||||
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||
notificationManager.createNotificationChannel(chan)
|
||||
return channelId
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_METHOD = "KEY_METHOD"
|
||||
const val KEY_ARGS = "KEY_ARGS"
|
||||
}
|
||||
|
||||
class AppbusEvent(json: String) : JSONObject(json) {
|
||||
val EventType = this.optString("EventType")
|
||||
val EventID = this.optString("EventID")
|
||||
val Data = this.optString("Data")
|
||||
}
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
package im.cwtch.flwtch
|
||||
|
||||
import SplashView
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import androidx.annotation.NonNull
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.work.*
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
@ -25,6 +35,8 @@ import kotlin.concurrent.thread
|
|||
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
|
||||
|
@ -40,13 +52,31 @@ class MainActivity: FlutterActivity() {
|
|||
// Channel to send eventbus events on
|
||||
private val CWTCH_EVENTBUS = "test.flutter.dev/eventBus"
|
||||
|
||||
// Channel to trigger contactview when an external notification is clicked
|
||||
private val CHANNEL_NOTIF_CLICK = "im.cwtch.flwtch/notificationClickHandler"
|
||||
|
||||
private var methodChan: MethodChannel? = null
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
if (methodChan == null || intent.extras == null) return
|
||||
if (!intent.extras!!.containsKey("ProfileOnion") || !intent.extras!!.containsKey("RemotePeer")) {
|
||||
Log.i("onNewIntent", "got intent with no onions")
|
||||
return
|
||||
}
|
||||
val profile = intent.extras!!.getString("ProfileOnion")
|
||||
val handle = intent.extras!!.getString("RemotePeer")
|
||||
val mappo = mapOf("ProfileOnion" to profile, "RemotePeer" to handle)
|
||||
val j = JSONObject(mappo)
|
||||
methodChan!!.invokeMethod("NotificationClicked", j.toString())
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
// Note: this methods are invoked on the main thread.
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_APP_INFO).setMethodCallHandler { call, result -> handleAppInfo(call, result) }
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_CWTCH).setMethodCallHandler { call, result -> handleCwtch(call, result) }
|
||||
|
||||
|
||||
methodChan = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NOTIF_CLICK)
|
||||
}
|
||||
|
||||
private fun handleAppInfo(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
|
@ -61,143 +91,68 @@ class MainActivity: FlutterActivity() {
|
|||
val ainfo = this.applicationContext.packageManager.getApplicationInfo(
|
||||
"im.cwtch.flwtch", // Must be app name
|
||||
PackageManager.GET_SHARED_LIBRARY_FILES)
|
||||
|
||||
return ainfo.nativeLibraryDir
|
||||
}
|
||||
|
||||
// receives messages from the ForegroundService (which provides, ironically enough, the backend)
|
||||
private fun handleCwtch(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
when (call.method) {
|
||||
"Start" -> {
|
||||
Log.i("MainActivity.kt", "handleAppInfo Start")
|
||||
val appDir = (call.argument("appDir") as? String) ?: "";
|
||||
val torPath = (call.argument("torPath") as? String) ?: "tor";
|
||||
Log.i("MainActivity.kt", " appDir: '" + appDir + "' torPath: '" + torPath + "'")
|
||||
Cwtch.startCwtch(appDir, torPath)
|
||||
var method = call.method
|
||||
val argmap: Map<String, String> = call.arguments as Map<String, String>
|
||||
|
||||
// seperate coroutine to poll event bus and send to dart
|
||||
val eventbus_chan = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
|
||||
Log.i("MainActivity.kt", "got event chan: " + eventbus_chan + " launching corouting...")
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
while(true) {
|
||||
val evt = AppbusEvent(Cwtch.getAppBusEvent())
|
||||
Log.i("MainActivity.kt", "got appbusEvent: " + evt)
|
||||
launch(Dispatchers.Main) {
|
||||
//todo: this elides evt.EventID which may be needed at some point?
|
||||
eventbus_chan.invokeMethod(evt.EventType, evt.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"SelectProfile" -> {
|
||||
val onion = (call.argument("profile") as? String) ?: "";
|
||||
Cwtch.selectProfile(onion)
|
||||
}
|
||||
"CreateProfile" -> {
|
||||
val nick = (call.argument("nick") as? String) ?: "";
|
||||
val pass = (call.argument("pass") as? String) ?: "";
|
||||
Cwtch.createProfile(nick, pass)
|
||||
}
|
||||
"LoadProfiles" -> {
|
||||
val pass = (call.argument("pass") as? String) ?: "";
|
||||
Cwtch.loadProfiles(pass)
|
||||
}
|
||||
"GetProfiles" -> result.success(Cwtch.getProfiles())
|
||||
// "ACNEvents" -> result.success(Cwtch.acnEvents())
|
||||
"ContactEvents" -> result.success(Cwtch.contactEvents())
|
||||
"NumMessages" -> {
|
||||
val profile = (call.argument("profile") as? String) ?: "";
|
||||
val handle = (call.argument("contact") as? String) ?: "";
|
||||
result.success(Cwtch.numMessages(profile, handle))
|
||||
}
|
||||
"GetMessage" -> {
|
||||
//Log.i("MainActivivity.kt", (call.argument("index")));
|
||||
// the frontend calls Start every time it fires up, but we don't want to *actually* call Cwtch.Start()
|
||||
// in case the ForegroundService is still running. in both cases, however, we *do* want to re-register
|
||||
// the eventbus listener.
|
||||
if (call.method == "Start") {
|
||||
val workerTag = "cwtchEventBusWorker"
|
||||
val uniqueTag = argmap["torPath"] ?: "nullEventBus"
|
||||
|
||||
// var args : HashMap<String, dynamic> = call.arguments();
|
||||
// Log.i("MainActivity.kt", args);
|
||||
// note: because the ForegroundService is specified as UniquePeriodicWork, it can't actually get
|
||||
// accidentally duplicated. however, we still need to manually check if it's running or not, so
|
||||
// that we can divert this method call to ReconnectCwtchForeground instead if so.
|
||||
val works = WorkManager.getInstance(this).getWorkInfosByTag(workerTag).get()
|
||||
var alreadyRunning = false
|
||||
for (workInfo in works) {
|
||||
if (workInfo.tags.contains(uniqueTag)) {
|
||||
if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) {
|
||||
alreadyRunning = true
|
||||
}
|
||||
} else {
|
||||
WorkManager.getInstance(this).cancelWorkById(workInfo.id)
|
||||
}
|
||||
}
|
||||
|
||||
// register our eventbus listener. note that we observe any/all work according to its tag, which
|
||||
// results in an implicit "reconnection" to old service threads even after frontend restarts
|
||||
val mc = MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, CWTCH_EVENTBUS)
|
||||
val filter = IntentFilter("im.cwtch.flwtch.broadcast.SERVICE_EVENT_BUS")
|
||||
LocalBroadcastManager.getInstance(applicationContext).registerReceiver(MyBroadcastReceiver(mc), filter)
|
||||
|
||||
val profile = (call.argument("profile") as? String) ?: "";
|
||||
val handle = (call.argument("contact") as? String) ?: "";
|
||||
val indexI = call.argument<Int>("index") ?: 0;
|
||||
Log.i("MainActivity.kt", "indexI = " + indexI)
|
||||
result.success(Cwtch.getMessage(profile, handle, indexI.toLong()))
|
||||
if (alreadyRunning) {
|
||||
Log.i("MainActivity.kt", "diverting Start -> Reconnect")
|
||||
method = "ReconnectCwtchForeground"
|
||||
} else {
|
||||
Log.i("MainActivity.kt", "Start() launching foregroundservice")
|
||||
// this is where the eventbus ForegroundService gets launched. WorkManager should keep it alive after this
|
||||
val data: Data = Data.Builder().putString(FlwtchWorker.KEY_METHOD, call.method).putString(FlwtchWorker.KEY_ARGS, JSONObject(argmap).toString()).build()
|
||||
// 15 minutes is the shortest interval you can request
|
||||
val workRequest = PeriodicWorkRequestBuilder<FlwtchWorker>(15, TimeUnit.MINUTES).setInputData(data).addTag(workerTag).addTag(uniqueTag).build()
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork("req_$uniqueTag", ExistingPeriodicWorkPolicy.KEEP, workRequest)
|
||||
return
|
||||
}
|
||||
"GetMessages" -> {
|
||||
val profile = (call.argument("profile") as? String) ?: "";
|
||||
val handle = (call.argument("contact") as? String) ?: "";
|
||||
val start = (call.argument("start") as? Long) ?: 0;
|
||||
val end = (call.argument("end") as? Long) ?: 0;
|
||||
result.success(Cwtch.getMessages(profile, handle, start, end))
|
||||
}
|
||||
"AcceptContact" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val handle = (call.argument("handle") as? String) ?: "";
|
||||
Cwtch.acceptContact(profile, handle);
|
||||
|
||||
// ...otherwise fallthru to a normal ffi method call (and return the result using the result callback)
|
||||
val data: Data = Data.Builder().putString(FlwtchWorker.KEY_METHOD, method).putString(FlwtchWorker.KEY_ARGS, JSONObject(argmap).toString()).build()
|
||||
val workRequest = OneTimeWorkRequestBuilder<FlwtchWorker>().setInputData(data).build()
|
||||
WorkManager.getInstance(this).enqueue(workRequest)
|
||||
WorkManager.getInstance(applicationContext).getWorkInfoByIdLiveData(workRequest.id).observe(
|
||||
this, Observer { workInfo ->
|
||||
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
||||
val res = workInfo.outputData.keyValueMap.toString()
|
||||
result.success(workInfo.outputData.getString("result"))
|
||||
}
|
||||
"BlockContact" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val handle = (call.argument("handle") as? String) ?: "";
|
||||
Cwtch.blockContact(profile, handle);
|
||||
}
|
||||
"DebugResetContact" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val handle = (call.argument("handle") as? String) ?: "";
|
||||
Cwtch.debugResetContact(profile, handle);
|
||||
}
|
||||
"SendMessage" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val handle = (call.argument("handle") as? String) ?: "";
|
||||
val message = (call.argument("message") as? String) ?: "";
|
||||
Cwtch.sendMessage(profile, handle, message);
|
||||
}
|
||||
"SendInvitation" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val handle = (call.argument("handle") as? String) ?: "";
|
||||
val target = (call.argument("target") as? String) ?: "";
|
||||
Cwtch.sendInvitation(profile, handle, target);
|
||||
}
|
||||
"SendProfileEvent" -> {
|
||||
val onion = (call.argument("onion") as? String) ?: "";
|
||||
val jsonEvent = (call.argument("jsonEvent") as? String) ?: "";
|
||||
Cwtch.sendProfileEvent(onion, jsonEvent);
|
||||
}
|
||||
"SendAppEvent" -> {
|
||||
val jsonEvent = (call.argument("jsonEvent") as? String) ?: "";
|
||||
Cwtch.sendAppEvent(jsonEvent);
|
||||
}
|
||||
"ResetTor" -> {
|
||||
Cwtch.resetTor();
|
||||
}
|
||||
"ImportBundle" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val bundle = (call.argument("bundle") as? String) ?: "";
|
||||
Cwtch.importBundle(profile, bundle);
|
||||
}
|
||||
"SetGroupAttribute" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (call.argument("groupHandle") as? String) ?: "";
|
||||
val key = (call.argument("key") as? String) ?: "";
|
||||
val value = (call.argument("value") as? String) ?: "";
|
||||
Cwtch.setGroupAttribute(profile, groupHandle, key, value);
|
||||
}
|
||||
"CreateGroup" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val server = (call.argument("server") as? String) ?: "";
|
||||
val groupName = (call.argument("groupname") as? String) ?: "";
|
||||
Cwtch.createGroup(profile, server, groupName);
|
||||
}
|
||||
"LeaveGroup" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (call.argument("groupHandle") as? String) ?: "";
|
||||
Cwtch.leaveGroup(profile, groupHandle);
|
||||
}
|
||||
"RejectInvite" -> {
|
||||
val profile = (call.argument("ProfileOnion") as? String) ?: "";
|
||||
val groupHandle = (call.argument("groupHandle") as? String) ?: "";
|
||||
Cwtch.rejectInvite(profile, groupHandle);
|
||||
}
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// source: https://web.archive.org/web/20210203022531/https://stackoverflow.com/questions/41928803/how-to-parse-json-in-kotlin/50468095
|
||||
|
@ -219,4 +174,16 @@ class MainActivity: FlutterActivity() {
|
|||
val EventID = this.optString("EventID")
|
||||
val Data = this.optString("Data")
|
||||
}
|
||||
|
||||
class MyBroadcastReceiver(mc: MethodChannel) : BroadcastReceiver() {
|
||||
val eventBus: MethodChannel = mc
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val evtType = intent.getStringExtra("EventType") ?: ""
|
||||
val evtData = intent.getStringExtra("Data") ?: ""
|
||||
//val evtID = intent.getStringExtra("EventID") ?: ""//todo?
|
||||
eventBus.invokeMethod(evtType, evtData)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ subprojects {
|
|||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
//removed due to gradle namespace conflicts that are beyond erinn's mere mortal understanding
|
||||
//task clean(type: Delete) {
|
||||
// delete rootProject.buildDir
|
||||
//}
|
||||
|
|
Binary file not shown.
|
@ -1,6 +1,8 @@
|
|||
abstract class Cwtch {
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> Start();
|
||||
Future<dynamic> Start();
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> ReconnectCwtchForeground();
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
void SelectProfile(String onion);
|
||||
|
@ -38,6 +40,8 @@ abstract class Cwtch {
|
|||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> GetMessage(String profile, String handle, int index);
|
||||
// ignore: non_constant_identifier_names
|
||||
void UpdateMessageFlags(String profile, String handle, int index, int flags);
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<dynamic> GetMessages(String profile, String handle, int start, int end);
|
||||
// ignore: non_constant_identifier_names
|
||||
void SendMessage(String profile, String handle, String message);
|
||||
|
|
|
@ -178,23 +178,24 @@ class CwtchNotifier {
|
|||
profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]);
|
||||
break;
|
||||
case "NewGroup":
|
||||
print("new group invite: $data");
|
||||
print("new group: $data");
|
||||
String invite = data["GroupInvite"].toString();
|
||||
if (invite.startsWith("torv3")) {
|
||||
String inviteJson = new String.fromCharCodes(base64Decode(invite.substring(5)));
|
||||
dynamic groupInvite = jsonDecode(inviteJson);
|
||||
print("new group invite: $groupInvite");
|
||||
print("group invite: $groupInvite");
|
||||
|
||||
// Retrieve Server Status from Cache...
|
||||
String status = "";
|
||||
ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(groupInvite["ServerHost"]);
|
||||
ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])!.serverList.getServer(groupInvite["ServerHost"]);
|
||||
if (serverInfoState != null) {
|
||||
print("Got server status: " + serverInfoState.status);
|
||||
status = serverInfoState.status;
|
||||
}
|
||||
|
||||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(groupInvite["GroupID"]) == null) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], groupInvite["GroupID"],
|
||||
isInvitation: true,
|
||||
isInvitation: false,
|
||||
imagePath: data["PicturePath"],
|
||||
nickname: groupInvite["GroupName"],
|
||||
server: groupInvite["ServerHost"],
|
||||
|
|
|
@ -15,8 +15,8 @@ import '../config.dart';
|
|||
/// Cwtch API ///
|
||||
/////////////////////
|
||||
|
||||
typedef start_cwtch_function = Void Function(Pointer<Utf8> str, Int32 length, Pointer<Utf8> str2, Int32 length2);
|
||||
typedef StartCwtchFn = void Function(Pointer<Utf8> dir, int len, Pointer<Utf8> tor, int torLen);
|
||||
typedef start_cwtch_function = Int8 Function(Pointer<Utf8> str, Int32 length, Pointer<Utf8> str2, Int32 length2);
|
||||
typedef StartCwtchFn = int Function(Pointer<Utf8> dir, int len, Pointer<Utf8> tor, int torLen);
|
||||
|
||||
typedef void_from_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
|
||||
typedef VoidFromStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
|
||||
|
@ -27,6 +27,9 @@ typedef VoidFromStringStringStringFn = void Function(Pointer<Utf8>, int, Pointer
|
|||
typedef void_from_string_string_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
|
||||
typedef VoidFromStringStringStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int);
|
||||
|
||||
typedef void_from_string_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int64, Int64);
|
||||
typedef VoidFromStringStringIntIntFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int);
|
||||
|
||||
typedef access_cwtch_eventbus_function = Void Function();
|
||||
typedef NextEventFn = void Function();
|
||||
|
||||
|
@ -76,7 +79,7 @@ class CwtchFfi implements Cwtch {
|
|||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> Start() async {
|
||||
Future<dynamic> Start() async {
|
||||
String home = "";
|
||||
String bundledTor = "";
|
||||
Map<String, String> envVars = Platform.environment;
|
||||
|
@ -109,6 +112,14 @@ class CwtchFfi implements Cwtch {
|
|||
});
|
||||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> ReconnectCwtchForeground() async {
|
||||
var reconnectCwtch = library.lookup<NativeFunction<Void Function()>>("c_ReconnectCwtchForeground");
|
||||
// ignore: non_constant_identifier_names
|
||||
final ReconnectCwtchForeground = reconnectCwtch.asFunction<void Function()>();
|
||||
ReconnectCwtchForeground();
|
||||
}
|
||||
|
||||
// Called on object being disposed to (presumably on app close) to close the isolate that's listening to libcwtch-go events
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -384,4 +395,14 @@ class CwtchFfi implements Cwtch {
|
|||
final u2 = groupHandle.toNativeUtf8();
|
||||
RejectInvite(u1, u1.length, u2, u2.length);
|
||||
}
|
||||
|
||||
@override
|
||||
void UpdateMessageFlags(String profile, String handle, int index, int flags) {
|
||||
var updateMessageFlagsC = library.lookup<NativeFunction<void_from_string_string_int_int_function>>("c_UpdateMessageFlags");
|
||||
// ignore: non_constant_identifier_names
|
||||
final updateMessageFlags = updateMessageFlagsC.asFunction<VoidFromStringStringIntIntFn>();
|
||||
final utf8profile = profile.toNativeUtf8();
|
||||
final utf8handle = handle.toNativeUtf8();
|
||||
updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cwtch/config.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -43,7 +42,7 @@ class CwtchGomobile implements Cwtch {
|
|||
}
|
||||
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> Start() async {
|
||||
Future<dynamic> Start() async {
|
||||
print("gomobile.dart: Start()...");
|
||||
var cwtchDir = path.join((await androidHomeDirectory).path, ".cwtch");
|
||||
if (EnvironmentConfig.BUILD_VER == dev_version) {
|
||||
|
@ -51,7 +50,13 @@ class CwtchGomobile implements Cwtch {
|
|||
}
|
||||
String torPath = path.join(await androidLibraryDir, "libtor.so");
|
||||
print("gomobile.dart: Start invokeMethod Start($cwtchDir, $torPath)...");
|
||||
cwtchPlatform.invokeMethod("Start", {"appDir": cwtchDir, "torPath": torPath});
|
||||
return cwtchPlatform.invokeMethod("Start", {"appDir": cwtchDir, "torPath": torPath});
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
Future<void> ReconnectCwtchForeground() async {
|
||||
cwtchPlatform.invokeMethod("ReconnectCwtchForeground", {});
|
||||
}
|
||||
|
||||
// Handle libcwtch-go events (received via kotlin) and dispatch to the cwtchNotifier
|
||||
|
@ -187,4 +192,10 @@ class CwtchGomobile implements Cwtch {
|
|||
void LeaveGroup(String profileOnion, String groupHandle) {
|
||||
cwtchPlatform.invokeMethod("LeaveGroup", {"ProfileOnion": profileOnion, "handle": groupHandle});
|
||||
}
|
||||
|
||||
@override
|
||||
void UpdateMessageFlags(String profile, String handle, int index, int flags) {
|
||||
print("gomobile.dart UpdateMessageFlags " + index.toString());
|
||||
cwtchPlatform.invokeMethod("UpdateMessageFlags", {"profile": profile, "contact": handle, "index": index, "flags": flags});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/// Flutter icons MyFlutterApp
|
||||
/// Copyright (C) 2021 by original authors @ fluttericon.com, fontello.com
|
||||
/// Flutter icons CwtchIcons
|
||||
/// Copyright (C) 2021 by Open Privacy Research Society via fluttericon.com, fontello.com
|
||||
/// 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
|
||||
|
@ -102,8 +102,9 @@ class CwtchIcons {
|
|||
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 send_invite = IconData(0xe888, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData copy_address = IconData(0xe889, 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);
|
||||
}
|
||||
|
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "de",
|
||||
"acceptGroupBtn": "Annehmen",
|
||||
"acceptGroupInviteLabel": "Möchtest Du die Einladung annehmen",
|
||||
"acknowledgedLabel": "bestätigt",
|
||||
"addListItem": "Liste hinzufügen",
|
||||
"addListItemBtn": "Element hinzufügen",
|
||||
"addNewItem": "Ein neues Element zur Liste hinzufügen",
|
||||
"addNewProfileBtn": "Neues Profil hinzufügen",
|
||||
"addPeer": "Peer hinzufügen",
|
||||
"addPeerTab": "Einen Peer hinzufügen",
|
||||
"addProfileTitle": "Neues Profil hinzufügen",
|
||||
"addressLabel": "Adresse",
|
||||
"blockBtn": "Peer blockieren",
|
||||
"blocked": "Blockiert",
|
||||
"blockUnknownLabel": "Unbekannte Peers blockieren",
|
||||
"builddate": "Aufgebaut auf: %2",
|
||||
"bulletinsBtn": "Meldungen",
|
||||
"chatBtn": "Chat",
|
||||
"chatHistoryDefault": "",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "in die Zwischenablage kopiert",
|
||||
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
|
||||
"copyBtn": "Kopieren",
|
||||
"couldNotSendMsgError": "Nachricht konnte nicht gesendet werden",
|
||||
"createGroup": "Gruppe erstellen",
|
||||
"createGroupBtn": "Anlegen",
|
||||
"createGroupTab": "Eine Gruppe erstellen",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Gruppe Anlegen",
|
||||
"createProfileBtn": "Profil speichern",
|
||||
"currentPasswordLabel": "derzeitiges Passwort",
|
||||
"cwtchSettingsTitle": "Cwtch Einstellungen",
|
||||
"cycleCatsAndroid": "",
|
||||
"cycleCatsDesktop": "",
|
||||
"cycleColoursAndroid": "",
|
||||
"cycleColoursDesktop": "",
|
||||
"cycleMorphsAndroid": "",
|
||||
"cycleMorphsDesktop": "",
|
||||
"dateDaysAgo": "",
|
||||
"dateHoursAgo": "",
|
||||
"dateLastMonth": "",
|
||||
"dateLastYear": "",
|
||||
"dateMinutesAgo": "",
|
||||
"dateMonthsAgo": "",
|
||||
"dateNever": "",
|
||||
"dateRightNow": "",
|
||||
"dateWeeksAgo": "",
|
||||
"dateYearsAgo": "",
|
||||
"dateYesterday": "",
|
||||
"defaultGroupName": "Tolle Gruppe",
|
||||
"defaultProfileName": "Alice",
|
||||
"defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:",
|
||||
"deleteBtn": "Löschen",
|
||||
"deleteConfirmLabel": "Geben Sie LÖSCHEN zur Bestätigung ein",
|
||||
"deleteConfirmText": "LÖSCHEN",
|
||||
"deleteProfileBtn": "Profil löschen",
|
||||
"deleteProfileConfirmBtn": "Profil wirklich löschen",
|
||||
"descriptionBlockUnknownConnections": "",
|
||||
"descriptionExperiments": "",
|
||||
"descriptionExperimentsGroups": "",
|
||||
"displayNameLabel": "Angezeigter Name",
|
||||
"dmTooltip": "Klicken, um DM zu senden",
|
||||
"dontSavePeerHistory": "Peer-Verlauf löschen",
|
||||
"editProfile": "Profil bearbeiten",
|
||||
"editProfileTitle": "Profil bearbeiten",
|
||||
"enableGroups": "",
|
||||
"enterCurrentPasswordForDelete": "",
|
||||
"enterProfilePassword": "Geben Sie ein Passwort ein, um Ihre Profile anzuzeigen",
|
||||
"error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen",
|
||||
"experimentsEnabled": "Experimente aktiviert",
|
||||
"groupAddr": "Adresse",
|
||||
"groupName": "Gruppenname",
|
||||
"serverLabel": "Server",
|
||||
"groupNameLabel": "Gruppenname",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Einladung",
|
||||
"invitationLabel": "Einladung",
|
||||
"inviteBtn": "Einladen",
|
||||
"inviteToGroup": "",
|
||||
"inviteToGroupLabel": "In die Gruppe einladen",
|
||||
"joinGroup": "Gruppe beitreten",
|
||||
"joinGroupTab": "Einer Gruppe beitreten",
|
||||
"largeTextLabel": "Groß",
|
||||
"leaveGroup": "",
|
||||
"listsBtn": "Listen",
|
||||
"loadingTor": "Tor wird geladen...",
|
||||
"localeDe": "Deutsche",
|
||||
"localeEn": "",
|
||||
"localeEs": "",
|
||||
"localeFr": "",
|
||||
"localeIt": "",
|
||||
"localePt": "",
|
||||
"membershipDescription": "Unten steht eine Liste der Benutzer, die Nachrichten an die Gruppe gesendet haben. Möglicherweise enthält diese Benutzerzliste nicht alle, die Zugang zur Gruppe haben.",
|
||||
"networkStatusAttemptingTor": "Versuche, eine Verbindung mit dem Tor-Netzwerk herzustellen",
|
||||
"networkStatusConnecting": "Verbinde zu Netzwerk und Peers ...",
|
||||
"networkStatusDisconnected": "Vom Internet getrennt, überprüfen Sie Ihre Verbindung",
|
||||
"networkStatusOnline": "Online",
|
||||
"newBulletinLabel": "Neue Meldung",
|
||||
"newConnectionPaneTitle": "Neue Verbindung",
|
||||
"newGroupBtn": "Neue Gruppe anlegen",
|
||||
"newPassword": "",
|
||||
"newProfile": "Neues Profil",
|
||||
"noPasswordWarning": "Wenn für dieses Konto kein Passwort verwendet wird, bedeutet dies, dass alle lokal gespeicherten Daten nicht verschlüsselt werden.",
|
||||
"password": "Passwort",
|
||||
"password1Label": "Passwort",
|
||||
"password2Label": "Passwort erneut eingeben",
|
||||
"passwordChangeError": "Fehler beim Ändern des Passworts: Das Passwort wurde abgelehnt",
|
||||
"passwordErrorEmpty": "Passwort kann nicht leer sein",
|
||||
"passwordErrorMatch": "Passwörter stimmen nicht überein",
|
||||
"pasteAddressToAddContact": "Adresse hier hinzufügen, um einen Kontakt aufzunehmen",
|
||||
"peerAddress": "Adresse",
|
||||
"peerBlockedMessage": "Peer ist blockiert",
|
||||
"peerName": "Namen",
|
||||
"peerNotOnline": "",
|
||||
"peerOfflineMessage": "Peer ist offline, Nachrichten können derzeit nicht zugestellt werden",
|
||||
"pendingLabel": "Bestätigung ausstehend",
|
||||
"postNewBulletinLabel": "Neue Meldung veröffentlichen",
|
||||
"profileName": "Anzeigename",
|
||||
"defaultGroupName": "Tolle Gruppe",
|
||||
"createGroupBtn": "Anlegen",
|
||||
"profileOnionLabel": "Senden Sie diese Adresse an Peers, mit denen Sie sich verbinden möchten",
|
||||
"puzzleGameBtn": "Puzzlespiel",
|
||||
"radioNoPassword": "Unverschlüsselt (kein Passwort)",
|
||||
"radioUsePassword": "Passwort",
|
||||
"reallyLeaveThisGroupPrompt": "",
|
||||
"rejectGroupBtn": "Ablehnen",
|
||||
"saveBtn": "Speichern",
|
||||
"savePeerHistory": "Peer-Verlauf speichern",
|
||||
"savePeerHistoryDescription": "Legt fest, ob ein mit dem Peer verknüpfter Verlauf gelöscht werden soll oder nicht.",
|
||||
"saveProfileBtn": "Profil speichern",
|
||||
"search": "Suche...",
|
||||
"searchList": "",
|
||||
"copyBtn": "Kopieren",
|
||||
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
|
||||
"addPeerTab": "Einen Peer hinzufügen",
|
||||
"createGroupTab": "Eine Gruppe erstellen",
|
||||
"joinGroupTab": "Einer Gruppe beitreten",
|
||||
"peerAddress": "Adresse",
|
||||
"peerName": "Namen",
|
||||
"groupName": "Gruppenname",
|
||||
"server": "Server",
|
||||
"invitation": "Einladung",
|
||||
"groupAddr": "Adresse",
|
||||
"addPeer": "Peer hinzufügen",
|
||||
"createGroup": "Gruppe erstellen",
|
||||
"joinGroup": "Gruppe beitreten",
|
||||
"newBulletinLabel": "Neue Meldung",
|
||||
"postNewBulletinLabel": "Neue Meldung veröffentlichen",
|
||||
"titlePlaceholder": "Titel...",
|
||||
"pasteAddressToAddContact": "Adresse hier hinzufügen, um einen Kontakt aufzunehmen",
|
||||
"blocked": "Blockiert",
|
||||
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
|
||||
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
|
||||
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
|
||||
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
|
||||
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
|
||||
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
|
||||
"search": "Suche...",
|
||||
"invitationLabel": "Einladung",
|
||||
"serverInfo": "Server-Informationen",
|
||||
"serverConnectivityConnected": "Server verbunden",
|
||||
"serverConnectivityDisconnected": "Server getrennt",
|
||||
"serverInfo": "Server-Informationen",
|
||||
"serverLabel": "Server",
|
||||
"serverNotSynced": "",
|
||||
"serverSynced": "",
|
||||
"settingInterfaceZoom": "Zoomstufe",
|
||||
"settingLanguage": "Sprache",
|
||||
"settingTheme": "Thema",
|
||||
"smallTextLabel": "Klein",
|
||||
"successfullAddedContact": "",
|
||||
"themeDark": "Dunkel",
|
||||
"themeLight": "Licht",
|
||||
"titleManageContacts": "",
|
||||
"titleManageProfiles": "",
|
||||
"titleManageServers": "",
|
||||
"titlePlaceholder": "Titel...",
|
||||
"todoPlaceholder": "noch zu erledigen",
|
||||
"tooltipAddContact": "",
|
||||
"tooltipOpenSettings": "",
|
||||
"tooltipUnlockProfiles": "",
|
||||
"serverSynced": "Synced",
|
||||
"serverNotSynced": "Out of Sync",
|
||||
"viewServerInfo": "Server Info",
|
||||
"saveBtn": "speichern",
|
||||
"inviteToGroupLabel": "In die Gruppe einladen",
|
||||
"inviteBtn": "Einladen",
|
||||
"deleteBtn": "löschen",
|
||||
"update": "Update",
|
||||
"searchList": "Search List",
|
||||
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
|
||||
"addListItemBtn": "Element hinzufügen",
|
||||
"membershipDescription": "Unten steht eine Liste der Benutzer, die Nachrichten an die Gruppe gesendet haben. Möglicherweise enthält diese Benutzerzliste nicht alle, die Zugang zur Gruppe haben.",
|
||||
"dmTooltip": "Klicken, um DM zu senden",
|
||||
"couldNotSendMsgError": "Nachricht konnte nicht gesendet werden",
|
||||
"acknowledgedLabel": "bestätigt",
|
||||
"pendingLabel": "Bestätigung ausstehend",
|
||||
"peerBlockedMessage": "Peer ist blockiert",
|
||||
"peerOfflineMessage": "Peer ist offline, Nachrichten können derzeit nicht zugestellt werden",
|
||||
"copiedClipboardNotification": "in die Zwischenablage kopiert",
|
||||
"newGroupBtn": "Neue Gruppe anlegen",
|
||||
"acceptGroupInviteLabel": "Möchtest Du die Einladung annehmen",
|
||||
"acceptGroupBtn": "Annehmen",
|
||||
"rejectGroupBtn": "Ablehnen",
|
||||
"chatBtn": "Chat",
|
||||
"listsBtn": "Listen",
|
||||
"bulletinsBtn": "Meldungen",
|
||||
"puzzleGameBtn": "Puzzlespiel",
|
||||
"addressLabel": "Adresse",
|
||||
"displayNameLabel": "Angezeigter Name",
|
||||
"blockBtn": "Peer blockieren",
|
||||
"savePeerHistory": "Peer-Verlauf speichern",
|
||||
"savePeerHistoryDescription": "Legt fest, ob ein mit dem Peer verknüpfter Verlauf gelöscht werden soll oder nicht.",
|
||||
"dontSavePeerHistory": "Peer-Verlauf löschen",
|
||||
"unblockBtn": "Peer entblockieren",
|
||||
"unlock": "Entsperren",
|
||||
"update": "",
|
||||
"version": "Version %1",
|
||||
"versionBuilddate": "Version: %1 Aufgebaut auf: %2",
|
||||
"versionTor": "Version %1 mit tor %2",
|
||||
"viewGroupMembershipTooltip": "Gruppenmitgliedschaft anzeigen",
|
||||
"viewServerInfo": "",
|
||||
"yesLeave": "",
|
||||
"addProfileTitle": "Neues Profil hinzufügen",
|
||||
"editProfileTitle": "Profil bearbeiten",
|
||||
"profileName": "Anzeigename",
|
||||
"defaultProfileName": "Alice",
|
||||
"newProfile": "Neues Profil",
|
||||
"editProfile": "Profil bearbeiten",
|
||||
"radioUsePassword": "Passwort",
|
||||
"radioNoPassword": "Unverschlüsselt (kein Passwort)",
|
||||
"noPasswordWarning": "Wenn für dieses Konto kein Passwort verwendet wird, bedeutet dies, dass alle lokal gespeicherten Daten nicht verschlüsselt werden.",
|
||||
"yourDisplayName": "Ihr Anzeigename",
|
||||
"currentPasswordLabel": "derzeitiges Passwort",
|
||||
"password1Label": "Passwort",
|
||||
"password2Label": "Passwort erneut eingeben",
|
||||
"passwordErrorEmpty": "Passwort kann nicht leer sein",
|
||||
"createProfileBtn": "Profil speichern",
|
||||
"saveProfileBtn": "Profil speichern",
|
||||
"passwordErrorMatch": "Passwörter stimmen nicht überein",
|
||||
"passwordChangeError": "Fehler beim Ändern des Passworts: Das Passwort wurde abgelehnt",
|
||||
"deleteProfileBtn": "Profil löschen",
|
||||
"deleteConfirmLabel": "Geben Sie LÖSCHEN zur Bestätigung ein",
|
||||
"deleteProfileConfirmBtn": "Profil wirklich löschen",
|
||||
"deleteConfirmText": "LÖSCHEN",
|
||||
"addNewProfileBtn": "Neues Profil hinzufügen",
|
||||
"enterProfilePassword": "Geben Sie ein Passwort ein, um Ihre Profile anzuzeigen",
|
||||
"password": "Passwort",
|
||||
"error0ProfilesLoadedForPassword": "0 Profile mit diesem Passwort geladen",
|
||||
"yourProfiles": "Ihre Profile",
|
||||
"yourServers": "Ihre Server",
|
||||
"zoomLabel": "Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)"
|
||||
"unlock": "Entsperren",
|
||||
"cwtchSettingsTitle": "Cwtch Einstellungen",
|
||||
"versionBuilddate": "Version: %1 Aufgebaut auf: %2",
|
||||
"zoomLabel": "Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)",
|
||||
"blockUnknownLabel": "Unbekannte Peers blockieren",
|
||||
"settingLanguage": "Sprache",
|
||||
"localeEn": "English",
|
||||
"localeFr": "Frances",
|
||||
"localePt": "Portuguesa",
|
||||
"localeDe": "Deutsche",
|
||||
"settingInterfaceZoom": "Zoomstufe",
|
||||
"largeTextLabel": "Groß",
|
||||
"settingTheme": "Thema",
|
||||
"themeLight": "Licht",
|
||||
"themeDark": "Dunkel",
|
||||
"experimentsEnabled": "Experimente aktiviert",
|
||||
"versionTor": "Version %1 mit tor %2",
|
||||
"version": "Version %1",
|
||||
"builddate": "Aufgebaut auf: %2",
|
||||
"defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:",
|
||||
"smallTextLabel": "Klein",
|
||||
"loadingTor": "Tor wird geladen...",
|
||||
"viewGroupMembershipTooltip": "Gruppenmitgliedschaft anzeigen",
|
||||
"networkStatusDisconnected": "Vom Internet getrennt, überprüfen Sie Ihre Verbindung",
|
||||
"networkStatusAttemptingTor": "Versuche, eine Verbindung mit dem Tor-Netzwerk herzustellen",
|
||||
"networkStatusConnecting": "Verbinde zu Netzwerk und Peers ...",
|
||||
"networkStatusOnline": "Online",
|
||||
"newConnectionPaneTitle": "Neue Verbindung",
|
||||
"addListItem": "Liste hinzufügen",
|
||||
"addNewItem": "Ein neues Element zur Liste hinzufügen",
|
||||
"todoPlaceholder": "noch zu erledigen",
|
||||
"localeEs": "Espanol",
|
||||
"localeIt": "Italiana",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "en",
|
||||
"acceptGroupBtn": "Accept",
|
||||
"acceptGroupInviteLabel": "Do you want to accept the invitation to",
|
||||
"acknowledgedLabel": "Acknowledged",
|
||||
"addListItem": "Add a New List Item",
|
||||
"addListItemBtn": "Add Item",
|
||||
"addNewItem": "Add a new item to the list",
|
||||
"addNewProfileBtn": "Add new profile",
|
||||
"addPeer": "Add Peer",
|
||||
"addPeerTab": "Add a peer",
|
||||
"addProfileTitle": "Add new profile",
|
||||
"addressLabel": "Address",
|
||||
"blockBtn": "Block Peer",
|
||||
"blocked": "Blocked",
|
||||
"blockUnknownLabel": "Block Unknown Peers",
|
||||
"builddate": "Built on: %2",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"chatBtn": "Chat",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"copiedClipboardNotification": "Copied to clipboard",
|
||||
"copiedToClipboardNotification": "Copied to Clipboard",
|
||||
"copyBtn": "Copy",
|
||||
"couldNotSendMsgError": "Could not send this message",
|
||||
"createGroup": "Create group",
|
||||
"createGroupBtn": "Create",
|
||||
"createGroupTab": "Create a group",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Create Group",
|
||||
"createProfileBtn": "Create Profile",
|
||||
"currentPasswordLabel": "Current Password",
|
||||
"cwtchSettingsTitle": "Cwtch Settings",
|
||||
"cycleCatsAndroid": "Click to cycle category.\\nLong-press to reset.",
|
||||
"cycleCatsDesktop": "Click to cycle category.\\nRight-click to reset.",
|
||||
"cycleColoursAndroid": "Click to cycle colours.\\nLong-press to reset.",
|
||||
"cycleColoursDesktop": "Click to cycle colours.\\nRight-click to reset.",
|
||||
"cycleMorphsAndroid": "Click to cycle morphs.\\nLong-press to reset.",
|
||||
"cycleMorphsDesktop": "Click to cycle morphs.\\nRight-click to reset.",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"dateNever": "Never",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateYesterday": "Yesterday",
|
||||
"defaultGroupName": "Awesome Group",
|
||||
"defaultProfileName": "Alice",
|
||||
"defaultScalingText": "Default size text (scale factor:",
|
||||
"deleteBtn": "Delete",
|
||||
"deleteConfirmLabel": "Type DELETE to confirm",
|
||||
"deleteConfirmText": "DELETE",
|
||||
"deleteProfileBtn": "Delete Profile",
|
||||
"deleteProfileConfirmBtn": "Really Delete Profile",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"displayNameLabel": "Display Name",
|
||||
"dmTooltip": "Click to DM",
|
||||
"dontSavePeerHistory": "Delete Peer History",
|
||||
"editProfile": "Edit Profille",
|
||||
"editProfileTitle": "Edit Profile",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"enterProfilePassword": "Enter a password to view your profiles",
|
||||
"error0ProfilesLoadedForPassword": "0 profiles loaded with that password",
|
||||
"experimentsEnabled": "Enable Experiments",
|
||||
"groupAddr": "Address",
|
||||
"groupName": "Group name",
|
||||
"serverLabel": "Server",
|
||||
"groupNameLabel": "Group Name",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"invitation": "Invitation",
|
||||
"invitationLabel": "Invitation",
|
||||
"inviteBtn": "Invite",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"inviteToGroupLabel": "Invite to group",
|
||||
"joinGroup": "Join group",
|
||||
"joinGroupTab": "Join a group",
|
||||
"largeTextLabel": "Large",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"listsBtn": "Lists",
|
||||
"loadingTor": "Loading tor...",
|
||||
"localeDe": "Deutsche",
|
||||
"localeEn": "English",
|
||||
"localeEs": "Espanol",
|
||||
"localeFr": "Frances",
|
||||
"localeIt": "Italiana",
|
||||
"localePt": "Portuguesa",
|
||||
"membershipDescription": "Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.",
|
||||
"networkStatusAttemptingTor": "Attempting to connect to Tor network",
|
||||
"networkStatusConnecting": "Connecting to network and peers...",
|
||||
"networkStatusDisconnected": "Disconnected from the internet, check your connection",
|
||||
"networkStatusOnline": "Online",
|
||||
"newBulletinLabel": "New Bulletin",
|
||||
"newConnectionPaneTitle": "New Connection",
|
||||
"newGroupBtn": "Create new group",
|
||||
"newPassword": "New Password",
|
||||
"newProfile": "New Profile",
|
||||
"noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted",
|
||||
"password": "Password",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reenter password",
|
||||
"passwordChangeError": "Error changing password: Supplied password rejected",
|
||||
"passwordErrorEmpty": "Password cannot be empty",
|
||||
"passwordErrorMatch": "Passwords do not match",
|
||||
"pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation",
|
||||
"peerAddress": "Address",
|
||||
"peerBlockedMessage": "Peer is blocked",
|
||||
"peerName": "Name",
|
||||
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
|
||||
"peerOfflineMessage": "Peer is offline, messages can't be delivered right now",
|
||||
"pendingLabel": "Pending",
|
||||
"postNewBulletinLabel": "Post new bulletin",
|
||||
"profileName": "Display name",
|
||||
"defaultGroupName": "Awesome Group",
|
||||
"createGroupBtn": "Create",
|
||||
"profileOnionLabel": "Send this address to peers you want to connect with",
|
||||
"puzzleGameBtn": "Puzzle Game",
|
||||
"radioNoPassword": "Unencrypted (No password)",
|
||||
"radioUsePassword": "Password",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"rejectGroupBtn": "Reject",
|
||||
"saveBtn": "Save",
|
||||
"savePeerHistory": "Save Peer History",
|
||||
"savePeerHistoryDescription": "Determines whether or not to delete any history associated with the peer.",
|
||||
"saveProfileBtn": "Save Profile",
|
||||
"search": "Search...",
|
||||
"searchList": "Search List",
|
||||
"copyBtn": "Copy",
|
||||
"copiedToClipboardNotification": "Copied to Clipboard",
|
||||
"addPeerTab": "Add a peer",
|
||||
"createGroupTab": "Create a group",
|
||||
"joinGroupTab": "Join a group",
|
||||
"peerAddress": "Address",
|
||||
"peerName": "Name",
|
||||
"groupName": "Group name",
|
||||
"server": "Server",
|
||||
"invitation": "Invitation",
|
||||
"groupAddr": "Address",
|
||||
"addPeer": "Add Peer",
|
||||
"createGroup": "Create group",
|
||||
"joinGroup": "Join group",
|
||||
"newBulletinLabel": "New Bulletin",
|
||||
"postNewBulletinLabel": "Post new bulletin",
|
||||
"titlePlaceholder": "title...",
|
||||
"pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation",
|
||||
"blocked": "Blocked",
|
||||
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
|
||||
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
|
||||
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
|
||||
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
|
||||
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
|
||||
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
|
||||
"search": "Search...",
|
||||
"invitationLabel": "Invitation",
|
||||
"serverInfo": "Server Information",
|
||||
"serverConnectivityConnected": "Server Connected",
|
||||
"serverConnectivityDisconnected": "Server Disconnected",
|
||||
"serverInfo": "Server Information",
|
||||
"serverLabel": "Server",
|
||||
"serverNotSynced": "Out of Sync",
|
||||
"serverSynced": "Synced",
|
||||
"settingInterfaceZoom": "Zoom level",
|
||||
"settingLanguage": "Language",
|
||||
"settingTheme": "Theme",
|
||||
"smallTextLabel": "Small",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"themeDark": "Dark",
|
||||
"themeLight": "Light",
|
||||
"titleManageContacts": "Conversations",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"titlePlaceholder": "title...",
|
||||
"todoPlaceholder": "Todo...",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"unblockBtn": "Unblock Peer",
|
||||
"unlock": "Unlock",
|
||||
"update": "Update",
|
||||
"version": "Version %1",
|
||||
"versionBuilddate": "Version: %1 Built on: %2",
|
||||
"versionTor": "Version %1 with tor %2",
|
||||
"viewGroupMembershipTooltip": "View Group Membership",
|
||||
"serverNotSynced": "Out of Sync",
|
||||
"viewServerInfo": "Server Info",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"saveBtn": "Save",
|
||||
"inviteToGroupLabel": "Invite to group",
|
||||
"inviteBtn": "Invite",
|
||||
"deleteBtn": "Delete",
|
||||
"update": "Update",
|
||||
"searchList": "Search List",
|
||||
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
|
||||
"addListItemBtn": "Add Item",
|
||||
"membershipDescription": "Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.",
|
||||
"dmTooltip": "Click to DM",
|
||||
"couldNotSendMsgError": "Could not send this message",
|
||||
"acknowledgedLabel": "Acknowledged",
|
||||
"pendingLabel": "Pending",
|
||||
"peerBlockedMessage": "Peer is blocked",
|
||||
"peerOfflineMessage": "Peer is offline, messages can't be delivered right now",
|
||||
"copiedClipboardNotification": "Copied to clipboard",
|
||||
"newGroupBtn": "Create new group",
|
||||
"acceptGroupInviteLabel": "Do you want to accept the invitation to",
|
||||
"acceptGroupBtn": "Accept",
|
||||
"rejectGroupBtn": "Reject",
|
||||
"chatBtn": "Chat",
|
||||
"listsBtn": "Lists",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"puzzleGameBtn": "Puzzle Game",
|
||||
"addressLabel": "Address",
|
||||
"displayNameLabel": "Display Name",
|
||||
"blockBtn": "Block Peer",
|
||||
"savePeerHistory": "Save Peer History",
|
||||
"savePeerHistoryDescription": "Determines whether or not to delete any history associated with the peer.",
|
||||
"dontSavePeerHistory": "Delete Peer History",
|
||||
"unblockBtn": "Unblock Peer",
|
||||
"addProfileTitle": "Add new profile",
|
||||
"editProfileTitle": "Edit Profile",
|
||||
"profileName": "Display name",
|
||||
"defaultProfileName": "Alice",
|
||||
"newProfile": "New Profile",
|
||||
"editProfile": "Edit Profille",
|
||||
"radioUsePassword": "Password",
|
||||
"radioNoPassword": "Unencrypted (No password)",
|
||||
"noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted",
|
||||
"yourDisplayName": "Your Display Name",
|
||||
"currentPasswordLabel": "Current Password",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reenter password",
|
||||
"passwordErrorEmpty": "Password cannot be empty",
|
||||
"createProfileBtn": "Create Profile",
|
||||
"saveProfileBtn": "Save Profile",
|
||||
"passwordErrorMatch": "Passwords do not match",
|
||||
"passwordChangeError": "Error changing password: Supplied password rejected",
|
||||
"deleteProfileBtn": "Delete Profile",
|
||||
"deleteConfirmLabel": "Type DELETE to confirm",
|
||||
"deleteProfileConfirmBtn": "Really Delete Profile",
|
||||
"deleteConfirmText": "DELETE",
|
||||
"addNewProfileBtn": "Add new profile",
|
||||
"enterProfilePassword": "Enter a password to view your profiles",
|
||||
"password": "Password",
|
||||
"error0ProfilesLoadedForPassword": "0 profiles loaded with that password",
|
||||
"yourProfiles": "Your Profiles",
|
||||
"yourServers": "Your Servers",
|
||||
"zoomLabel": "Interface zoom (mostly affects text and button sizes)"
|
||||
"unlock": "Unlock",
|
||||
"cwtchSettingsTitle": "Cwtch Settings",
|
||||
"versionBuilddate": "Version: %1 Built on: %2",
|
||||
"zoomLabel": "Interface zoom (mostly affects text and button sizes)",
|
||||
"blockUnknownLabel": "Block Unknown Peers",
|
||||
"settingLanguage": "Language",
|
||||
"localeEn": "English",
|
||||
"localeFr": "Frances",
|
||||
"localePt": "Portuguesa",
|
||||
"localeDe": "Deutsche",
|
||||
"settingInterfaceZoom": "Zoom level",
|
||||
"largeTextLabel": "Large",
|
||||
"settingTheme": "Theme",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"experimentsEnabled": "Enable Experiments",
|
||||
"versionTor": "Version %1 with tor %2",
|
||||
"version": "Version %1",
|
||||
"builddate": "Built on: %2",
|
||||
"defaultScalingText": "Default size text (scale factor:",
|
||||
"smallTextLabel": "Small",
|
||||
"loadingTor": "Loading tor...",
|
||||
"viewGroupMembershipTooltip": "View Group Membership",
|
||||
"networkStatusDisconnected": "Disconnected from the internet, check your connection",
|
||||
"networkStatusAttemptingTor": "Attempting to connect to Tor network",
|
||||
"networkStatusConnecting": "Connecting to network and peers...",
|
||||
"networkStatusOnline": "Online",
|
||||
"newConnectionPaneTitle": "New Connection",
|
||||
"addListItem": "Add a New List Item",
|
||||
"addNewItem": "Add a new item to the list",
|
||||
"todoPlaceholder": "Todo...",
|
||||
"localeEs": "Espanol",
|
||||
"localeIt": "Italiana",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "es",
|
||||
"acceptGroupBtn": "Aceptar",
|
||||
"acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ",
|
||||
"acknowledgedLabel": "Reconocido",
|
||||
"addListItem": "Añadir un nuevo elemento a la lista",
|
||||
"addListItemBtn": "Agregar artículo",
|
||||
"addNewItem": "Añadir un nuevo elemento a la lista",
|
||||
"addNewProfileBtn": "Agregar nuevo perfil",
|
||||
"addPeer": "Agregar Contacto",
|
||||
"addPeerTab": "Agregar Contacto",
|
||||
"addProfileTitle": "Agregar nuevo perfil",
|
||||
"addressLabel": "Dirección",
|
||||
"blockBtn": "Bloquear contacto",
|
||||
"blocked": "Bloqueado",
|
||||
"blockUnknownLabel": "Bloquear conexiones desconocidas",
|
||||
"builddate": "Basado en: %2",
|
||||
"bulletinsBtn": "Boletines",
|
||||
"chatBtn": "Chat",
|
||||
"chatHistoryDefault": "",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiado al portapapeles",
|
||||
"copiedToClipboardNotification": "Copiado al portapapeles",
|
||||
"copyBtn": "Copiar",
|
||||
"couldNotSendMsgError": "No se pudo enviar este mensaje",
|
||||
"createGroup": "Crear perfil",
|
||||
"createGroupBtn": "Crear",
|
||||
"createGroupTab": "Crear un grupo",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Crear un grupo",
|
||||
"createProfileBtn": "Crear perfil",
|
||||
"currentPasswordLabel": "Contraseña actual",
|
||||
"cwtchSettingsTitle": "Configuración de Cwtch",
|
||||
"serverLabel": "Servidor",
|
||||
"groupNameLabel": "Nombre del grupo",
|
||||
"defaultGroupName": "El Grupo Asombroso",
|
||||
"createGroupBtn": "Crear",
|
||||
"profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte",
|
||||
"copyBtn": "Copiar",
|
||||
"copiedToClipboardNotification": "Copiado al portapapeles",
|
||||
"addPeerTab": "Agregar Contacto",
|
||||
"createGroupTab": "Crear un grupo",
|
||||
"joinGroupTab": "Únete a un grupo",
|
||||
"peerAddress": "Dirección",
|
||||
"peerName": "Nombre",
|
||||
"groupName": "Nombre del grupo",
|
||||
"server": "Servidor",
|
||||
"invitation": "Invitación",
|
||||
"groupAddr": "Dirección",
|
||||
"addPeer": "Agregar Contacto",
|
||||
"createGroup": "Crear perfil",
|
||||
"joinGroup": "Únete al grupo",
|
||||
"newBulletinLabel": "Nuevo Boletín",
|
||||
"postNewBulletinLabel": "Publicar nuevo boletín",
|
||||
"titlePlaceholder": "título...",
|
||||
"pasteAddressToAddContact": "...pegar una dirección aquí para añadir contacto...",
|
||||
"blocked": "Bloqueado",
|
||||
"cycleCatsAndroid": "Click para cambiar categoría. Mantenga pulsado para reiniciar.",
|
||||
"cycleCatsDesktop": "Click para cambiar categoría. Click derecho para reiniciar.",
|
||||
"cycleColoursAndroid": "Click para cambiar colores. Mantenga pulsado para reiniciar.",
|
||||
"cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.",
|
||||
"cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.",
|
||||
"cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.",
|
||||
"dateDaysAgo": "",
|
||||
"dateHoursAgo": "",
|
||||
"dateLastMonth": "",
|
||||
"dateLastYear": "",
|
||||
"dateMinutesAgo": "",
|
||||
"dateMonthsAgo": "",
|
||||
"dateNever": "",
|
||||
"dateRightNow": "",
|
||||
"dateWeeksAgo": "",
|
||||
"dateYearsAgo": "",
|
||||
"dateYesterday": "",
|
||||
"defaultGroupName": "El Grupo Asombroso",
|
||||
"defaultProfileName": "Alicia",
|
||||
"defaultScalingText": "Tamaño predeterminado de texto (factor de escala:",
|
||||
"deleteBtn": "Eliminar",
|
||||
"deleteConfirmLabel": "Escribe ELIMINAR para confirmar",
|
||||
"deleteConfirmText": "ELIMINAR",
|
||||
"deleteProfileBtn": "Eliminar Perfil",
|
||||
"deleteProfileConfirmBtn": "Confirmar eliminar perfil",
|
||||
"descriptionBlockUnknownConnections": "",
|
||||
"descriptionExperiments": "",
|
||||
"descriptionExperimentsGroups": "",
|
||||
"displayNameLabel": "Nombre de Usuario",
|
||||
"dmTooltip": "Haz clic para enviar mensaje directo",
|
||||
"dontSavePeerHistory": "Eliminar historial de contacto",
|
||||
"editProfile": "Editar perfil",
|
||||
"editProfileTitle": "Editar perfil",
|
||||
"enableGroups": "",
|
||||
"enterCurrentPasswordForDelete": "",
|
||||
"enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles",
|
||||
"error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña",
|
||||
"experimentsEnabled": "Experimentos habilitados",
|
||||
"groupAddr": "Dirección",
|
||||
"groupName": "Nombre del grupo",
|
||||
"groupNameLabel": "Nombre del grupo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Invitación",
|
||||
"invitationLabel": "Invitación",
|
||||
"inviteBtn": "Invitar",
|
||||
"inviteToGroup": "",
|
||||
"inviteToGroupLabel": "Invitar al grupo",
|
||||
"joinGroup": "Únete al grupo",
|
||||
"joinGroupTab": "Únete a un grupo",
|
||||
"largeTextLabel": "Grande",
|
||||
"leaveGroup": "",
|
||||
"listsBtn": "Listas",
|
||||
"loadingTor": "Cargando tor...",
|
||||
"localeDe": "Alemán",
|
||||
"localeEn": "Inglés",
|
||||
"localeEs": "Español",
|
||||
"localeFr": "Francés",
|
||||
"localeIt": "Italiano",
|
||||
"localePt": "Portugués",
|
||||
"membershipDescription": "La lista a continuación solo muestra los miembros que han enviado mensajes al grupo, no incluye a todos los usuarios dentro del grupo",
|
||||
"networkStatusAttemptingTor": "Intentando conectarse a la red Tor",
|
||||
"networkStatusConnecting": "Conectando a la red y a los contactos...",
|
||||
"networkStatusDisconnected": "Sin conexión, comprueba tu conexión",
|
||||
"networkStatusOnline": "En línea",
|
||||
"newBulletinLabel": "Nuevo Boletín",
|
||||
"newConnectionPaneTitle": "Nueva conexión",
|
||||
"newGroupBtn": "Crear un nuevo grupo de chat",
|
||||
"newPassword": "",
|
||||
"newProfile": "Nuevo perfil",
|
||||
"noPasswordWarning": "No usar una contraseña para esta cuenta significa que los datos almacenados localmente no serán encriptados",
|
||||
"password": "Contraseña",
|
||||
"password1Label": "Contraseña",
|
||||
"password2Label": "Vuelve a ingresar tu contraseña",
|
||||
"passwordChangeError": "Hubo un error cambiando tu contraseña: la contraseña ingresada fue rechazada",
|
||||
"passwordErrorEmpty": "El campo de contraseña no puede estar vacío",
|
||||
"passwordErrorMatch": "Las contraseñas no coinciden",
|
||||
"pasteAddressToAddContact": "...pegar una dirección aquí para añadir contacto...",
|
||||
"peerAddress": "Dirección",
|
||||
"peerBlockedMessage": "Contacto bloqueado",
|
||||
"peerName": "Nombre",
|
||||
"peerNotOnline": "Este contacto no está en línea, la aplicación no puede ser usada en este momento",
|
||||
"peerOfflineMessage": "Este contacto no está en línea, los mensajes no pueden ser entregados en este momento",
|
||||
"pendingLabel": "Pendiente",
|
||||
"postNewBulletinLabel": "Publicar nuevo boletín",
|
||||
"profileName": "Nombre de Usuario",
|
||||
"profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte",
|
||||
"puzzleGameBtn": "Juego de rompecabezas",
|
||||
"radioNoPassword": "Sin cifrado (sin contraseña)",
|
||||
"radioUsePassword": "Contraseña",
|
||||
"reallyLeaveThisGroupPrompt": "",
|
||||
"rejectGroupBtn": "Rechazar",
|
||||
"saveBtn": "Guardar",
|
||||
"savePeerHistory": "Guardar el historial con contacto",
|
||||
"savePeerHistoryDescription": "Determina si eliminar o no el historial asociado con el contacto.",
|
||||
"saveProfileBtn": "Guardar perfil",
|
||||
"cycleColoursAndroid": "Click para cambiar colores. Mantenga pulsado para reiniciar.",
|
||||
"cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.",
|
||||
"search": "Búsqueda...",
|
||||
"searchList": "Buscar en la lista",
|
||||
"server": "Servidor",
|
||||
"invitationLabel": "Invitación",
|
||||
"serverInfo": "Información del servidor",
|
||||
"serverConnectivityConnected": "Servidor conectado",
|
||||
"serverConnectivityDisconnected": "Servidor desconectado",
|
||||
"serverInfo": "Información del servidor",
|
||||
"serverLabel": "Servidor",
|
||||
"serverNotSynced": "Fuera de sincronización con el servidor",
|
||||
"serverSynced": "Sincronizado",
|
||||
"settingInterfaceZoom": "Nivel de zoom",
|
||||
"settingLanguage": "Idioma",
|
||||
"settingTheme": "Tema",
|
||||
"smallTextLabel": "Pequeño",
|
||||
"successfullAddedContact": "",
|
||||
"themeDark": "Oscuro",
|
||||
"themeLight": "Claro",
|
||||
"titleManageContacts": "",
|
||||
"titleManageProfiles": "",
|
||||
"titleManageServers": "",
|
||||
"titlePlaceholder": "título...",
|
||||
"todoPlaceholder": "Por hacer...",
|
||||
"tooltipAddContact": "",
|
||||
"tooltipOpenSettings": "",
|
||||
"tooltipUnlockProfiles": "",
|
||||
"unblockBtn": "Desbloquear contacto",
|
||||
"unlock": "Desbloquear",
|
||||
"update": "Actualizar",
|
||||
"version": "Versión %1",
|
||||
"versionBuilddate": "Versión: %1 Basado en %2",
|
||||
"versionTor": "Versión %1 con tor %2",
|
||||
"viewGroupMembershipTooltip": "Ver membresía del grupo",
|
||||
"serverNotSynced": "Fuera de sincronización con el servidor",
|
||||
"viewServerInfo": "Información del servidor",
|
||||
"yesLeave": "",
|
||||
"saveBtn": "Guardar",
|
||||
"inviteToGroupLabel": "Invitar al grupo",
|
||||
"inviteBtn": "Invitar",
|
||||
"deleteBtn": "Eliminar",
|
||||
"update": "Actualizar",
|
||||
"searchList": "Buscar en la lista",
|
||||
"peerNotOnline": "Este contacto no está en línea, la aplicación no puede ser usada en este momento",
|
||||
"addListItemBtn": "Agregar artículo",
|
||||
"membershipDescription": "La lista a continuación solo muestra los miembros que han enviado mensajes al grupo, no incluye a todos los usuarios dentro del grupo",
|
||||
"dmTooltip": "Haz clic para enviar mensaje directo",
|
||||
"couldNotSendMsgError": "No se pudo enviar este mensaje",
|
||||
"acknowledgedLabel": "Reconocido",
|
||||
"pendingLabel": "Pendiente",
|
||||
"peerBlockedMessage": "Contacto bloqueado",
|
||||
"peerOfflineMessage": "Este contacto no está en línea, los mensajes no pueden ser entregados en este momento",
|
||||
"copiedClipboardNotification": "Copiado al portapapeles",
|
||||
"newGroupBtn": "Crear un nuevo grupo de chat",
|
||||
"acceptGroupInviteLabel": "¿Quieres aceptar la invitación a ",
|
||||
"acceptGroupBtn": "Aceptar",
|
||||
"rejectGroupBtn": "Rechazar",
|
||||
"chatBtn": "Chat",
|
||||
"listsBtn": "Listas",
|
||||
"bulletinsBtn": "Boletines",
|
||||
"puzzleGameBtn": "Juego de rompecabezas",
|
||||
"addressLabel": "Dirección",
|
||||
"displayNameLabel": "Nombre de Usuario",
|
||||
"blockBtn": "Bloquear contacto",
|
||||
"savePeerHistory": "Guardar el historial con contacto",
|
||||
"savePeerHistoryDescription": "Determina si eliminar o no el historial asociado con el contacto.",
|
||||
"dontSavePeerHistory": "Eliminar historial de contacto",
|
||||
"unblockBtn": "Desbloquear contacto",
|
||||
"addProfileTitle": "Agregar nuevo perfil",
|
||||
"editProfileTitle": "Editar perfil",
|
||||
"profileName": "Nombre de Usuario",
|
||||
"defaultProfileName": "Alicia",
|
||||
"newProfile": "Nuevo perfil",
|
||||
"editProfile": "Editar perfil",
|
||||
"radioUsePassword": "Contraseña",
|
||||
"radioNoPassword": "Sin cifrado (sin contraseña)",
|
||||
"noPasswordWarning": "No usar una contraseña para esta cuenta significa que los datos almacenados localmente no serán encriptados",
|
||||
"yourDisplayName": "Tu nombre de usuario",
|
||||
"currentPasswordLabel": "Contraseña actual",
|
||||
"password1Label": "Contraseña",
|
||||
"password2Label": "Vuelve a ingresar tu contraseña",
|
||||
"passwordErrorEmpty": "El campo de contraseña no puede estar vacío",
|
||||
"createProfileBtn": "Crear perfil",
|
||||
"saveProfileBtn": "Guardar perfil",
|
||||
"passwordErrorMatch": "Las contraseñas no coinciden",
|
||||
"passwordChangeError": "Hubo un error cambiando tu contraseña: la contraseña ingresada fue rechazada",
|
||||
"deleteProfileBtn": "Eliminar Perfil",
|
||||
"deleteConfirmLabel": "Escribe ELIMINAR para confirmar",
|
||||
"deleteProfileConfirmBtn": "Confirmar eliminar perfil",
|
||||
"deleteConfirmText": "ELIMINAR",
|
||||
"addNewProfileBtn": "Agregar nuevo perfil",
|
||||
"enterProfilePassword": "Ingresa tu contraseña para ver tus perfiles",
|
||||
"password": "Contraseña",
|
||||
"error0ProfilesLoadedForPassword": "0 perfiles cargados con esa contraseña",
|
||||
"yourProfiles": "Tus perfiles",
|
||||
"yourServers": "Tus servidores",
|
||||
"zoomLabel": "Zoom de la interfaz (afecta principalmente el tamaño del texto y de los botones)"
|
||||
"unlock": "Desbloquear",
|
||||
"cwtchSettingsTitle": "Configuración de Cwtch",
|
||||
"versionBuilddate": "Versión: %1 Basado en %2",
|
||||
"zoomLabel": "Zoom de la interfaz (afecta principalmente el tamaño del texto y de los botones)",
|
||||
"blockUnknownLabel": "Bloquear conexiones desconocidas",
|
||||
"settingLanguage": "Idioma",
|
||||
"localeEn": "Inglés",
|
||||
"localeFr": "Francés",
|
||||
"localePt": "Portugués",
|
||||
"localeDe": "Alemán",
|
||||
"settingInterfaceZoom": "Nivel de zoom",
|
||||
"largeTextLabel": "Grande",
|
||||
"settingTheme": "Tema",
|
||||
"themeLight": "Claro",
|
||||
"themeDark": "Oscuro",
|
||||
"experimentsEnabled": "Experimentos habilitados",
|
||||
"versionTor": "Versión %1 con tor %2",
|
||||
"version": "Versión %1",
|
||||
"builddate": "Basado en: %2",
|
||||
"defaultScalingText": "Tamaño predeterminado de texto (factor de escala:",
|
||||
"smallTextLabel": "Pequeño",
|
||||
"loadingTor": "Cargando tor...",
|
||||
"viewGroupMembershipTooltip": "Ver membresía del grupo",
|
||||
"networkStatusDisconnected": "Sin conexión, comprueba tu conexión",
|
||||
"networkStatusAttemptingTor": "Intentando conectarse a la red Tor",
|
||||
"networkStatusConnecting": "Conectando a la red y a los contactos...",
|
||||
"networkStatusOnline": "En línea",
|
||||
"newConnectionPaneTitle": "Nueva conexión",
|
||||
"addListItem": "Añadir un nuevo elemento a la lista",
|
||||
"addNewItem": "Añadir un nuevo elemento a la lista",
|
||||
"todoPlaceholder": "Por hacer...",
|
||||
"localeEs": "Español",
|
||||
"localeIt": "Italiano",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "fr",
|
||||
"acceptGroupBtn": "Accepter",
|
||||
"acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe",
|
||||
"acknowledgedLabel": "Confirmé",
|
||||
"addListItem": "Ajouter un nouvel élément",
|
||||
"addListItemBtn": "",
|
||||
"addNewItem": "Ajouter un nouvel élément à la liste",
|
||||
"addNewProfileBtn": "",
|
||||
"addPeer": "",
|
||||
"addPeerTab": "",
|
||||
"addProfileTitle": "",
|
||||
"addressLabel": "Adresse",
|
||||
"blockBtn": "",
|
||||
"blocked": "",
|
||||
"blockUnknownLabel": "",
|
||||
"builddate": "",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"chatBtn": "Discuter",
|
||||
"chatHistoryDefault": "",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copié dans le presse-papier",
|
||||
"copiedToClipboardNotification": "Copié dans le presse-papier",
|
||||
"copyBtn": "Copier",
|
||||
"couldNotSendMsgError": "Impossible d'envoyer ce message",
|
||||
"createGroup": "",
|
||||
"createGroupBtn": "Créer",
|
||||
"createGroupTab": "",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Créer un groupe",
|
||||
"createProfileBtn": "",
|
||||
"currentPasswordLabel": "",
|
||||
"cwtchSettingsTitle": "Préférences Cwtch",
|
||||
"cycleCatsAndroid": "",
|
||||
"cycleCatsDesktop": "",
|
||||
"cycleColoursAndroid": "",
|
||||
"cycleColoursDesktop": "",
|
||||
"cycleMorphsAndroid": "",
|
||||
"cycleMorphsDesktop": "",
|
||||
"dateDaysAgo": "",
|
||||
"dateHoursAgo": "",
|
||||
"dateLastMonth": "",
|
||||
"dateLastYear": "",
|
||||
"dateMinutesAgo": "",
|
||||
"dateMonthsAgo": "",
|
||||
"dateNever": "",
|
||||
"dateRightNow": "",
|
||||
"dateWeeksAgo": "",
|
||||
"dateYearsAgo": "",
|
||||
"dateYesterday": "",
|
||||
"defaultGroupName": "Un super groupe",
|
||||
"defaultProfileName": "",
|
||||
"defaultScalingText": "Taille par défaut du texte (échelle:",
|
||||
"deleteBtn": "Effacer",
|
||||
"deleteConfirmLabel": "",
|
||||
"deleteConfirmText": "",
|
||||
"deleteProfileBtn": "",
|
||||
"deleteProfileConfirmBtn": "",
|
||||
"descriptionBlockUnknownConnections": "",
|
||||
"descriptionExperiments": "",
|
||||
"descriptionExperimentsGroups": "",
|
||||
"displayNameLabel": "Pseudo",
|
||||
"dmTooltip": "Envoyer un message privé",
|
||||
"dontSavePeerHistory": "",
|
||||
"editProfile": "",
|
||||
"editProfileTitle": "",
|
||||
"enableGroups": "",
|
||||
"enterCurrentPasswordForDelete": "",
|
||||
"enterProfilePassword": "",
|
||||
"error0ProfilesLoadedForPassword": "",
|
||||
"experimentsEnabled": "",
|
||||
"groupAddr": "",
|
||||
"groupName": "",
|
||||
"groupNameLabel": "Nom du groupe",
|
||||
"invalidImportString": "",
|
||||
"invitation": "",
|
||||
"invitationLabel": "Invitation",
|
||||
"inviteBtn": "Invitation",
|
||||
"inviteToGroup": "",
|
||||
"inviteToGroupLabel": "Inviter quelqu'un",
|
||||
"joinGroup": "",
|
||||
"joinGroupTab": "",
|
||||
"largeTextLabel": "Large",
|
||||
"leaveGroup": "",
|
||||
"listsBtn": "Listes",
|
||||
"loadingTor": "",
|
||||
"localeDe": "",
|
||||
"localeEn": "",
|
||||
"localeEs": "",
|
||||
"localeFr": "",
|
||||
"localeIt": "",
|
||||
"localePt": "",
|
||||
"membershipDescription": "Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être representatives de l'ensemble des membres du groupe.",
|
||||
"networkStatusAttemptingTor": "",
|
||||
"networkStatusConnecting": "",
|
||||
"networkStatusDisconnected": "",
|
||||
"networkStatusOnline": "",
|
||||
"newBulletinLabel": "Nouveau bulletin",
|
||||
"newConnectionPaneTitle": "",
|
||||
"newGroupBtn": "Créer un nouveau groupe",
|
||||
"newPassword": "",
|
||||
"newProfile": "",
|
||||
"noPasswordWarning": "",
|
||||
"password": "",
|
||||
"password1Label": "",
|
||||
"password2Label": "",
|
||||
"passwordChangeError": "",
|
||||
"passwordErrorEmpty": "",
|
||||
"passwordErrorMatch": "",
|
||||
"pasteAddressToAddContact": "... coller une adresse ici pour ajouter un contact...",
|
||||
"peerAddress": "",
|
||||
"peerBlockedMessage": "",
|
||||
"peerName": "",
|
||||
"peerNotOnline": "",
|
||||
"peerOfflineMessage": "",
|
||||
"pendingLabel": "En attente",
|
||||
"postNewBulletinLabel": "Envoyer un nouveau bulletin",
|
||||
"profileName": "",
|
||||
"profileOnionLabel": "",
|
||||
"puzzleGameBtn": "Puzzle",
|
||||
"radioNoPassword": "",
|
||||
"radioUsePassword": "",
|
||||
"reallyLeaveThisGroupPrompt": "",
|
||||
"rejectGroupBtn": "Refuser",
|
||||
"saveBtn": "Sauvegarder",
|
||||
"savePeerHistory": "",
|
||||
"savePeerHistoryDescription": "",
|
||||
"saveProfileBtn": "",
|
||||
"search": "",
|
||||
"searchList": "",
|
||||
"server": "",
|
||||
"serverConnectivityConnected": "",
|
||||
"serverConnectivityDisconnected": "",
|
||||
"serverInfo": "",
|
||||
"serverLabel": "Serveur",
|
||||
"serverNotSynced": "",
|
||||
"serverSynced": "",
|
||||
"settingInterfaceZoom": "",
|
||||
"settingLanguage": "",
|
||||
"settingTheme": "",
|
||||
"smallTextLabel": "Petit",
|
||||
"successfullAddedContact": "",
|
||||
"themeDark": "",
|
||||
"themeLight": "",
|
||||
"titleManageContacts": "",
|
||||
"titleManageProfiles": "",
|
||||
"titleManageServers": "",
|
||||
"groupNameLabel": "Nom du groupe",
|
||||
"defaultGroupName": "Un super groupe",
|
||||
"createGroupBtn": "Créer",
|
||||
"profileOnionLabel": "Send this address to peers you want to connect with",
|
||||
"copyBtn": "Copier",
|
||||
"copiedToClipboardNotification": "Copié dans le presse-papier",
|
||||
"addPeerTab": "Add a peer",
|
||||
"createGroupTab": "Create a group",
|
||||
"joinGroupTab": "Join a group",
|
||||
"peerAddress": "Address",
|
||||
"peerName": "Name",
|
||||
"groupName": "Group name",
|
||||
"server": "Server",
|
||||
"invitation": "Invitation",
|
||||
"groupAddr": "Address",
|
||||
"addPeer": "Add Peer",
|
||||
"createGroup": "Create group",
|
||||
"joinGroup": "Join group",
|
||||
"newBulletinLabel": "Nouveau bulletin",
|
||||
"postNewBulletinLabel": "Envoyer un nouveau bulletin",
|
||||
"titlePlaceholder": "titre...",
|
||||
"pasteAddressToAddContact": "... coller une adresse ici pour ajouter un contact...",
|
||||
"blocked": "Blocked",
|
||||
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
|
||||
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
|
||||
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
|
||||
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
|
||||
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
|
||||
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
|
||||
"search": "Search...",
|
||||
"invitationLabel": "Invitation",
|
||||
"serverInfo": "Server Information",
|
||||
"serverConnectivityConnected": "Server Connected",
|
||||
"serverConnectivityDisconnected": "Server Disconnected",
|
||||
"serverSynced": "Synced",
|
||||
"serverNotSynced": "Out of Sync",
|
||||
"viewServerInfo": "Server Info",
|
||||
"saveBtn": "Sauvegarder",
|
||||
"inviteToGroupLabel": "Inviter quelqu'un",
|
||||
"inviteBtn": "Invitation",
|
||||
"deleteBtn": "Effacer",
|
||||
"update": "Update",
|
||||
"searchList": "Search List",
|
||||
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
|
||||
"addListItemBtn": "Add Item",
|
||||
"membershipDescription": "Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être representatives de l'ensemble des membres du groupe.",
|
||||
"dmTooltip": "Envoyer un message privé",
|
||||
"couldNotSendMsgError": "Impossible d'envoyer ce message",
|
||||
"acknowledgedLabel": "Confirmé",
|
||||
"pendingLabel": "En attente",
|
||||
"peerBlockedMessage": "Peer is blocked",
|
||||
"peerOfflineMessage": "Peer is offline, messages can't be delivered right now",
|
||||
"copiedClipboardNotification": "Copié dans le presse-papier",
|
||||
"newGroupBtn": "Créer un nouveau groupe",
|
||||
"acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe",
|
||||
"acceptGroupBtn": "Accepter",
|
||||
"rejectGroupBtn": "Refuser",
|
||||
"chatBtn": "Discuter",
|
||||
"listsBtn": "Listes",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"puzzleGameBtn": "Puzzle",
|
||||
"addressLabel": "Adresse",
|
||||
"displayNameLabel": "Pseudo",
|
||||
"blockBtn": "Block Peer",
|
||||
"savePeerHistory": "Save Peer History",
|
||||
"savePeerHistoryDescription": "Determines whether or not to delete any history associated with the peer.",
|
||||
"dontSavePeerHistory": "Delete Peer History",
|
||||
"unblockBtn": "Unblock Peer",
|
||||
"addProfileTitle": "Add new profile",
|
||||
"editProfileTitle": "Edit Profile",
|
||||
"profileName": "Display name",
|
||||
"defaultProfileName": "Alice",
|
||||
"newProfile": "New Profile",
|
||||
"editProfile": "Edit Profille",
|
||||
"radioUsePassword": "Password",
|
||||
"radioNoPassword": "Unencrypted (No password)",
|
||||
"noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted",
|
||||
"yourDisplayName": "Your Display Name",
|
||||
"currentPasswordLabel": "Current Password",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reenter password",
|
||||
"passwordErrorEmpty": "Password cannot be empty",
|
||||
"createProfileBtn": "Create Profile",
|
||||
"saveProfileBtn": "Save Profile",
|
||||
"passwordErrorMatch": "Passwords do not match",
|
||||
"passwordChangeError": "Error changing password: Supplied password rejected",
|
||||
"deleteProfileBtn": "Delete Profile",
|
||||
"deleteConfirmLabel": "Type DELETE to confirm",
|
||||
"deleteProfileConfirmBtn": "Really Delete Profile",
|
||||
"deleteConfirmText": "DELETE",
|
||||
"addNewProfileBtn": "Add new profile",
|
||||
"enterProfilePassword": "Enter a password to view your profiles",
|
||||
"password": "Password",
|
||||
"error0ProfilesLoadedForPassword": "0 profiles loaded with that password",
|
||||
"yourProfiles": "Your Profiles",
|
||||
"yourServers": "Your Servers",
|
||||
"unlock": "Unlock",
|
||||
"cwtchSettingsTitle": "Préférences Cwtch",
|
||||
"versionBuilddate": "Version: %1 Built on: %2",
|
||||
"zoomLabel": "Interface zoom (essentiellement la taille du texte et des composants de l'interface)",
|
||||
"blockUnknownLabel": "Block Unknown Peers",
|
||||
"settingLanguage": "Language",
|
||||
"localeEn": "English",
|
||||
"localeFr": "Frances",
|
||||
"localePt": "Portuguesa",
|
||||
"localeDe": "Deutsche",
|
||||
"settingInterfaceZoom": "Zoom level",
|
||||
"largeTextLabel": "Large",
|
||||
"settingTheme": "Theme",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"experimentsEnabled": "Enable Experiments",
|
||||
"versionTor": "Version %1 with tor %2",
|
||||
"version": "Version %1",
|
||||
"builddate": "Built on: %2",
|
||||
"defaultScalingText": "Taille par défaut du texte (échelle:",
|
||||
"smallTextLabel": "Petit",
|
||||
"loadingTor": "Loading tor...",
|
||||
"viewGroupMembershipTooltip": "View Group Membership",
|
||||
"networkStatusDisconnected": "Disconnected from the internet, check your connection",
|
||||
"networkStatusAttemptingTor": "Attempting to connect to Tor network",
|
||||
"networkStatusConnecting": "Connecting to network and peers...",
|
||||
"networkStatusOnline": "Online",
|
||||
"newConnectionPaneTitle": "New Connection",
|
||||
"addListItem": "Ajouter un nouvel élément",
|
||||
"addNewItem": "Ajouter un nouvel élément à la liste",
|
||||
"todoPlaceholder": "A faire...",
|
||||
"tooltipAddContact": "",
|
||||
"tooltipOpenSettings": "",
|
||||
"tooltipUnlockProfiles": "",
|
||||
"unblockBtn": "",
|
||||
"unlock": "",
|
||||
"update": "",
|
||||
"version": "",
|
||||
"versionBuilddate": "",
|
||||
"versionTor": "",
|
||||
"viewGroupMembershipTooltip": "",
|
||||
"viewServerInfo": "",
|
||||
"yesLeave": "",
|
||||
"yourDisplayName": "",
|
||||
"yourProfiles": "",
|
||||
"yourServers": "",
|
||||
"zoomLabel": "Interface zoom (essentiellement la taille du texte et des composants de l'interface)"
|
||||
"localeEs": "Espanol",
|
||||
"localeIt": "Italiana",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "it",
|
||||
"acceptGroupBtn": "Accetta",
|
||||
"acceptGroupInviteLabel": "Vuoi accettare l'invito a",
|
||||
"acknowledgedLabel": "Riconosciuto",
|
||||
"addListItem": "Aggiungi un nuovo elemento alla lista",
|
||||
"addListItemBtn": "Aggiungi elemento",
|
||||
"addNewItem": "Aggiungi un nuovo elemento alla lista",
|
||||
"addNewProfileBtn": "Aggiungi nuovo profilo",
|
||||
"addPeer": "Aggiungi peer",
|
||||
"addPeerTab": "Aggiungi un peer",
|
||||
"addProfileTitle": "Aggiungi nuovo profilo",
|
||||
"addressLabel": "Indirizzo",
|
||||
"blockBtn": "Blocca il peer",
|
||||
"blocked": "Bloccato",
|
||||
"blockUnknownLabel": "Blocca peer sconosciuti",
|
||||
"builddate": "Costruito il: %2",
|
||||
"bulletinsBtn": "Bollettini",
|
||||
"chatBtn": "Chat",
|
||||
"chatHistoryDefault": "",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiato negli Appunti",
|
||||
"copiedToClipboardNotification": "Copiato negli Appunti",
|
||||
"copyBtn": "Copia",
|
||||
"couldNotSendMsgError": "Impossibile inviare questo messaggio",
|
||||
"createGroup": "Crea un gruppo",
|
||||
"createGroupBtn": "Crea",
|
||||
"createGroupTab": "Crea un gruppo",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Crea un gruppo",
|
||||
"createProfileBtn": "Crea un profilo",
|
||||
"currentPasswordLabel": "Password corrente",
|
||||
"cwtchSettingsTitle": "Impostazioni di Cwtch",
|
||||
"cycleCatsAndroid": "Fare clic per scorrere le categorie.\\nPressione lunga per resettare.",
|
||||
"cycleCatsDesktop": "Fare clic per scorrere le categorie.\\nCliccare con il tasto destro per resettare.",
|
||||
"cycleColoursAndroid": "Fare clic per scorrere i colori.\\nPressione lunga per resettare.",
|
||||
"cycleColoursDesktop": "Fare clic per scorrere i colori.\\nCliccare con il tasto destro per resettare.",
|
||||
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\\nPressione lunga per resettare.",
|
||||
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\\nCliccare con il tasto destro per resettare.",
|
||||
"dateDaysAgo": "",
|
||||
"dateHoursAgo": "",
|
||||
"dateLastMonth": "",
|
||||
"dateLastYear": "",
|
||||
"dateMinutesAgo": "",
|
||||
"dateMonthsAgo": "",
|
||||
"dateNever": "",
|
||||
"dateRightNow": "",
|
||||
"dateWeeksAgo": "",
|
||||
"dateYearsAgo": "",
|
||||
"dateYesterday": "",
|
||||
"defaultGroupName": "Gruppo fantastico",
|
||||
"defaultProfileName": "Alice",
|
||||
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",
|
||||
"deleteBtn": "Elimina",
|
||||
"deleteConfirmLabel": "Digita ELIMINA per confermare",
|
||||
"deleteConfirmText": "ELIMINA",
|
||||
"deleteProfileBtn": "Elimina profilo",
|
||||
"deleteProfileConfirmBtn": "Elimina realmente il profilo",
|
||||
"descriptionBlockUnknownConnections": "",
|
||||
"descriptionExperiments": "",
|
||||
"descriptionExperimentsGroups": "",
|
||||
"displayNameLabel": "Nome visualizzato",
|
||||
"dmTooltip": "Clicca per inviare un Messagio Diretto",
|
||||
"dontSavePeerHistory": "Elimina cronologia dei peer",
|
||||
"editProfile": "Modifica profilo",
|
||||
"editProfileTitle": "Modifica profilo",
|
||||
"enableGroups": "",
|
||||
"enterCurrentPasswordForDelete": "",
|
||||
"enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili",
|
||||
"error0ProfilesLoadedForPassword": "0 profili caricati con quella password",
|
||||
"experimentsEnabled": "Esperimenti abilitati",
|
||||
"groupAddr": "Indirizzo",
|
||||
"groupName": "Nome del gruppo",
|
||||
"serverLabel": "Server",
|
||||
"groupNameLabel": "Nome del gruppo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Invito",
|
||||
"invitationLabel": "Invito",
|
||||
"inviteBtn": "Invitare",
|
||||
"inviteToGroup": "",
|
||||
"inviteToGroupLabel": "Invitare nel gruppo",
|
||||
"joinGroup": "Unisciti al gruppo",
|
||||
"joinGroupTab": "Unisciti a un gruppo",
|
||||
"largeTextLabel": "Grande",
|
||||
"leaveGroup": "",
|
||||
"listsBtn": "Liste",
|
||||
"loadingTor": "Caricamento di tor...",
|
||||
"localeDe": "Tedesco",
|
||||
"localeEn": "Inglese",
|
||||
"localeEs": "Spagnolo",
|
||||
"localeFr": "Francese",
|
||||
"localeIt": "Italiano",
|
||||
"localePt": "Portoghese",
|
||||
"membershipDescription": "Di seguito è riportato un elenco di utenti che hanno inviato messaggi al gruppo. Questo elenco potrebbe non corrispondere a tutti gli utenti che hanno accesso al gruppo.",
|
||||
"networkStatusAttemptingTor": "Tentativo di connessione alla rete Tor",
|
||||
"networkStatusConnecting": "Connessione alla rete e ai peer ...",
|
||||
"networkStatusDisconnected": "Disconnesso da Internet, controlla la tua connessione",
|
||||
"networkStatusOnline": "Online",
|
||||
"newBulletinLabel": "Nuovo bollettino",
|
||||
"newConnectionPaneTitle": "Nuova connessione",
|
||||
"newGroupBtn": "Crea un nuovo gruppo",
|
||||
"newPassword": "",
|
||||
"newProfile": "Nuovo profilo",
|
||||
"noPasswordWarning": "Non utilizzare una password su questo account significa che tutti i dati archiviati localmente non verranno criptati",
|
||||
"password": "Password",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reinserire la password",
|
||||
"passwordChangeError": "Errore durante la modifica della password: password fornita rifiutata",
|
||||
"passwordErrorEmpty": "La password non può essere vuota",
|
||||
"passwordErrorMatch": "Le password non corrispondono",
|
||||
"pasteAddressToAddContact": "... incolla qui un indirizzo per aggiungere un contatto...",
|
||||
"peerAddress": "Indirizzo",
|
||||
"peerBlockedMessage": "Il peer è bloccato",
|
||||
"peerName": "Nome",
|
||||
"peerNotOnline": "Il peer è offline. Le applicazioni non possono essere utilizzate in questo momento.",
|
||||
"peerOfflineMessage": "Il peer è offline, i messaggi non possono essere recapitati in questo momento",
|
||||
"pendingLabel": "In corso",
|
||||
"postNewBulletinLabel": "Pubblica un nuovo bollettino",
|
||||
"profileName": "Nome visualizzato",
|
||||
"defaultGroupName": "Gruppo fantastico",
|
||||
"createGroupBtn": "Crea",
|
||||
"profileOnionLabel": "Inviare questo indirizzo ai peer con cui si desidera connettersi",
|
||||
"puzzleGameBtn": "Gioco di puzzle",
|
||||
"radioNoPassword": "Non criptato (senza password)",
|
||||
"radioUsePassword": "Password",
|
||||
"reallyLeaveThisGroupPrompt": "",
|
||||
"rejectGroupBtn": "Rifiuta",
|
||||
"saveBtn": "Salva",
|
||||
"savePeerHistory": "Salva cronologia peer",
|
||||
"savePeerHistoryDescription": "Determina se eliminare o meno ogni cronologia eventualmente associata al peer.",
|
||||
"saveProfileBtn": "Salva il profilo",
|
||||
"search": "Ricerca...",
|
||||
"searchList": "Cerca nella lista",
|
||||
"copyBtn": "Copia",
|
||||
"copiedToClipboardNotification": "Copiato negli appunti",
|
||||
"addPeerTab": "Aggiungi un peer",
|
||||
"createGroupTab": "Crea un gruppo",
|
||||
"joinGroupTab": "Unisciti a un gruppo",
|
||||
"peerAddress": "Indirizzo",
|
||||
"peerName": "Nome",
|
||||
"groupName": "Nome del gruppo",
|
||||
"server": "Server",
|
||||
"invitation": "Invito",
|
||||
"groupAddr": "Indirizzo",
|
||||
"addPeer": "Aggiungi peer",
|
||||
"createGroup": "Crea un gruppo",
|
||||
"joinGroup": "Unisciti al gruppo",
|
||||
"newBulletinLabel": "Nuovo bollettino",
|
||||
"postNewBulletinLabel": "Pubblica un nuovo bollettino",
|
||||
"titlePlaceholder": "titolo...",
|
||||
"pasteAddressToAddContact": "... incolla qui un indirizzo per aggiungere un contatto...",
|
||||
"blocked": "Bloccato",
|
||||
"cycleCatsAndroid": "Fare clic per scorrere le categorie.\nPressione lunga per resettare.",
|
||||
"cycleCatsDesktop": "Fare clic per scorrere le categorie.\nCliccare con il tasto destro per resettare.",
|
||||
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\nPressione lunga per resettare.",
|
||||
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\nCliccare con il tasto destro per resettare.",
|
||||
"cycleColoursAndroid": "Fare clic per scorrere i colori.\nPressione lunga per resettare.",
|
||||
"cycleColoursDesktop": "Fare clic per scorrere i colori.\nCliccare con il tasto destro per resettare.",
|
||||
"search": "Ricerca...",
|
||||
"invitationLabel": "Invito",
|
||||
"serverInfo": "Informazioni sul server",
|
||||
"serverConnectivityConnected": "Server connesso",
|
||||
"serverConnectivityDisconnected": "Server disconnesso",
|
||||
"serverInfo": "Informazioni sul server",
|
||||
"serverLabel": "Server",
|
||||
"serverNotSynced": "Non sincronizzato",
|
||||
"serverSynced": "Sincronizzato",
|
||||
"settingInterfaceZoom": "Livello di zoom",
|
||||
"settingLanguage": "Lingua",
|
||||
"settingTheme": "Tema",
|
||||
"smallTextLabel": "Piccolo",
|
||||
"successfullAddedContact": "",
|
||||
"themeDark": "Scuro",
|
||||
"themeLight": "Chiaro",
|
||||
"titleManageContacts": "",
|
||||
"titleManageProfiles": "",
|
||||
"titleManageServers": "",
|
||||
"titlePlaceholder": "titolo...",
|
||||
"todoPlaceholder": "Da fare...",
|
||||
"tooltipAddContact": "",
|
||||
"tooltipOpenSettings": "",
|
||||
"tooltipUnlockProfiles": "",
|
||||
"unblockBtn": "Sblocca il peer",
|
||||
"unlock": "Sblocca",
|
||||
"update": "Aggiornamento",
|
||||
"version": "Versione %1",
|
||||
"versionBuilddate": "Versione: %1 Costruito il: %2",
|
||||
"versionTor": "Versione %1 con tor %2",
|
||||
"viewGroupMembershipTooltip": "Visualizza i membri del gruppo",
|
||||
"serverNotSynced": "Non sincronizzato",
|
||||
"viewServerInfo": "Informazioni sul server",
|
||||
"yesLeave": "",
|
||||
"saveBtn": "Salva",
|
||||
"inviteToGroupLabel": "Invitare nel gruppo",
|
||||
"inviteBtn": "Invitare",
|
||||
"deleteBtn": "Elimina",
|
||||
"update": "Aggiornamento",
|
||||
"searchList": "Cerca nella lista",
|
||||
"peerNotOnline": "Il peer è offline. Le applicazioni non possono essere utilizzate in questo momento.",
|
||||
"addListItemBtn": "Aggiungi elemento",
|
||||
"membershipDescription": "Di seguito è riportato un elenco di utenti che hanno inviato messaggi al gruppo. Questo elenco potrebbe non corrispondere a tutti gli utenti che hanno accesso al gruppo.",
|
||||
"dmTooltip": "Clicca per inviare un Messagio Diretto",
|
||||
"couldNotSendMsgError": "Impossibile inviare questo messaggio",
|
||||
"acknowledgedLabel": "Riconosciuto",
|
||||
"pendingLabel": "In corso",
|
||||
"peerBlockedMessage": "Il peer è bloccato",
|
||||
"peerOfflineMessage": "Il peer è offline, i messaggi non possono essere recapitati in questo momento",
|
||||
"copiedClipboardNotification": "Copiato negli Appunti",
|
||||
"newGroupBtn": "Crea un nuovo gruppo",
|
||||
"acceptGroupInviteLabel": "Vuoi accettare l'invito a",
|
||||
"acceptGroupBtn": "Accetta",
|
||||
"rejectGroupBtn": "Rifiuta",
|
||||
"chatBtn": "Chat",
|
||||
"listsBtn": "Liste",
|
||||
"bulletinsBtn": "Bollettini",
|
||||
"puzzleGameBtn": "Gioco di puzzle",
|
||||
"addressLabel": "Indirizzo",
|
||||
"displayNameLabel": "Nome visualizzato",
|
||||
"blockBtn": "Blocca il peer",
|
||||
"savePeerHistory": "Salva cronologia peer",
|
||||
"savePeerHistoryDescription": "Determina se eliminare o meno ogni cronologia eventualmente associata al peer.",
|
||||
"dontSavePeerHistory": "Elimina cronologia dei peer",
|
||||
"unblockBtn": "Sblocca il peer",
|
||||
"addProfileTitle": "Aggiungi nuovo profilo",
|
||||
"editProfileTitle": "Modifica profilo",
|
||||
"profileName": "Nome visualizzato",
|
||||
"defaultProfileName": "Alice",
|
||||
"newProfile": "Nuovo profilo",
|
||||
"editProfile": "Modifica profilo",
|
||||
"radioUsePassword": "Password",
|
||||
"radioNoPassword": "Non criptato (senza password)",
|
||||
"noPasswordWarning": "Non utilizzare una password su questo account significa che tutti i dati archiviati localmente non verranno criptati",
|
||||
"yourDisplayName": "Il tuo nome visualizzato",
|
||||
"currentPasswordLabel": "Password corrente",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reinserire la password",
|
||||
"passwordErrorEmpty": "La password non può essere vuota",
|
||||
"createProfileBtn": "Crea un profilo",
|
||||
"saveProfileBtn": "Salva il profilo",
|
||||
"passwordErrorMatch": "Le password non corrispondono",
|
||||
"passwordChangeError": "Errore durante la modifica della password: password fornita rifiutata",
|
||||
"deleteProfileBtn": "Elimina profilo",
|
||||
"deleteConfirmLabel": "Digita ELIMINA per confermare",
|
||||
"deleteProfileConfirmBtn": "Elimina realmente il profilo",
|
||||
"deleteConfirmText": "ELIMINA",
|
||||
"addNewProfileBtn": "Aggiungi nuovo profilo",
|
||||
"enterProfilePassword": "Inserisci una password per visualizzare i tuoi profili",
|
||||
"password": "Password",
|
||||
"error0ProfilesLoadedForPassword": "0 profili caricati con quella password",
|
||||
"yourProfiles": "I tuoi profili",
|
||||
"yourServers": "I tuoi server",
|
||||
"zoomLabel": "Zoom dell'interfaccia (influisce principalmente sulle dimensioni del testo e dei pulsanti)"
|
||||
"unlock": "Sblocca",
|
||||
"cwtchSettingsTitle": "Impostazioni di Cwtch",
|
||||
"versionBuilddate": "Versione: %1 Costruito il: %2",
|
||||
"zoomLabel": "Zoom dell'interfaccia (influisce principalmente sulle dimensioni del testo e dei pulsanti)",
|
||||
"blockUnknownLabel": "Blocca peer sconosciuti",
|
||||
"settingLanguage": "Lingua",
|
||||
"localeEn": "Inglese",
|
||||
"localeFr": "Francese",
|
||||
"localePt": "Portoghese",
|
||||
"localeDe": "Tedesco",
|
||||
"settingInterfaceZoom": "Livello di zoom",
|
||||
"largeTextLabel": "Grande",
|
||||
"settingTheme": "Tema",
|
||||
"themeLight": "Chiaro",
|
||||
"themeDark": "Scuro",
|
||||
"experimentsEnabled": "Esperimenti abilitati",
|
||||
"versionTor": "Versione %1 con tor %2",
|
||||
"version": "Versione %1",
|
||||
"builddate": "Costruito il: %2",
|
||||
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",
|
||||
"smallTextLabel": "Piccolo",
|
||||
"loadingTor": "Caricamento di tor...",
|
||||
"viewGroupMembershipTooltip": "Visualizza i membri del gruppo",
|
||||
"networkStatusDisconnected": "Disconnesso da Internet, controlla la tua connessione",
|
||||
"networkStatusAttemptingTor": "Tentativo di connessione alla rete Tor",
|
||||
"networkStatusConnecting": "Connessione alla rete e ai peer ...",
|
||||
"networkStatusOnline": "Online",
|
||||
"newConnectionPaneTitle": "Nuova connessione",
|
||||
"addListItem": "Aggiungi un nuovo elemento alla lista",
|
||||
"addNewItem": "Aggiungi un nuovo elemento alla lista",
|
||||
"todoPlaceholder": "Da fare...",
|
||||
"localeEs": "Spagnolo",
|
||||
"localeIt": "Italiano",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,166 +1,186 @@
|
|||
{
|
||||
"@@locale": "pt",
|
||||
"acceptGroupBtn": "Aceitar",
|
||||
"acceptGroupInviteLabel": "Você quer aceitar o convite para",
|
||||
"acknowledgedLabel": "Confirmada",
|
||||
"addListItem": "Adicionar Item à Lista",
|
||||
"addListItemBtn": "",
|
||||
"addNewItem": "Adicionar novo item à lista",
|
||||
"addNewProfileBtn": "",
|
||||
"addPeer": "",
|
||||
"addPeerTab": "",
|
||||
"addProfileTitle": "",
|
||||
"addressLabel": "Endereço",
|
||||
"blockBtn": "",
|
||||
"blocked": "",
|
||||
"blockUnknownLabel": "",
|
||||
"builddate": "",
|
||||
"bulletinsBtn": "Boletins",
|
||||
"chatBtn": "Chat",
|
||||
"chatHistoryDefault": "",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiado",
|
||||
"copiedToClipboardNotification": "Copiado",
|
||||
"copyBtn": "Copiar",
|
||||
"couldNotSendMsgError": "Não deu para enviar esta mensagem",
|
||||
"createGroup": "",
|
||||
"createGroupBtn": "Criar",
|
||||
"createGroupTab": "",
|
||||
"@@last_modified": "2021-06-15T02:08:49+02:00",
|
||||
"createGroupTitle": "Criar Grupo",
|
||||
"createProfileBtn": "",
|
||||
"currentPasswordLabel": "",
|
||||
"cwtchSettingsTitle": "Configurações do Cwtch",
|
||||
"cycleCatsAndroid": "",
|
||||
"cycleCatsDesktop": "",
|
||||
"cycleColoursAndroid": "",
|
||||
"cycleColoursDesktop": "",
|
||||
"cycleMorphsAndroid": "",
|
||||
"cycleMorphsDesktop": "",
|
||||
"dateDaysAgo": "",
|
||||
"dateHoursAgo": "",
|
||||
"dateLastMonth": "",
|
||||
"dateLastYear": "",
|
||||
"dateMinutesAgo": "",
|
||||
"dateMonthsAgo": "",
|
||||
"dateNever": "",
|
||||
"dateRightNow": "",
|
||||
"dateWeeksAgo": "",
|
||||
"dateYearsAgo": "",
|
||||
"dateYesterday": "",
|
||||
"defaultGroupName": "Grupo incrível",
|
||||
"defaultProfileName": "",
|
||||
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
|
||||
"deleteBtn": "Deletar",
|
||||
"deleteConfirmLabel": "",
|
||||
"deleteConfirmText": "",
|
||||
"deleteProfileBtn": "",
|
||||
"deleteProfileConfirmBtn": "",
|
||||
"descriptionBlockUnknownConnections": "",
|
||||
"descriptionExperiments": "",
|
||||
"descriptionExperimentsGroups": "",
|
||||
"displayNameLabel": "Nome de Exibição",
|
||||
"dmTooltip": "Clique para DM",
|
||||
"dontSavePeerHistory": "",
|
||||
"editProfile": "",
|
||||
"editProfileTitle": "",
|
||||
"enableGroups": "",
|
||||
"enterCurrentPasswordForDelete": "",
|
||||
"enterProfilePassword": "",
|
||||
"error0ProfilesLoadedForPassword": "",
|
||||
"experimentsEnabled": "",
|
||||
"groupAddr": "",
|
||||
"groupName": "",
|
||||
"groupNameLabel": "Nome do Grupo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "",
|
||||
"invitationLabel": "Convite",
|
||||
"inviteBtn": "Convidar",
|
||||
"inviteToGroup": "",
|
||||
"inviteToGroupLabel": "Convidar ao grupo",
|
||||
"joinGroup": "",
|
||||
"joinGroupTab": "",
|
||||
"largeTextLabel": "Grande",
|
||||
"leaveGroup": "",
|
||||
"listsBtn": "Listas",
|
||||
"loadingTor": "",
|
||||
"localeDe": "",
|
||||
"localeEn": "",
|
||||
"localeEs": "",
|
||||
"localeFr": "",
|
||||
"localeIt": "",
|
||||
"localePt": "",
|
||||
"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.",
|
||||
"networkStatusAttemptingTor": "",
|
||||
"networkStatusConnecting": "",
|
||||
"networkStatusDisconnected": "",
|
||||
"networkStatusOnline": "",
|
||||
"newBulletinLabel": "Novo Boletim",
|
||||
"newConnectionPaneTitle": "",
|
||||
"newGroupBtn": "Criar novo grupo",
|
||||
"newPassword": "",
|
||||
"newProfile": "",
|
||||
"noPasswordWarning": "",
|
||||
"password": "",
|
||||
"password1Label": "",
|
||||
"password2Label": "",
|
||||
"passwordChangeError": "",
|
||||
"passwordErrorEmpty": "",
|
||||
"passwordErrorMatch": "",
|
||||
"pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…",
|
||||
"peerAddress": "",
|
||||
"peerBlockedMessage": "",
|
||||
"peerName": "",
|
||||
"peerNotOnline": "",
|
||||
"peerOfflineMessage": "",
|
||||
"pendingLabel": "Pendente",
|
||||
"postNewBulletinLabel": "Postar novo boletim",
|
||||
"profileName": "",
|
||||
"profileOnionLabel": "",
|
||||
"puzzleGameBtn": "Jogo de Adivinhação",
|
||||
"radioNoPassword": "",
|
||||
"radioUsePassword": "",
|
||||
"reallyLeaveThisGroupPrompt": "",
|
||||
"rejectGroupBtn": "Recusar",
|
||||
"saveBtn": "Salvar",
|
||||
"savePeerHistory": "",
|
||||
"savePeerHistoryDescription": "",
|
||||
"saveProfileBtn": "",
|
||||
"search": "",
|
||||
"searchList": "",
|
||||
"server": "",
|
||||
"serverConnectivityConnected": "",
|
||||
"serverConnectivityDisconnected": "",
|
||||
"serverInfo": "",
|
||||
"serverLabel": "Servidor",
|
||||
"serverNotSynced": "",
|
||||
"serverSynced": "",
|
||||
"settingInterfaceZoom": "",
|
||||
"settingLanguage": "",
|
||||
"settingTheme": "",
|
||||
"smallTextLabel": "Pequeno",
|
||||
"successfullAddedContact": "",
|
||||
"themeDark": "",
|
||||
"themeLight": "",
|
||||
"titleManageContacts": "",
|
||||
"titleManageProfiles": "",
|
||||
"titleManageServers": "",
|
||||
"groupNameLabel": "Nome do Grupo",
|
||||
"defaultGroupName": "Grupo incrível",
|
||||
"createGroupBtn": "Criar",
|
||||
"profileOnionLabel": "Send this address to peers you want to connect with",
|
||||
"copyBtn": "Copiar",
|
||||
"copiedToClipboardNotification": "Copiado",
|
||||
"addPeerTab": "Add a peer",
|
||||
"createGroupTab": "Create a group",
|
||||
"joinGroupTab": "Join a group",
|
||||
"peerAddress": "Address",
|
||||
"peerName": "Name",
|
||||
"groupName": "Group name",
|
||||
"server": "Server",
|
||||
"invitation": "Invitation",
|
||||
"groupAddr": "Address",
|
||||
"addPeer": "Add Peer",
|
||||
"createGroup": "Create group",
|
||||
"joinGroup": "Join group",
|
||||
"newBulletinLabel": "Novo Boletim",
|
||||
"postNewBulletinLabel": "Postar novo boletim",
|
||||
"titlePlaceholder": "título…",
|
||||
"pasteAddressToAddContact": "… cole um endereço aqui para adicionar um contato…",
|
||||
"blocked": "Blocked",
|
||||
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
|
||||
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
|
||||
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
|
||||
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
|
||||
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
|
||||
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
|
||||
"search": "Search...",
|
||||
"invitationLabel": "Convite",
|
||||
"serverInfo": "Server Information",
|
||||
"serverConnectivityConnected": "Server Connected",
|
||||
"serverConnectivityDisconnected": "Server Disconnected",
|
||||
"serverSynced": "Synced",
|
||||
"serverNotSynced": "Out of Sync",
|
||||
"viewServerInfo": "Server Info",
|
||||
"saveBtn": "Salvar",
|
||||
"inviteToGroupLabel": "Convidar ao grupo",
|
||||
"inviteBtn": "Convidar",
|
||||
"deleteBtn": "Deletar",
|
||||
"update": "Update",
|
||||
"searchList": "Search List",
|
||||
"peerNotOnline": "Peer is Offline. Applications cannot be used right now.",
|
||||
"addListItemBtn": "Add Item",
|
||||
"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.",
|
||||
"dmTooltip": "Clique para DM",
|
||||
"couldNotSendMsgError": "Não deu para enviar esta mensagem",
|
||||
"acknowledgedLabel": "Confirmada",
|
||||
"pendingLabel": "Pendente",
|
||||
"peerBlockedMessage": "Peer is blocked",
|
||||
"peerOfflineMessage": "Peer is offline, messages can't be delivered right now",
|
||||
"copiedClipboardNotification": "Copiado",
|
||||
"newGroupBtn": "Criar novo grupo",
|
||||
"acceptGroupInviteLabel": "Você quer aceitar o convite para",
|
||||
"acceptGroupBtn": "Aceitar",
|
||||
"rejectGroupBtn": "Recusar",
|
||||
"chatBtn": "Chat",
|
||||
"listsBtn": "Listas",
|
||||
"bulletinsBtn": "Boletins",
|
||||
"puzzleGameBtn": "Jogo de Adivinhação",
|
||||
"addressLabel": "Endereço",
|
||||
"displayNameLabel": "Nome de Exibição",
|
||||
"blockBtn": "Block Peer",
|
||||
"savePeerHistory": "Save Peer History",
|
||||
"savePeerHistoryDescription": "Determines whether or not to delete any history associated with the peer.",
|
||||
"dontSavePeerHistory": "Delete Peer History",
|
||||
"unblockBtn": "Unblock Peer",
|
||||
"addProfileTitle": "Add new profile",
|
||||
"editProfileTitle": "Edit Profile",
|
||||
"profileName": "Display name",
|
||||
"defaultProfileName": "Alice",
|
||||
"newProfile": "New Profile",
|
||||
"editProfile": "Edit Profille",
|
||||
"radioUsePassword": "Password",
|
||||
"radioNoPassword": "Unencrypted (No password)",
|
||||
"noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted",
|
||||
"yourDisplayName": "Your Display Name",
|
||||
"currentPasswordLabel": "Current Password",
|
||||
"password1Label": "Password",
|
||||
"password2Label": "Reenter password",
|
||||
"passwordErrorEmpty": "Password cannot be empty",
|
||||
"createProfileBtn": "Create Profile",
|
||||
"saveProfileBtn": "Save Profile",
|
||||
"passwordErrorMatch": "Passwords do not match",
|
||||
"passwordChangeError": "Error changing password: Supplied password rejected",
|
||||
"deleteProfileBtn": "Delete Profile",
|
||||
"deleteConfirmLabel": "Type DELETE to confirm",
|
||||
"deleteProfileConfirmBtn": "Really Delete Profile",
|
||||
"deleteConfirmText": "DELETE",
|
||||
"addNewProfileBtn": "Add new profile",
|
||||
"enterProfilePassword": "Enter a password to view your profiles",
|
||||
"password": "Password",
|
||||
"error0ProfilesLoadedForPassword": "0 profiles loaded with that password",
|
||||
"yourProfiles": "Your Profiles",
|
||||
"yourServers": "Your Servers",
|
||||
"unlock": "Unlock",
|
||||
"cwtchSettingsTitle": "Configurações do Cwtch",
|
||||
"versionBuilddate": "Version: %1 Built on: %2",
|
||||
"zoomLabel": "Zoom da interface (afeta principalmente tamanho de texto e botões)",
|
||||
"blockUnknownLabel": "Block Unknown Peers",
|
||||
"settingLanguage": "Language",
|
||||
"localeEn": "English",
|
||||
"localeFr": "Frances",
|
||||
"localePt": "Portuguesa",
|
||||
"localeDe": "Deutsche",
|
||||
"settingInterfaceZoom": "Zoom level",
|
||||
"largeTextLabel": "Grande",
|
||||
"settingTheme": "Theme",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"experimentsEnabled": "Enable Experiments",
|
||||
"versionTor": "Version %1 with tor %2",
|
||||
"version": "Version %1",
|
||||
"builddate": "Built on: %2",
|
||||
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
|
||||
"smallTextLabel": "Pequeno",
|
||||
"loadingTor": "Loading tor...",
|
||||
"viewGroupMembershipTooltip": "View Group Membership",
|
||||
"networkStatusDisconnected": "Disconnected from the internet, check your connection",
|
||||
"networkStatusAttemptingTor": "Attempting to connect to Tor network",
|
||||
"networkStatusConnecting": "Connecting to network and peers...",
|
||||
"networkStatusOnline": "Online",
|
||||
"newConnectionPaneTitle": "New Connection",
|
||||
"addListItem": "Adicionar Item à Lista",
|
||||
"addNewItem": "Adicionar novo item à lista",
|
||||
"todoPlaceholder": "Afazer…",
|
||||
"tooltipAddContact": "",
|
||||
"tooltipOpenSettings": "",
|
||||
"tooltipUnlockProfiles": "",
|
||||
"unblockBtn": "",
|
||||
"unlock": "",
|
||||
"update": "",
|
||||
"version": "",
|
||||
"versionBuilddate": "",
|
||||
"versionTor": "",
|
||||
"viewGroupMembershipTooltip": "",
|
||||
"viewServerInfo": "",
|
||||
"yesLeave": "",
|
||||
"yourDisplayName": "",
|
||||
"yourProfiles": "",
|
||||
"yourServers": "",
|
||||
"zoomLabel": "Zoom da interface (afeta principalmente tamanho de texto e botões)"
|
||||
"localeEs": "Espanol",
|
||||
"localeIt": "Italiana",
|
||||
"enableGroups": "Enable Group Chat",
|
||||
"enterCurrentPasswordForDelete": "Please enter current password to delete this profile.",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"tooltipOpenSettings": "Open the settings pane",
|
||||
"tooltipAddContact": "Add a new contact or conversation",
|
||||
"titleManageContacts": "Conversations",
|
||||
"tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.",
|
||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||
"descriptionExperiments": "Cwtch experiments are optional, opt-in features that add additional functionality to Cwtch that may have different privacy considerations than traditional 1:1 metadata resistant chat e.g. group chat, bot integration etc.",
|
||||
"descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.",
|
||||
"descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.",
|
||||
"successfullAddedContact": "Successfully added ",
|
||||
"dateRightNow": "Right Now",
|
||||
"dateMinutesAgo": "Minutes Ago",
|
||||
"dateHoursAgo": "Hours Ago",
|
||||
"dateDaysAgo": "Days Ago",
|
||||
"dateWeeksAgo": "Weeks Ago",
|
||||
"dateLastMonth": "Last Month",
|
||||
"dateYesterday": "Yesterday",
|
||||
"dateLastYear": "Last Year",
|
||||
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||
"dateNever": "Never",
|
||||
"dateMonthsAgo": "Months Ago",
|
||||
"titleManageServers": "Manage Servers",
|
||||
"inviteToGroup": "You have been invited to join a group:",
|
||||
"leaveGroup": "Leave This Conversation",
|
||||
"reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.",
|
||||
"yesLeave": "Yes, Leave This Conversation",
|
||||
"newPassword": "New Password",
|
||||
"chatHistoryDefault": "This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right.",
|
||||
"accepted": "Accepted!",
|
||||
"rejected": "Rejected!",
|
||||
"contactSuggestion": "This is a contact suggestion for: ",
|
||||
"sendAnInvitation": "You sent an invitation for: ",
|
||||
"torVersion": "Tor Version",
|
||||
"torStatus": "Tor Status",
|
||||
"resetTor": "Reset",
|
||||
"cancel": "Cancel",
|
||||
"sendMessage": "Send Message",
|
||||
"sendInvite": "Send a contact or group invite",
|
||||
"deleteProfileSuccess": "Successfully deleted profile",
|
||||
"addServerFirst": "You need to add a server before you can create a group",
|
||||
"nickChangeSuccess": "Profile nickname changed successfully",
|
||||
"createProfileToBegin": "Please create or unlock a profile to begin",
|
||||
"addContactFirst": "Add or pick a contact to begin chatting.",
|
||||
"torNetworkStatus": "Tor network status",
|
||||
"debugLog": "Turn on console debug logging",
|
||||
"profileDeleteSuccess": "Successfully deleted profile",
|
||||
"malformedMessage": "Malformed message"
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cwtch/notification_manager.dart';
|
||||
import 'package:cwtch/views/messageview.dart';
|
||||
import 'package:cwtch/widgets/rightshiftfixer.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cwtch/cwtch/ffi.dart';
|
||||
|
@ -8,6 +11,7 @@ import 'package:cwtch/errorHandler.dart';
|
|||
import 'package:cwtch/settings.dart';
|
||||
import 'package:cwtch/torstatus.dart';
|
||||
import 'package:cwtch/views/triplecolview.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'cwtch/cwtch.dart';
|
||||
import 'cwtch/cwtchNotifier.dart';
|
||||
|
@ -44,6 +48,8 @@ class FlwtchState extends State<Flwtch> {
|
|||
var columns = [1]; // default or 'single column' mode
|
||||
//var columns = [1, 1, 2];
|
||||
late ProfileListState profs;
|
||||
final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler');
|
||||
final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
initState() {
|
||||
|
@ -51,6 +57,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
cwtchInit = false;
|
||||
|
||||
profs = ProfileListState();
|
||||
notificationClickChannel.setMethodCallHandler(_externalNotificationClicked);
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager());
|
||||
|
@ -63,11 +70,10 @@ class FlwtchState extends State<Flwtch> {
|
|||
cwtch = CwtchFfi(cwtchNotifier);
|
||||
}
|
||||
|
||||
cwtch.Start().then((val) {
|
||||
cwtch.Start();
|
||||
setState(() {
|
||||
cwtchInit = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
|
||||
|
@ -92,13 +98,12 @@ class FlwtchState extends State<Flwtch> {
|
|||
return Consumer<Settings>(
|
||||
builder: (context, settings, child) => MaterialApp(
|
||||
key: Key('app'),
|
||||
navigatorKey: navKey,
|
||||
locale: settings.locale,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
title: 'Cwtch',
|
||||
theme: mkThemeData(settings),
|
||||
// from dan: home: cwtchInit == true ? ProfileMgrView(cwtch) : SplashView(),
|
||||
// from erinn: home: columns.length == 3 ? TripleColumnView() : ProfileMgrView(),
|
||||
home: cwtchInit == true ? (columns.length == 3 ? TripleColumnView() : ShiftRightFixer(child: ProfileMgrView())) : SplashView(),
|
||||
),
|
||||
);
|
||||
|
@ -106,6 +111,26 @@ class FlwtchState extends State<Flwtch> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _externalNotificationClicked(MethodCall call) async {
|
||||
var args = jsonDecode(call.arguments);
|
||||
var profile = profs.getProfile(args["ProfileOnion"])!;
|
||||
var contact = profile.contactList.getContact(args["RemotePeer"])!;
|
||||
contact.unreadMessages = 0;
|
||||
navKey.currentState?.push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (BuildContext builderContext) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: profile),
|
||||
ChangeNotifierProvider.value(value: contact),
|
||||
],
|
||||
builder: (context, child) => MessageView(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
cwtch.dispose();
|
||||
|
|
|
@ -183,7 +183,7 @@ class ProfileInfoState extends ChangeNotifier {
|
|||
|
||||
// Parse out the server list json into our server info state struct...
|
||||
void replaceServers(String serversJson) {
|
||||
if (serversJson != null && serversJson != "" && serversJson != "null") {
|
||||
if (serversJson != "" && serversJson != "null") {
|
||||
print("got servers $serversJson");
|
||||
List<dynamic> servers = jsonDecode(serversJson);
|
||||
this._servers.replace(servers.map((server) {
|
||||
|
@ -382,6 +382,7 @@ class MessageState extends ChangeNotifier {
|
|||
late String _inviteNick;
|
||||
late DateTime _timestamp;
|
||||
late String _senderOnion;
|
||||
late int _flags;
|
||||
String? _senderImage;
|
||||
late String _signature = "";
|
||||
late bool _ackd = false;
|
||||
|
@ -402,6 +403,12 @@ class MessageState extends ChangeNotifier {
|
|||
get message => this._message;
|
||||
get overlay => this._overlay;
|
||||
get timestamp => this._timestamp;
|
||||
int get flags => this._flags;
|
||||
set flags(int newVal) {
|
||||
this._flags = newVal;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool get ackd => this._ackd;
|
||||
bool get error => this._error;
|
||||
bool get malformed => this._malformed;
|
||||
|
@ -450,6 +457,7 @@ class MessageState extends ChangeNotifier {
|
|||
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
|
||||
this._senderOnion = messageWrapper['PeerID'];
|
||||
this._senderImage = messageWrapper['ContactImage'];
|
||||
this._flags = int.parse(messageWrapper['Flags'].toString(), radix: 2);
|
||||
|
||||
// If this is a group, store the signature
|
||||
if (contactHandle.length == 32) {
|
||||
|
|
|
@ -1383,6 +1383,8 @@ ThemeData mkThemeData(Settings opaque) {
|
|||
)),
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarActiveColor()), trackColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())),
|
||||
tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))),
|
||||
dialogTheme: DialogTheme(
|
||||
backgroundColor: opaque.current().backgroundPaneColor(),
|
||||
|
|
|
@ -119,7 +119,11 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
CwtchButtonTextField(
|
||||
controller: ctrlrOnion,
|
||||
onPressed: _copyOnion,
|
||||
icon: Icon(CwtchIcons.copy_address),
|
||||
readonly: true,
|
||||
icon: Icon(
|
||||
CwtchIcons.address_copy_2,
|
||||
size: 32,
|
||||
),
|
||||
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||
),
|
||||
SizedBox(
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cwtch/widgets/textfield.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import '../cwtch_icons_icons.dart';
|
||||
import '../main.dart';
|
||||
import '../opaque.dart';
|
||||
import '../settings.dart';
|
||||
|
@ -122,7 +123,11 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
|
|||
CwtchButtonTextField(
|
||||
controller: ctrlrOnion,
|
||||
onPressed: _copyOnion,
|
||||
icon: Icon(Icons.copy),
|
||||
readonly: true,
|
||||
icon: Icon(
|
||||
CwtchIcons.address_copy_2,
|
||||
size: 32,
|
||||
),
|
||||
tooltip: AppLocalizations.of(context)!.copyBtn,
|
||||
)
|
||||
])),
|
||||
|
|
|
@ -177,7 +177,9 @@ class _MessageViewState extends State<MessageView> {
|
|||
),
|
||||
ChangeNotifierProvider.value(
|
||||
value: Provider.of<ProfileInfoState>(ctx, listen: false),
|
||||
child: DropdownContacts(onChanged: (newVal) {
|
||||
child: DropdownContacts(filter: (contact) {
|
||||
return contact.onion != Provider.of<ContactInfoState>(context).onion;
|
||||
}, onChanged: (newVal) {
|
||||
setState(() {
|
||||
this.selectedContact = newVal;
|
||||
});
|
||||
|
|
|
@ -9,9 +9,9 @@ import 'package:cwtch/widgets/tor_icon.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:cwtch/widgets/profilerow.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../config.dart';
|
||||
import '../main.dart';
|
||||
import '../model.dart';
|
||||
import '../opaque.dart';
|
||||
import '../torstatus.dart';
|
||||
import 'addeditprofileview.dart';
|
||||
import 'globalsettingsview.dart';
|
||||
|
@ -58,22 +58,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
),
|
||||
Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor())))
|
||||
]),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: TorIcon(),
|
||||
onPressed: _pushTorStatus,
|
||||
tooltip: Provider.of<TorStatus>(context).progress == 100
|
||||
? AppLocalizations.of(context)!.networkStatusOnline
|
||||
: (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor),
|
||||
),
|
||||
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
|
||||
IconButton(
|
||||
icon: Icon(CwtchIcons.lock_open_24px),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles,
|
||||
onPressed: _modalUnlockProfiles,
|
||||
),
|
||||
IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings),
|
||||
],
|
||||
actions: getActions(),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _pushAddEditProfile,
|
||||
|
@ -88,6 +73,36 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
);
|
||||
}
|
||||
|
||||
List<Widget> getActions() {
|
||||
List<Widget> actions = new List<Widget>.empty(growable: true);
|
||||
|
||||
// Tor Status
|
||||
actions.add(IconButton(
|
||||
icon: TorIcon(),
|
||||
onPressed: _pushTorStatus,
|
||||
tooltip: Provider.of<TorStatus>(context).progress == 100
|
||||
? AppLocalizations.of(context)!.networkStatusOnline
|
||||
: (Provider.of<TorStatus>(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor),
|
||||
));
|
||||
|
||||
// Only show debug button on development builds
|
||||
if (EnvironmentConfig.BUILD_VER == dev_version) {
|
||||
actions.add(IconButton(icon: Icon(Icons.bug_report_outlined), tooltip: "Turn on Debug Logging", onPressed: _setLoggingLevelDebug));
|
||||
}
|
||||
|
||||
// Unlock Profiles
|
||||
actions.add(IconButton(
|
||||
icon: Icon(CwtchIcons.lock_open_24px),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles,
|
||||
onPressed: _modalUnlockProfiles,
|
||||
));
|
||||
|
||||
// Global Settings
|
||||
actions.add(IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
void _setLoggingLevelDebug() {
|
||||
final setLoggingLevel = {
|
||||
"EventType": "SetLoggingLevel",
|
||||
|
|
|
@ -3,6 +3,10 @@ import 'package:provider/provider.dart';
|
|||
|
||||
import '../model.dart';
|
||||
|
||||
bool noFilter(ContactInfoState peer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dropdown menu populated from Provider.of<ProfileInfoState>'s contact list
|
||||
// Includes both peers and groups; begins empty/nothing selected
|
||||
// Displays nicknames to UI but uses handles as values
|
||||
|
@ -10,8 +14,10 @@ import '../model.dart';
|
|||
class DropdownContacts extends StatefulWidget {
|
||||
DropdownContacts({
|
||||
required this.onChanged,
|
||||
this.filter = noFilter,
|
||||
});
|
||||
final Function(dynamic) onChanged;
|
||||
final bool Function(ContactInfoState) filter;
|
||||
|
||||
@override
|
||||
_DropdownContactsState createState() => _DropdownContactsState();
|
||||
|
@ -24,7 +30,7 @@ class _DropdownContactsState extends State<DropdownContacts> {
|
|||
Widget build(BuildContext context) {
|
||||
return DropdownButton(
|
||||
value: this.selected,
|
||||
items: Provider.of<ProfileInfoState>(context, listen: false).contactList.contacts.map<DropdownMenuItem<String>>((ContactInfoState contact) {
|
||||
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));
|
||||
}).toList(),
|
||||
onChanged: (String? newVal) {
|
||||
|
|
|
@ -28,6 +28,7 @@ class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
|
|||
suffixIcon: IconButton(
|
||||
onPressed: widget.onPressed,
|
||||
icon: widget.icon,
|
||||
padding: EdgeInsets.fromLTRB(0.0, 4.0, 2.0, 2.0),
|
||||
tooltip: widget.tooltip,
|
||||
enableFeedback: true,
|
||||
color: theme.current().mainTextColor(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||
import 'package:cwtch/widgets/malformedbubble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../main.dart';
|
||||
|
@ -21,15 +22,17 @@ class InvitationBubble extends StatefulWidget {
|
|||
|
||||
class InvitationBubbleState extends State<InvitationBubble> {
|
||||
bool rejected = false;
|
||||
bool isAccepted = false;
|
||||
FocusNode _focus = FocusNode();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
||||
var isGroup = Provider.of<MessageState>(context).overlay == 101;
|
||||
var isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget) != null;
|
||||
isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget) != null;
|
||||
var prettyDate = "";
|
||||
var borderRadiousEh = 15.0;
|
||||
rejected = Provider.of<MessageState>(context).flags & 0x01 == 0x01;
|
||||
var myKey = Provider.of<MessageState>(context).profileOnion + "::" + Provider.of<MessageState>(context).contactHandle + "::" + Provider.of<MessageState>(context).messageIndex.toString();
|
||||
|
||||
if (Provider.of<MessageState>(context).timestamp != null) {
|
||||
|
@ -53,25 +56,32 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
|||
child: SelectableText(senderDisplayStr + '\u202F',
|
||||
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor())));
|
||||
|
||||
// todo: translations
|
||||
// If we receive an invite for ourselves, treat it as a bug. The UI no longer allows this so it could have only come from
|
||||
// some kind of malfeasance.
|
||||
var selfInvite = Provider.of<MessageState>(context).inviteNick == Provider.of<ProfileInfoState>(context).onion;
|
||||
if (selfInvite) {
|
||||
return MalformedBubble();
|
||||
}
|
||||
|
||||
var wdgMessage = fromMe
|
||||
? senderInviteChrome("You sent an invitation for", isGroup ? "a group" : Provider.of<MessageState>(context).message, myKey)
|
||||
: inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : "This is a contact suggestion for:", Provider.of<MessageState>(context).inviteNick,
|
||||
Provider.of<MessageState>(context).inviteTarget, myKey);
|
||||
? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation,
|
||||
isGroup ? Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget)!.nickname : Provider.of<MessageState>(context).message, myKey)
|
||||
: (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of<MessageState>(context).inviteNick,
|
||||
Provider.of<MessageState>(context).inviteTarget, myKey));
|
||||
|
||||
Widget wdgDecorations;
|
||||
if (fromMe) {
|
||||
wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageState>(context).ackd, errored: Provider.of<MessageState>(context).error, fromMe: fromMe, prettyDate: prettyDate);
|
||||
} else if (isAccepted) {
|
||||
wdgDecorations = Text("Accepted!");
|
||||
wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F');
|
||||
} else if (this.rejected) {
|
||||
wdgDecorations = Text("Rejected.");
|
||||
wdgDecorations = Text(AppLocalizations.of(context)!.rejected + '\u202F');
|
||||
} else {
|
||||
wdgDecorations = Center(
|
||||
widthFactor: 1,
|
||||
child: Row(children: [
|
||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Reject"), onPressed: _btnReject)),
|
||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text("Accept"), onPressed: _btnAccept)),
|
||||
child: Wrap(children: [
|
||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text(AppLocalizations.of(context)!.rejectGroupBtn + '\u202F'), onPressed: _btnReject)),
|
||||
Padding(padding: EdgeInsets.all(5), child: TextButton(child: Text(AppLocalizations.of(context)!.acceptGroupBtn + '\u202F'), onPressed: _btnAccept)),
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -95,87 +105,83 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
|||
widthFactor: 1.0,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(9.0),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(4), child: Icon(CwtchIcons.send_invite, size: 32))),
|
||||
child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [
|
||||
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(CwtchIcons.send_invite, size: 32))),
|
||||
Center(
|
||||
widthFactor: 1.0,
|
||||
child: Column(
|
||||
crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations])),
|
||||
children: fromMe ? [wdgMessage, wdgDecorations] : [wdgSender, wdgMessage, wdgDecorations]),
|
||||
)
|
||||
])))));
|
||||
});
|
||||
}
|
||||
|
||||
void _btnReject() {
|
||||
//todo: how should we track inline invite rejections?
|
||||
setState(() => this.rejected = true);
|
||||
setState(() {
|
||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||
var idx = Provider.of<MessageState>(context, listen: false).messageIndex;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageState>(context, listen: false).flags | 0x01);
|
||||
Provider.of<MessageState>(context).flags |= 0x01;
|
||||
});
|
||||
}
|
||||
|
||||
void _btnAccept() {
|
||||
setState(() {
|
||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
if (Provider.of<MessageState>(context, listen: false).overlay == 100) {
|
||||
final setPeerAttribute = {
|
||||
"EventType": "AddContact",
|
||||
"Data": {"ImportString": Provider.of<MessageState>(context, listen: false).message},
|
||||
};
|
||||
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||
} else {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.ImportBundle(profileOnion, Provider.of<MessageState>(context, listen: false).message);
|
||||
}
|
||||
isAccepted = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Construct an invite chrome for the sender
|
||||
Widget senderInviteChrome(String chrome, String targetName, String myKey) {
|
||||
return Center(
|
||||
widthFactor: 1,
|
||||
child: Row(children: [
|
||||
return Wrap(children: [
|
||||
SelectableText(
|
||||
chrome,
|
||||
focusNode: _focus,
|
||||
chrome + '\u202F',
|
||||
style: TextStyle(
|
||||
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
maxLines: 2,
|
||||
textWidthBasis: TextWidthBasis.longestLine,
|
||||
),
|
||||
SelectableText(
|
||||
targetName + '\u202F',
|
||||
key: Key(myKey),
|
||||
focusNode: _focus,
|
||||
style: TextStyle(
|
||||
color: Provider.of<Settings>(context).theme.messageFromMeTextColor(),
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
maxLines: 2,
|
||||
textWidthBasis: TextWidthBasis.longestLine,
|
||||
)
|
||||
]));
|
||||
]);
|
||||
}
|
||||
|
||||
// Construct an invite chrome
|
||||
Widget inviteChrome(String chrome, String targetName, String targetId, String myKey) {
|
||||
return Center(
|
||||
widthFactor: 1,
|
||||
child: Row(children: [
|
||||
return Wrap(children: [
|
||||
SelectableText(
|
||||
chrome,
|
||||
focusNode: _focus,
|
||||
chrome + '\u202F',
|
||||
style: TextStyle(
|
||||
color: Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
textWidthBasis: TextWidthBasis.longestLine,
|
||||
maxLines: 2,
|
||||
),
|
||||
SelectableText(
|
||||
targetName,
|
||||
targetName + '\u202F',
|
||||
key: Key(myKey),
|
||||
focusNode: _focus,
|
||||
style: TextStyle(color: Provider.of<Settings>(context).theme.messageFromOtherTextColor()),
|
||||
textAlign: TextAlign.left,
|
||||
maxLines: 2,
|
||||
textWidthBasis: TextWidthBasis.longestLine,
|
||||
)
|
||||
]));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ class _MessageListState extends State<MessageList> {
|
|||
)),
|
||||
Expanded(
|
||||
child: Scrollbar(
|
||||
isAlwaysShown: true,
|
||||
controller: ctrlr1,
|
||||
child: Container(
|
||||
// Only show broken heart is the contact is offline...
|
||||
|
@ -54,7 +53,7 @@ class _MessageListState extends State<MessageList> {
|
|||
child: ListView.builder(
|
||||
controller: ctrlr1,
|
||||
itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages,
|
||||
reverse: true,
|
||||
reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction...
|
||||
itemBuilder: (itemBuilderContext, index) {
|
||||
var trueIndex = Provider.of<ContactInfoState>(outerContext).totalMessages - index - 1;
|
||||
return ChangeNotifierProvider(
|
||||
|
|
|
@ -94,7 +94,10 @@ class _MessageRowState extends State<MessageRow> {
|
|||
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||
|
||||
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact));
|
||||
final snackBar = SnackBar(
|
||||
content: Text(AppLocalizations.of(context)!.successfullAddedContact),
|
||||
duration: Duration(seconds: 2),
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <window_size/window_size_plugin.h>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||
#define GENERATED_PLUGIN_REGISTRANT_
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
version: "2.7.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -191,7 +191,7 @@ packages:
|
|||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -392,7 +392,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
version: "0.4.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -450,7 +450,7 @@ packages:
|
|||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "5.1.2"
|
||||
sdks:
|
||||
dart: ">=2.13.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
|
|
@ -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.0.0+9
|
||||
version: 1.0.0+11
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <window_size/window_size_plugin.h>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||
#define GENERATED_PLUGIN_REGISTRANT_
|
||||
|
||||
|
|
Loading…
Reference in New Issue