From 37e50b95799d30062f29e2a0eb755d58855372fe Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 15 May 2023 13:51:24 -0700 Subject: [PATCH 01/20] Upgrading Dependencies --- .gitignore | 1 + lib/main.dart | 3 +- lib/notification_manager.dart | 26 +- .../pubspec.yaml | 2 +- lib/widgets/filebubble.dart | 7 +- lib/widgets/folderpicker.dart | 5 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 +- pubspec.lock | 234 +++++++----------- pubspec.yaml | 23 +- 9 files changed, 125 insertions(+), 178 deletions(-) diff --git a/.gitignore b/.gitignore index 1a15686e..96b25619 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ package-lock.json libCwtch* cwtch.aar node_modules +test_home # IntelliJ related *.iml diff --git a/lib/main.dart b/lib/main.dart index 356937e6..31199ab6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -84,7 +84,7 @@ class FlwtchState extends State with WindowListener { print("initState: running..."); windowManager.addListener(this); - super.initState(); + print("initState: registering notification, shutdown handlers..."); profs = ProfileListState(); @@ -108,6 +108,7 @@ class FlwtchState extends State with WindowListener { print("initState: invoking cwtch.Start()"); cwtch.Start(); print("initState: done!"); + super.initState(); } // connectivity listening is an optional enhancement feature that tries to listen for OS events about the network diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 00042bcc..dd3acb71 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -6,7 +6,6 @@ import 'package:cwtch/main.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:win_toast/win_toast.dart'; -import 'package:desktop_notifications/desktop_notifications.dart' as linux_notifications; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; import 'package:flutter_local_notifications_linux/src/model/hint.dart'; @@ -33,9 +32,10 @@ class WindowsNotificationManager implements NotificationsManager { bool active = false; bool initialized = false; + // TODO This needs testing and redefining... WindowsNotificationManager() { scheduleMicrotask(() async { - initialized = await WinToast.instance().initialize(appName: 'cwtch', productName: 'Cwtch', companyName: 'Open Privacy Research Society'); + initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); }); } @@ -43,14 +43,14 @@ class WindowsNotificationManager implements NotificationsManager { if (initialized && !globalAppState.focus) { if (!active) { active = true; - WinToast.instance().clear(); - final toast = await WinToast.instance().showToast(type: ToastType.text01, title: message); - toast?.eventStream.listen((event) { - if (event is ActivatedEvent) { - WinToast.instance().bringWindowToFront(); - } + // WinToast.instance().clear(); + //final toast = await WinToast.instance().showToast(toast: Toast(children: ,type: ToastType.text01, title: message)); + //toast?.eventStream.listen((event) { + // if (event is ActivatedEvent) { + // WinToast.instance().bringWindowToFront(); + // } active = false; - }); + // }); } } } @@ -113,12 +113,12 @@ class NixNotificationManager implements NotificationsManager { linuxAssetsPath = ""; } - final MacOSInitializationSettings initializationSettingsMacOS = MacOSInitializationSettings(defaultPresentSound: false); + var linuxIcon = FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: linuxIcon, defaultSuppressSound: true); - final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: initializationSettingsMacOS, linux: initializationSettingsLinux); + final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: DarwinInitializationSettings(defaultPresentSound: false), linux: initializationSettingsLinux); flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( alert: true, @@ -126,7 +126,7 @@ class NixNotificationManager implements NotificationsManager { sound: false, ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: selectNotification); + await flutterLocalNotificationsPlugin.initialize(initializationSettings, ); }); } @@ -138,7 +138,7 @@ class NixNotificationManager implements NotificationsManager { message, '', NotificationDetails( - linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived(), icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))), + linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived, icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))), payload: jsonEncode(NotificationPayload(profile, conversationId))); } } diff --git a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml index 8c4c5efa..9fa6956b 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml +++ b/lib/third_party/connectivity_plus/connectivity_plus_platform_interface/pubspec.yaml @@ -6,7 +6,7 @@ repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ environment: sdk: ">=2.12.0 <3.0.0" - flutter: ">=2.11.0" + flutter: ">=3.7.0" dependencies: flutter: diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index f88237d8..badadf70 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -8,7 +8,7 @@ import 'package:cwtch/models/filedownloadprogress.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/profile.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; -import 'package:file_picker_desktop/file_picker_desktop.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -278,8 +278,9 @@ class FileBubbleState extends State { } } else { try { - selectedFileName = await saveFile( - defaultFileName: widget.nameSuggestion, + selectedFileName = await FilePicker.platform.saveFile( + fileName: widget.nameSuggestion, + lockParentWindow: true, ); if (selectedFileName != null) { file = File(selectedFileName); diff --git a/lib/widgets/folderpicker.dart b/lib/widgets/folderpicker.dart index 52c5cb67..d34335fb 100644 --- a/lib/widgets/folderpicker.dart +++ b/lib/widgets/folderpicker.dart @@ -1,12 +1,7 @@ -import 'package:cwtch/config.dart'; import 'package:cwtch/controllers/filesharing.dart'; -import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/appstate.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'dart:io'; - -import 'package:file_picker_desktop/file_picker_desktop.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; import 'buttontextfield.dart'; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 3dbcbd23..656d31e1 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,7 +7,7 @@ import Foundation import connectivity_plus import flutter_local_notifications -import package_info_plus_macos +import package_info_plus import path_provider_foundation import screen_retriever import url_launcher_macos diff --git a/pubspec.lock b/pubspec.lock index fd020d1b..4518638e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: args - sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" async: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" build_resolvers: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "56942f8114731d1e79942cd981cfef29501937ff1bccf4dbdce0273f31f13640" + sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.3" build_runner_core: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: built_value - sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" + sha256: "2f17434bd5d52a26762043d6b43bb53b3acd029b4d9071a329f46d67ef297e6d" url: "https://pub.dev" source: hosted - version: "8.4.3" + version: "8.5.0" characters: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" cli_util: dependency: transitive description: @@ -219,18 +219,10 @@ packages: dependency: "direct main" description: name: dbus - sha256: "253bfaa3d340778d8bc755e89c3af38e85ef95e65fd5d5670aa3167f8d4f6577" + sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" url: "https://pub.dev" source: hosted - version: "0.7.4" - desktop_notifications: - dependency: "direct main" - description: - name: desktop_notifications - sha256: "6d92694ad6e9297a862c5ff7dd6b8ff64c819972557754769f819d2209612927" - url: "https://pub.dev" - source: hosted - version: "0.6.3" + version: "0.7.8" fake_async: dependency: transitive description: @@ -243,10 +235,10 @@ packages: dependency: "direct main" description: name: ffi - sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18" + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "2.0.2" file: dependency: transitive description: @@ -259,18 +251,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "704259669b5e9cb24e15c11cfcf02caf5f20d30901b3916d60b6d1c2d647035f" + sha256: c7a8e25ca60e7f331b153b0cb3d405828f18d3e72a6fa1d9440c86556fffc877 url: "https://pub.dev" source: hosted - version: "4.6.1" - file_picker_desktop: - dependency: "direct main" - description: - name: file_picker_desktop - sha256: bc802a0fff747071aed0ccdd9b3df827527e46643a18756b2c6bd4b4b4adce20 - url: "https://pub.dev" - source: hosted - version: "1.1.1" + version: "5.3.0" fixnum: dependency: transitive description: @@ -302,26 +286,26 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: "57d0012730780fe137260dd180e072c18a73fbeeb924cdc029c18aaa0f338d64" + sha256: ee6ee56855aa920899b68586b538474d086c149932220b47b92502cbfb5ba5e5 url: "https://pub.dev" source: hosted - version: "9.9.1" + version: "14.0.0+2" flutter_local_notifications_linux: dependency: transitive description: name: flutter_local_notifications_linux - sha256: b472bfc173791b59ede323661eae20f7fff0b6908fea33dd720a6ef5d576bae8 + sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "4.0.0+1" flutter_local_notifications_platform_interface: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "21bceee103a66a53b30ea9daf677f990e5b9e89b62f222e60dd241cd08d63d3a" + sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "7.0.0+1" flutter_localizations: dependency: "direct main" description: flutter @@ -331,10 +315,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + sha256: "96af49aa6b57c10a312106ad6f71deed5a754029c24789bbf620ba784f0bd0b0" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.14" flutter_test: dependency: transitive description: flutter @@ -349,10 +333,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "4f4a162323c86ffc1245765cfe138872b8f069deb42f7dbb36115fa27f31469b" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.2.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -362,10 +346,10 @@ packages: dependency: transitive description: name: get_it - sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" + sha256: "529de303c739fca98cd7ece5fca500d8ff89649f1bb4b4e94fb20954abcd7468" url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "7.6.0" gherkin: dependency: transitive description: @@ -386,18 +370,18 @@ packages: dependency: transitive description: name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + sha256: "772db3d53d23361d4ffcf5a9bb091cf3ee9b22f2be52cd107cd7a2683a89ba0e" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_multi_server: dependency: transitive description: @@ -455,10 +439,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.8.1" logging: dependency: transitive description: @@ -527,50 +511,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "7a6114becdf042be2b0777d77ace954d4a205644171a1cbd8712976b9bbb837c" + sha256: d39e8fbff4c5aef4592737e25ad6ac500df006ce7a7a8e1f838ce1256e167542 url: "https://pub.dev" source: hosted - version: "1.4.2" - package_info_plus_linux: - dependency: transitive - description: - name: package_info_plus_linux - sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - package_info_plus_macos: - dependency: transitive - description: - name: package_info_plus_macos - sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6 - url: "https://pub.dev" - source: hosted - version: "1.3.0" + version: "4.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8 + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" url: "https://pub.dev" source: hosted - version: "1.0.2" - package_info_plus_web: - dependency: transitive - description: - name: package_info_plus_web - sha256: f0829327eb534789e0a16ccac8936a80beed4e2401c4d3a74f3f39094a822d3b - url: "https://pub.dev" - source: hosted - version: "1.0.6" - package_info_plus_windows: - dependency: transitive - description: - name: package_info_plus_windows - sha256: a6040b8695c82f8dd3c3d4dfab7ef96fbe9c67aac21b9bcf5db272589ef84441 - url: "https://pub.dev" - source: hosted - version: "1.0.5" + version: "2.0.1" path: dependency: transitive description: @@ -583,50 +535,50 @@ packages: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.3" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.10" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905 + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.1.6" petitparser: dependency: transitive description: @@ -647,10 +599,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pool: dependency: transitive description: @@ -679,18 +631,18 @@ packages: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.3" qr: dependency: transitive description: @@ -719,26 +671,26 @@ packages: dependency: "direct main" description: name: scrollable_positioned_list - sha256: ca7fcaa743db712d4f7b1580526f494d0093c77a721a65705ee51fbeac7a2bd3 + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" url: "https://pub.dev" source: hosted - version: "0.3.5" + version: "0.3.8" shelf: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -820,10 +772,10 @@ packages: dependency: transitive description: name: timezone - sha256: "57b35f6e8ef731f18529695bffc62f92c6189fac2e52c12d478dec1931afb66e" + sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.9.2" timing: dependency: transitive description: @@ -844,66 +796,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 url: "https://pub.dev" source: hosted - version: "6.1.8" + version: "6.1.11" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: "7aac14be5f4731b923cc697ae2d42043945076cd0dbb8806baecc92c1dc88891" url: "https://pub.dev" source: hosted - version: "6.0.23" + version: "6.0.33" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" url: "https://pub.dev" source: hosted - version: "6.0.18" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" url: "https://pub.dev" source: hosted - version: "2.0.14" + version: "2.0.16" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" uuid: dependency: transitive description: @@ -940,10 +892,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" webdriver: dependency: transitive description: @@ -956,34 +908,34 @@ packages: dependency: transitive description: name: win32 - sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "4.1.4" win_toast: dependency: "direct main" description: name: win_toast - sha256: "6349ef17a487d2ebf9caa51da1cb5a325f4cd7e5a601935ced456f3c00d1e64f" + sha256: "371d62b17b30489cad41e831e6340c2777202d2b4b2fd55a14ffc566b3df7518" url: "https://pub.dev" source: hosted - version: "0.0.2" + version: "0.3.0" window_manager: dependency: "direct main" description: name: window_manager - sha256: d812d3189d23465d2e94baa2505a4462b46dde4939012ff370711c6897d747ae + sha256: "2b2572442b2a5178642730442dc625ac088244f5827b1f0811371b1b7485eb62" url: "https://pub.dev" source: hosted - version: "0.2.9" + version: "0.3.2" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.0.0" xml: dependency: transitive description: @@ -996,10 +948,10 @@ packages: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: dart: ">=2.19.0 <3.0.0" - flutter: ">=3.0.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index c62360bb..2d83cc64 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,13 +18,13 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.11.0+37 environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=2.17.0 <4.0.0" dependencies: flutter: sdk: flutter provider: ^6.0.3 - package_info_plus: ^1.0.0 + package_info_plus: ^4.0.0 #intl_translation: any flutter_localizations: sdk: flutter @@ -32,24 +32,21 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0 - # Todo: upgrade to 2.x, allow other package upgrades (dbus) - ffi: ^1.2.1 + ffi: ^2.0.2 path_provider: ^2.0.0 + # Todo: upgrade to 3.0.3 when integration test is upgraded in flutter gherkin + # Note: This is a non-urgent upgrade as 3.0.3 is only a dart version bump crypto: ^3.0.2 glob: any scrollable_positioned_list: ^0.3.2 - file_picker: ^4.3.2 - file_picker_desktop: ^1.1.1 + file_picker: ^5.3.0 url_launcher: ^6.0.18 - window_manager: ^0.2.8 + window_manager: ^0.3.2 # notification plugins - win_toast: ^0.0.2 - flutter_local_notifications: ^9.6.1 - desktop_notifications: ^0.6.3 - # network management plugins - # dbus >=0.7.5 depends on ffi ^2.0.0 and cwtch depends on ffi ^1.2.1, dbus >=0.7.5 is forbidden. - dbus: 0.7.4 + win_toast: ^0.3.0 + flutter_local_notifications: ^14.0.0+2 + dbus: ^0.7.8 connectivity_plus: path: lib/third_party/connectivity_plus/connectivity_plus # misc plugins From 0567f6029439738729e6b249d19ed259ae1ee89f Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 15 May 2023 14:24:57 -0700 Subject: [PATCH 02/20] Dependency Upgrades --- android/app/build.gradle | 2 +- android/build.gradle | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/l10n/custom_material_delegate.dart | 22 +++ .../connectivity_plus/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/views/contactsview.dart | 2 +- pubspec.lock | 136 +++++++++--------- pubspec.yaml | 12 +- 9 files changed, 106 insertions(+), 78 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c616f190..ab559447 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -53,7 +53,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "im.cwtch.flwtch" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/build.gradle b/android/build.gradle index dcb88e5b..cd6c32c0 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.8.21' repositories { google() // jCenter() no longer exists... https://blog.gradle.org/jcenter-shutdown @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.0.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 42a7a584..7b74e3d3 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,7 +2,7 @@ distributionBase=GRADLE_USER_HOME # third party plugin connectivity_plus should match, so when updating, also update # lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/lib/l10n/custom_material_delegate.dart b/lib/l10n/custom_material_delegate.dart index d5470c54..fd43bb95 100644 --- a/lib/l10n/custom_material_delegate.dart +++ b/lib/l10n/custom_material_delegate.dart @@ -622,4 +622,26 @@ class MaterialLocalizationLu extends MaterialLocalizations { @override // TODO: implement menuBarMenuLabel String get menuBarMenuLabel => throw UnimplementedError(); + + @override + // TODO: implement bottomSheetLabel + String get bottomSheetLabel => throw UnimplementedError(); + + @override + // TODO: implement currentDateLabel + String get currentDateLabel => throw UnimplementedError(); + + @override + // TODO: implement keyboardKeyShift + String get keyboardKeyShift => throw UnimplementedError(); + + @override + // TODO: implement scrimLabel + String get scrimLabel => throw UnimplementedError(); + + @override + String scrimOnTapHint(String modalRouteContentName) { + // TODO: implement scrimOnTapHint + throw UnimplementedError(); + } } diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle index 448c6e91..5fe48e88 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/build.gradle @@ -35,7 +35,7 @@ android { } defaultConfig { - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 31 //testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties index 477dc87d..3b07aa2f 100644 --- a/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties +++ b/lib/third_party/connectivity_plus/connectivity_plus/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 9f189cca..8845b837 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -472,7 +472,7 @@ class _ContactsViewState extends State { builder: (BuildContext context) { return Wrap(children: [ Center( - child: QrImage( + child: QrImageView( data: profile_code, version: QrVersions.auto, size: 400.0, diff --git a/pubspec.lock b/pubspec.lock index 4518638e..40907f70 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8" + sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07" url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "60.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80" + sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "5.12.0" archive: dependency: transitive description: name: archive - sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.2" + version: "3.3.7" args: dependency: transitive description: @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" build_config: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "4.0.0" build_resolvers: dependency: transitive description: @@ -85,18 +85,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.4" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + sha256: "30859c90e9ddaccc484f56303931f477b1f1ba2bab74aa32ed5d6ce15870f8cf" url: "https://pub.dev" source: hosted - version: "7.2.7" + version: "7.2.8" built_collection: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: cli_util - sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 url: "https://pub.dev" source: hosted - version: "0.3.5" + version: "0.4.0" clock: dependency: transitive description: @@ -157,10 +157,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" connectivity_plus: dependency: "direct main" description: @@ -195,10 +195,10 @@ packages: dependency: "direct main" description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -251,10 +251,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: c7a8e25ca60e7f331b153b0cb3d405828f18d3e72a6fa1d9440c86556fffc877 + sha256: e6c7ad8e572379df86ea64ef0a5395889fba3954411d47ca021b888d79f8e798 url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.2.11" fixnum: dependency: transitive description: @@ -276,11 +276,9 @@ packages: flutter_gherkin: dependency: "direct dev" description: - path: "." - ref: main - resolved-ref: bc846ee4df720288a17b8455ec4cc1ccbe90ecdb - url: "https://git.openprivacy.ca/openprivacy/flutter_gherkin" - source: git + path: flutter_gherkin + relative: true + source: path version: "3.0.0-rc.17" flutter_local_notifications: dependency: "direct main" @@ -402,10 +400,10 @@ packages: dependency: transitive description: name: image - sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "4.0.17" integration_test: dependency: transitive description: flutter @@ -415,10 +413,10 @@ packages: dependency: transitive description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.0" io: dependency: transitive description: @@ -431,10 +429,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -455,10 +453,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -471,10 +469,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: @@ -487,10 +485,10 @@ packages: dependency: "direct dev" description: name: msix - sha256: e3de4d9f52543ad6e4b0f534991e1303cbd379d24be28dd241ac60bd9439a201 + sha256: "88ee83949d87dc635ffd51d7c17ef222390e5067693cc248046661b12a353d13" url: "https://pub.dev" source: hosted - version: "3.7.0" + version: "3.12.2" nested: dependency: transitive description: @@ -527,10 +525,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: "direct main" description: @@ -583,10 +581,10 @@ packages: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.4.0" platform: dependency: transitive description: @@ -603,6 +601,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" pool: dependency: transitive description: @@ -647,18 +653,18 @@ packages: dependency: transitive description: name: qr - sha256: "5c4208b4dc0d55c3184d10d83ee0ded6212dc2b5e2ba17c5a0c0aab279128d21" + sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.1" qr_flutter: dependency: "direct main" description: name: qr_flutter - sha256: c5c121c54cb6dd837b9b9d57eb7bc7ec6df4aee741032060c8833a678c80b87e + sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" screen_retriever: dependency: transitive description: @@ -764,10 +770,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" timezone: dependency: transitive description: @@ -788,10 +794,10 @@ packages: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" url_launcher: dependency: "direct main" description: @@ -876,18 +882,18 @@ packages: dependency: transitive description: name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "11.3.0" watcher: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" web_socket_channel: dependency: transitive description: @@ -900,10 +906,10 @@ packages: dependency: transitive description: name: webdriver - sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841 + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" win32: dependency: transitive description: @@ -940,10 +946,10 @@ packages: dependency: transitive description: name: xml - sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" yaml: dependency: transitive description: @@ -953,5 +959,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=2.19.0 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2d83cc64..c80e8298 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: glob: any scrollable_positioned_list: ^0.3.2 - file_picker: ^5.3.0 + file_picker: 5.2.11 url_launcher: ^6.0.18 window_manager: ^0.3.2 # notification plugins @@ -53,13 +53,13 @@ dependencies: qr_flutter: ^4.0.0 dev_dependencies: - msix: ^3.6.2 + msix: ^3.12.2 build_runner: any flutter_gherkin: - #path: ./flutter_gherkin - git: - url: https://git.openprivacy.ca/openprivacy/flutter_gherkin - ref: main + path: ./flutter_gherkin + # git: + # url: https://git.openprivacy.ca/openprivacy/flutter_gherkin + # ref: main # Uncomment to update lokalise translations (see README for list of deps to comment out bc incompatibilities) #dev_dependencies: From 42d2e8e825149e0b8c19b9f39cece61d6344793a Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 15 May 2023 14:26:48 -0700 Subject: [PATCH 03/20] Use git flutter gherkin --- pubspec.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index c80e8298..e631836b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -56,10 +56,10 @@ dev_dependencies: msix: ^3.12.2 build_runner: any flutter_gherkin: - path: ./flutter_gherkin - # git: - # url: https://git.openprivacy.ca/openprivacy/flutter_gherkin - # ref: main + #path: ./flutter_gherkin + git: + url: https://git.openprivacy.ca/openprivacy/flutter_gherkin + ref: main # Uncomment to update lokalise translations (see README for list of deps to comment out bc incompatibilities) #dev_dependencies: From 2c0e0e16f2d6fd66c7f390089b601897604eda1f Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 15 May 2023 14:31:50 -0700 Subject: [PATCH 04/20] Upgrade .lock --- pubspec.lock | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 40907f70..bec166ba 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -276,9 +276,11 @@ packages: flutter_gherkin: dependency: "direct dev" description: - path: flutter_gherkin - relative: true - source: path + path: "." + ref: main + resolved-ref: "9e89cc0d89770242a3c2e86573f9618a0dd49194" + url: "https://git.openprivacy.ca/openprivacy/flutter_gherkin" + source: git version: "3.0.0-rc.17" flutter_local_notifications: dependency: "direct main" From 471ab9674302a94eeae67f581264a1ef6fb92024 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Mon, 22 May 2023 12:54:40 -0700 Subject: [PATCH 05/20] windows fixes: especially new version of win toast --- lib/main.dart | 11 ++- lib/notification_manager.dart | 122 ++++++++++++++++++++++++------- windows/nsis/cwtch-installer.nsi | 2 +- windows/runner/Runner.rc | 10 +-- 4 files changed, 109 insertions(+), 36 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 31199ab6..94309a3d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -44,6 +44,8 @@ Future main() async { print("Cwtch version: ${EnvironmentConfig.BUILD_VER} built on: ${EnvironmentConfig.BUILD_DATE}"); LicenseRegistry.addLicense(() => licenses()); WidgetsFlutterBinding.ensureInitialized(); + // window_manager requires (await recommended but probably not required if not using immediately) + windowManager.ensureInitialized(); print("runApp()"); return runApp(Flwtch()); } @@ -104,9 +106,10 @@ class FlwtchState extends State with WindowListener { new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); cwtch = CwtchFfi(cwtchNotifier); } - startConnectivityListener(); print("initState: invoking cwtch.Start()"); cwtch.Start(); + print("initState: starting connectivityListener"); + startConnectivityListener(); print("initState: done!"); super.initState(); } @@ -288,7 +291,8 @@ class FlwtchState extends State with WindowListener { ); // On Gnome follows up a clicked notification with a "Cwtch is ready" notification that takes you to the app. AFAICT just because Gnome is bad // https://askubuntu.com/questions/1286206/how-to-skip-the-is-ready-notification-and-directly-open-apps-in-ubuntu-20-4 - windowManager.focus(); + await windowManager.show(); + await windowManager.focus(); } // using windowManager flutter plugin until proper lifecycle management lands in desktop @@ -303,6 +307,9 @@ class FlwtchState extends State with WindowListener { globalAppState.focus = false; } + void onWindowClose() { + } + @override void dispose() { globalAppState.SetModalState(ModalState.shutdown); diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index dd3acb71..34ffe402 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -23,7 +23,8 @@ abstract class NotificationsManager { // NullNotificationsManager ignores all notification requests class NullNotificationsManager implements NotificationsManager { @override - Future notify(String message, String profile, int conversationId) async {} + Future notify( + String message, String profile, int conversationId) async {} } // Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement @@ -31,11 +32,32 @@ class NullNotificationsManager implements NotificationsManager { class WindowsNotificationManager implements NotificationsManager { bool active = false; bool initialized = false; + late Future Function(String, int) notificationSelectConvo; - // TODO This needs testing and redefining... - WindowsNotificationManager() { + + WindowsNotificationManager(Future Function(String, int) notificationSelectConvo) { + this.notificationSelectConvo = notificationSelectConvo; scheduleMicrotask(() async { - initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); + //initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); + // initialize toast with you aumId, displayName and iconPath + var init = await WinToast.instance().initialize( + aumId: 'OpenPrivacyResearchSociety.Cwtch', + displayName: 'Cwtch', + iconPath: '', // TODO NEED ICON + clsid: 'cwtch', + ); + WinToast.instance().setActivatedCallback((event) { + if (event.argument != "close") { + try { + Map payloadMap = jsonDecode(event.argument); + var payload = NotificationPayload.fromJson(payloadMap); + notificationSelectConvo(payload.profileOnion, payload.convoId); + } catch (e) { + /* it failed, is ok, may have been 'close'? */ + } + } + }); + initialized = true; }); } @@ -43,14 +65,31 @@ class WindowsNotificationManager implements NotificationsManager { if (initialized && !globalAppState.focus) { if (!active) { active = true; - // WinToast.instance().clear(); - //final toast = await WinToast.instance().showToast(toast: Toast(children: ,type: ToastType.text01, title: message)); - //toast?.eventStream.listen((event) { - // if (event is ActivatedEvent) { - // WinToast.instance().bringWindowToFront(); - // } - active = false; - // }); + WinToast.instance().clear(); + await WinToast.instance().showToast( + toast: Toast( + duration: ToastDuration.short, + children: [ + ToastChildAudio(source: ToastAudioSource.im), + ToastChildVisual( + binding: ToastVisualBinding(children: [ + ToastVisualBindingChildText( + text: message, + id: 1, + ), + ])), + ToastChildActions(children: [ + ToastAction( + content: "Open", + arguments: jsonEncode(NotificationPayload(profile, conversationId)), + ), + ToastAction( + content: "Close", + arguments: "close", + ), + ]), + ])); + active = false; } } } @@ -87,7 +126,8 @@ class NixNotificationManager implements NotificationsManager { Future detectLinuxAssetsPath() async { var devStat = FileStat.stat("assets"); var localStat = FileStat.stat("data/flutter_assets"); - var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets"); + var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + + "/.local/share/cwtch/data/flutter_assets"); var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets"); if ((await devStat).type == FileSystemEntityType.directory) { @@ -95,14 +135,16 @@ class NixNotificationManager implements NotificationsManager { } else if ((await localStat).type == FileSystemEntityType.directory) { return path.join(Directory.current.path, "data/flutter_assets/"); } else if ((await homeStat).type == FileSystemEntityType.directory) { - return (Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets/"; + return (Platform.environment["HOME"] ?? "") + + "/.local/share/cwtch/data/flutter_assets/"; } else if ((await rootStat).type == FileSystemEntityType.directory) { return "/usr/share/cwtch/data/flutter_assets/"; } return ""; } - NixNotificationManager(Future Function(String, int) notificationSelectConvo) { + NixNotificationManager( + Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -113,24 +155,39 @@ class NixNotificationManager implements NotificationsManager { linuxAssetsPath = ""; } + var linuxIcon = + FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); - var linuxIcon = FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); + final LinuxInitializationSettings initializationSettingsLinux = + LinuxInitializationSettings( + defaultActionName: 'Open notification', + defaultIcon: linuxIcon, + defaultSuppressSound: true); - final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: linuxIcon, defaultSuppressSound: true); + final InitializationSettings initializationSettings = + InitializationSettings( + android: null, + iOS: null, + macOS: DarwinInitializationSettings(defaultPresentSound: false), + linux: initializationSettingsLinux); - final InitializationSettings initializationSettings = InitializationSettings(android: null, iOS: null, macOS: DarwinInitializationSettings(defaultPresentSound: false), linux: initializationSettingsLinux); - - flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( + flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + MacOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( alert: true, badge: false, sound: false, ); - await flutterLocalNotificationsPlugin.initialize(initializationSettings, ); + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + ); }); } - Future notify(String message, String profile, int conversationId) async { + Future notify( + String message, String profile, int conversationId) async { if (!globalAppState.focus) { // Warning: Only use title field on Linux, body field will render links as clickable await flutterLocalNotificationsPlugin.show( @@ -138,7 +195,11 @@ class NixNotificationManager implements NotificationsManager { message, '', NotificationDetails( - linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived, icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))), + linux: LinuxNotificationDetails( + suppressSound: true, + category: LinuxNotificationCategory.imReceived, + icon: FilePathLinuxIcon( + path.join(linuxAssetsPath, 'assets/knott.png')))), payload: jsonEncode(NotificationPayload(profile, conversationId))); } } @@ -153,7 +214,9 @@ class NixNotificationManager implements NotificationsManager { } } -NotificationsManager newDesktopNotificationsManager(Future Function(String profileOnion, int convoId) notificationSelectConvo) { +NotificationsManager newDesktopNotificationsManager( + Future Function(String profileOnion, int convoId) + notificationSelectConvo) { // We don't want notifications in Dev Mode if (EnvironmentConfig.TEST_MODE) { return NullNotificationsManager(); @@ -163,19 +226,22 @@ NotificationsManager newDesktopNotificationsManager(Future Function(String try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create LinuxNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog( + "Failed to create LinuxNotificationManager. Switching off notifications."); } } else if (Platform.isMacOS) { try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create NixNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog( + "Failed to create NixNotificationManager. Switching off notifications."); } } else if (Platform.isWindows) { try { - return WindowsNotificationManager(); + return WindowsNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog("Failed to create Windows desktoasts notification manager"); + EnvironmentConfig.debugLog( + "Failed to create Windows desktoasts notification manager"); } } diff --git a/windows/nsis/cwtch-installer.nsi b/windows/nsis/cwtch-installer.nsi index b9a3b274..a0495a97 100644 --- a/windows/nsis/cwtch-installer.nsi +++ b/windows/nsis/cwtch-installer.nsi @@ -81,7 +81,7 @@ ShowInstDetails show Section # define the output path for this file - SetOutPath $INSTDIR + SetOutPath "$INSTDIR" # define what to install and place it in the output path # Filler for .sh to populate with contents of deploy/windows diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index d0b33234..ec59a28f 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -69,14 +69,14 @@ IDI_APP_ICON_16 ICON "resources\\knot_16.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif From 38ec143ef6c7fb35fb14e0c6a7524918e8975adb Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Sun, 28 May 2023 10:04:28 -0700 Subject: [PATCH 06/20] build updates for macos flutter 3.10 --- .metadata | 24 ++++++++++- README.md | 8 +++- ios/Flutter/Debug.xcconfig | 1 + ios/Flutter/Release.xcconfig | 1 + macos/Podfile | 2 +- macos/Podfile.lock | 42 ++++++++++++------- macos/Runner.xcodeproj/project.pbxproj | 11 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- 8 files changed, 66 insertions(+), 25 deletions(-) diff --git a/.metadata b/.metadata index 182cccaf..b5d8c1fe 100644 --- a/.metadata +++ b/.metadata @@ -1,10 +1,30 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: 78910062997c3a836feee883712c241a5fd22983 + revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf channel: stable project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + - platform: macos + create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/README.md index 86c50e26..93473bbd 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,14 @@ To build a release version and load normal profiles, use `build-release.sh X` in ### Building on MacOS -- Cocaopods is required, you may need to `gem install cocaopods -v 1.9.3` -- copy `libCwtch.x64.dylib` and `libCwtch.arm/dylib` into the root folder, or run `fetch-libcwtch-go-macos.sh` to download it +- Cocoapods is required. Mac and Ruby don't seem to care about version stability and compatibility so good luck. The version of Ruby Mac seems to ship is very incompatible with software in the gem repo. You will probablly need to manually specify a specific older version of cocoapods that is compatible with your system. First you will also probably need to make sure you are on the latest MacOS version and then try `gem install cocoapods -v 1.x.x` + - For MacOS 13.4 `gem install cocoapods -v 1.11.3` worked on 2023.05.28 +- copy `libCwtch.x64.dylib` and `libCwtch.arm.dylib` into the root folder, or run `fetch-libcwtch-go-macos.sh` to download it + - The error 'Podfile not found' has still been seen on fresh repos, depending on varios versions. To fix run `flutter create --platforms=macos . --org im.cwtch` + - You may have to temporarily rename the project folder a "dart project suitable name" like "cwtch" - run `fetch-tor-macos.sh` to fetch Tor or Download and install Tor Browser and `cp -r /Applications/Tor\ Browser.app/Contents/MacOS/Tor ./macos/` - `flutter build macos` + - If you are building on Mac Arm Silicon you may need to append `--no-tree-shake-icons` as the build seems to invoke a mac x64 binary that Arm Mac "cannot verify" and therefor will not run on some versions of Flutter - optional: launch cwtch-ui release build with `./build/macos/Build/Products/Release/Cwtch.app/Contents/MacOS/Cwtch` - To package the UI: `./macos/package-release.sh`, which results in a Cwtch.dmg that has libCwtch.dylib and tor in it as well and can be installed into Applications diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee8..ec97fc6f 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee8..c4855bfe 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/macos/Podfile b/macos/Podfile index dade8dfa..049abe29 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.11' +platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 5ead0ac0..dd995ef1 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,11 +1,16 @@ PODS: + - connectivity_plus (0.0.1): + - FlutterMacOS + - ReachabilitySwift - flutter_local_notifications (0.0.1): - FlutterMacOS - FlutterMacOS (1.0.0) - - package_info_plus_macos (0.0.1): + - package_info_plus (0.0.1): - FlutterMacOS - - path_provider_macos (0.0.1): + - path_provider_foundation (0.0.1): + - Flutter - FlutterMacOS + - ReachabilitySwift (5.0.0) - screen_retriever (0.0.1): - FlutterMacOS - url_launcher_macos (0.0.1): @@ -14,23 +19,30 @@ PODS: - FlutterMacOS DEPENDENCIES: + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) - - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) +SPEC REPOS: + trunk: + - ReachabilitySwift + EXTERNAL SOURCES: + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos flutter_local_notifications: :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos FlutterMacOS: :path: Flutter/ephemeral - package_info_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos - path_provider_macos: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin screen_retriever: :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos url_launcher_macos: @@ -39,14 +51,16 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos SPEC CHECKSUMS: + connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 - FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 - package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c - path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 + ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 - url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 + url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 -PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c +PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 55cfcda1..189068fc 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -202,7 +202,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -255,6 +255,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -403,7 +404,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -483,7 +484,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -530,7 +531,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 35f5d0f8..11487c24 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 29 May 2023 10:21:21 -0700 Subject: [PATCH 07/20] update drone to flutter 3.10 containers --- .drone.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.drone.yml b/.drone.yml index a775a2a5..1c953c50 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,7 +8,7 @@ clone: steps: - name: clone - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 environment: buildbot_key_b64: from_secret: buildbot_key_b64 @@ -24,7 +24,7 @@ steps: - git checkout $DRONE_COMMIT - name: fetch - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 volumes: - name: deps path: /root/.pub-cache @@ -47,7 +47,7 @@ steps: # #Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting - name: build-linux - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 volumes: - name: deps path: /root/.pub-cache @@ -61,7 +61,7 @@ steps: - rm -r cwtch - name: linux-ui-tests - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 volumes: - name: deps path: /root/.pub-cache @@ -70,7 +70,7 @@ steps: - ./run-tests-headless.sh "01_general|02_global_settings|04_profile_mgmt" - name: test-build-android - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 when: event: pull_request volumes: @@ -80,7 +80,7 @@ steps: - flutter build apk --debug - name: build-android - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 when: event: push environment: @@ -104,7 +104,7 @@ steps: #- cp build/app/outputs/flutter-apk/app-debug.apk deploy/android - name: widget-tests - image: openpriv/flutter-desktop:linux-fstable-3.7.1 + image: openpriv/flutter-desktop:linux-fstable-3.10.2 volumes: - name: deps path: /root/.pub-cache @@ -177,7 +177,7 @@ clone: steps: - name: clone - image: openpriv/flutter-desktop:windows-sdk30-fstable-3.7.1 + image: openpriv/flutter-desktop:windows-sdk30-fstable-3.10.2 environment: buildbot_key_b64: from_secret: buildbot_key_b64 @@ -195,7 +195,7 @@ steps: - git checkout $Env:DRONE_COMMIT - name: fetch - image: openpriv/flutter-desktop:windows-sdk30-fstable-3.7.1 + image: openpriv/flutter-desktop:windows-sdk30-fstable-3.10.2 commands: - git describe --tags --abbrev=1 > VERSION - git log -1 --format=%cd --date=format:'%Y-%m-%d-%H-%M' > COMMIT_DATE @@ -203,7 +203,7 @@ steps: - .\fetch-libcwtch-go.ps1 - name: build-windows - image: openpriv/flutter-desktop:windows-sdk30-fstable-3.7.1 + image: openpriv/flutter-desktop:windows-sdk30-fstable-3.10.2 commands: - flutter pub get - $Env:version += type .\VERSION @@ -260,7 +260,7 @@ steps: - move *.sha512.txt deploy\$Env:builddir - name: deploy-windows - image: openpriv/flutter-desktop:windows-sdk30-fstable-3.7.1 + image: openpriv/flutter-desktop:windows-sdk30-fstable-3.10.2 when: event: push status: [ success ] From 90625eacb568e67a465e0d3843b3e8b7299de16a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 2 Jun 2023 10:02:38 -0700 Subject: [PATCH 08/20] revert win toast to 0.0.2 --- lib/notification_manager.dart | 24 ++++++++++++++++++++---- pubspec.lock | 4 ++-- pubspec.yaml | 6 +++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 34ffe402..95fe93ef 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -38,8 +38,10 @@ class WindowsNotificationManager implements NotificationsManager { WindowsNotificationManager(Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; scheduleMicrotask(() async { - //initialized = await WinToast.instance().initialize(clsid: 'cwtch', displayName: 'Cwtch', aumId: 'Open Privacy Research Society', iconPath: ''); - // initialize toast with you aumId, displayName and iconPath + initialized = await WinToast.instance().initialize(appName: 'cwtch', productName: 'Cwtch', companyName: 'Open Privacy Research Society'); + /* + * WinToast 0.3.0 code for when we can compile it + * var init = await WinToast.instance().initialize( aumId: 'OpenPrivacyResearchSociety.Cwtch', displayName: 'Cwtch', @@ -56,7 +58,7 @@ class WindowsNotificationManager implements NotificationsManager { /* it failed, is ok, may have been 'close'? */ } } - }); + });*/ initialized = true; }); } @@ -65,6 +67,20 @@ class WindowsNotificationManager implements NotificationsManager { if (initialized && !globalAppState.focus) { if (!active) { active = true; + WinToast.instance().clear(); + final toast = await WinToast.instance().showToast( + type: ToastType.text01, title: message); + toast?.eventStream.listen((event) { + if (event is ActivatedEvent) { + WinToast.instance().bringWindowToFront(); + } + active = false; + }); + } + + /* + * WinToast 0.3.0 code for when we can compile it + * WinToast.instance().clear(); await WinToast.instance().showToast( toast: Toast( @@ -90,7 +106,7 @@ class WindowsNotificationManager implements NotificationsManager { ]), ])); active = false; - } + }*/ } } } diff --git a/pubspec.lock b/pubspec.lock index bec166ba..91de4add 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -924,10 +924,10 @@ packages: dependency: "direct main" description: name: win_toast - sha256: "371d62b17b30489cad41e831e6340c2777202d2b4b2fd55a14ffc566b3df7518" + sha256: "6349ef17a487d2ebf9caa51da1cb5a325f4cd7e5a601935ced456f3c00d1e64f" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.0.2" window_manager: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e631836b..989ec65f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,7 +44,11 @@ dependencies: url_launcher: ^6.0.18 window_manager: ^0.3.2 # notification plugins - win_toast: ^0.3.0 + ## Somewhere between 0.0.2 and 0.3 they introduced a dependancy on a new Windows RT feature + ## Which can only be linked to with a new VC 17 compiler and we're suspicious only work on + ## Windows 2022 and newer... we can't seem to automate compiling on win server 2019 containers + ## So pinning to 0.0.2 for the forseeable future or until we change plugins + win_toast: ^0.0.2 flutter_local_notifications: ^14.0.0+2 dbus: ^0.7.8 connectivity_plus: From 7f500369687274e1b2225b628cb48ced0feab633 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 2 Jun 2023 12:30:02 -0700 Subject: [PATCH 09/20] drone win cp files from right place --- .drone.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.drone.yml b/.drone.yml index 1c953c50..04d8203d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -214,9 +214,9 @@ steps: # 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.30133\x64\Microsoft.VC142.CRT\vcruntime140.dll $Env:releasedir - - copy C:\BuildTools\VC\Redist\MSVC\14.29.30133\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:releasedir - - copy C:\BuildTools\VC\Redist\MSVC\14.29.30133\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:releasedir + - copy 'C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Redist\MSVC\14.36.32532\x64\Microsoft.VC143.CRT\vcruntime140.dll' $Env:releasedir + - copy 'C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Redist\MSVC\14.36.32532\x64\Microsoft.VC143.CRT\vcruntime140_1.dll' $Env:releasedir + - copy 'C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Redist\MSVC\14.36.32532\x64\Microsoft.VC143.CRT\msvcp140.dll' $Env:releasedir - copy README.md $Env:releasedir\ - copy windows\*.bat $Env:releasedir\ - powershell -command "Expand-Archive -Path tor.zip -DestinationPath $Env:releasedir\Tor" From 22bf5cfe923787254300169f306213e9d2a9ac06 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 11:15:13 -0700 Subject: [PATCH 10/20] Small UI Fixes / Font Styles / Abstractions --- .../kotlin/im/cwtch/flwtch/MainActivity.kt | 17 ++-- lib/controllers/open_link_modal.dart | 32 +++--- lib/cwtch/cwtch.dart | 4 +- lib/cwtch/cwtchNotifier.dart | 26 ++--- lib/cwtch/ffi.dart | 12 +-- lib/cwtch/gomobile.dart | 28 +++--- lib/main.dart | 4 +- lib/models/contact.dart | 9 ++ lib/models/message_draft.dart | 24 ++++- lib/notification_manager.dart | 97 +++++++------------ lib/settings.dart | 5 + lib/themes/opaque.dart | 6 ++ lib/views/messageview.dart | 60 ++++++------ lib/widgets/cwtchlabel.dart | 3 +- lib/widgets/filebubble.dart | 97 ++++++------------- lib/widgets/invitationbubble.dart | 46 +++++---- lib/widgets/messageBubbleWidgetHelpers.dart | 48 +++++++++ lib/widgets/messagebubble.dart | 53 +--------- lib/widgets/messagerow.dart | 3 +- lib/widgets/quotedmessage.dart | 49 +--------- lib/widgets/staticmessagebubble.dart | 8 +- 21 files changed, 290 insertions(+), 341 deletions(-) create mode 100644 lib/widgets/messageBubbleWidgetHelpers.dart diff --git a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt index d17f83ec..c4cdda25 100644 --- a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt +++ b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt @@ -360,8 +360,7 @@ class MainActivity: FlutterActivity() { "PeerWithOnion" -> { val profile: String = call.argument("ProfileOnion") ?: "" val onion: String = call.argument("onion") ?: "" - result.success(Cwtch.peerWithOnion(profile, onion)) - return + Cwtch.peerWithOnion(profile, onion) } @@ -493,14 +492,17 @@ class MainActivity: FlutterActivity() { } "GetProfileAttribute" -> { val profile: String = call.argument("ProfileOnion") ?: "" - val key: String = call.argument("Key") ?: "" - Data.Builder().putString("result", Cwtch.getProfileAttribute(profile, key)).build() + val key: String = call.argument("key") ?: "" + var resultjson = Cwtch.getProfileAttribute(profile, key); + return result.success(resultjson) } "GetConversationAttribute" -> { val profile: String = call.argument("ProfileOnion") ?: "" val conversation: Int = call.argument("conversation") ?: 0 - val key: String = call.argument("Key") ?: "" - Data.Builder().putString("result", Cwtch.getConversationAttribute(profile, conversation.toLong(), key)).build() + val key: String = call.argument("key") ?: "" + var resultjson = Cwtch.getConversationAttribute(profile, conversation.toLong(), key); + result.success(resultjson) + return } "SetConversationAttribute" -> { val profile: String = call.argument("ProfileOnion") ?: "" @@ -512,7 +514,8 @@ class MainActivity: FlutterActivity() { "ImportProfile" -> { val file: String = call.argument("file") ?: "" val pass: String = call.argument("pass") ?: "" - Data.Builder().putString("result", Cwtch.importProfile(file, pass)).build() + result.success(Cwtch.importProfile(file, pass)) + return } "ReconnectCwtchForeground" -> { Cwtch.reconnectCwtchForeground() diff --git a/lib/controllers/open_link_modal.dart b/lib/controllers/open_link_modal.dart index 7b021f6d..c770bcb6 100644 --- a/lib/controllers/open_link_modal.dart +++ b/lib/controllers/open_link_modal.dart @@ -1,16 +1,20 @@ +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/third_party/linkify/linkify.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:url_launcher/url_launcher.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +import '../settings.dart'; void modalOpenLink(BuildContext ctx, LinkableElement link) { showModalBottomSheet( context: ctx, builder: (BuildContext bcontext) { return Container( - height: 200, // bespoke value courtesy of the [TextField] docs + height: 200, child: Center( child: Padding( padding: EdgeInsets.all(30.0), @@ -18,17 +22,24 @@ void modalOpenLink(BuildContext ctx, LinkableElement link) { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - Text(AppLocalizations.of(bcontext)!.clickableLinksWarning), + Text( + AppLocalizations.of(bcontext)!.clickableLinksWarning, + style: Provider.of(bcontext).scaleFonts(defaultTextStyle), + ), Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10), child: ElevatedButton( - child: Text(AppLocalizations.of(bcontext)!.clickableLinksCopy, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinksCopy), + child: Text(AppLocalizations.of(bcontext)!.clickableLinksCopy, + style: Provider.of(bcontext).scaleFonts(defaultTextButtonStyle), semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinksCopy), onPressed: () { Clipboard.setData(new ClipboardData(text: link.url)); final snackBar = SnackBar( - content: Text(AppLocalizations.of(bcontext)!.copiedToClipboardNotification), + content: Text( + AppLocalizations.of(bcontext)!.copiedToClipboardNotification, + style: Provider.of(bcontext).scaleFonts(defaultTextButtonStyle), + ), ); Navigator.pop(bcontext); @@ -39,15 +50,14 @@ void modalOpenLink(BuildContext ctx, LinkableElement link) { Container( margin: EdgeInsets.symmetric(vertical: 20, horizontal: 10), child: ElevatedButton( - child: Text(AppLocalizations.of(bcontext)!.clickableLinkOpen, semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinkOpen), + child: Text(AppLocalizations.of(bcontext)!.clickableLinkOpen, + style: Provider.of(bcontext).scaleFonts(defaultTextButtonStyle), semanticsLabel: AppLocalizations.of(bcontext)!.clickableLinkOpen), onPressed: () async { - if (await canLaunch(link.url)) { - await launch(link.url); + if (await canLaunchUrlString(link.url)) { + await launchUrlString(link.url); Navigator.pop(bcontext); } else { - final snackBar = SnackBar( - content: Text(AppLocalizations.of(bcontext)!.clickableLinkError), - ); + final snackBar = SnackBar(content: Text(AppLocalizations.of(bcontext)!.clickableLinkError, style: Provider.of(bcontext).scaleFonts(defaultTextButtonStyle))); ScaffoldMessenger.of(bcontext).showSnackBar(snackBar); } }, diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index 0ca8c851..98e4fac5 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -97,11 +97,11 @@ abstract class Cwtch { Future ImportBundle(String profile, String bundle); // ignore: non_constant_identifier_names void SetProfileAttribute(String profile, String key, String val); - String? GetProfileAttribute(String profile, String key); + Future GetProfileAttribute(String profile, String key); // ignore: non_constant_identifier_names void SetConversationAttribute(String profile, int conversation, String key, String val); // ignore: non_constant_identifier_names - String? GetConversationAttribute(String profile, int identifier, String s); + Future GetConversationAttribute(String profile, int identifier, String s); // ignore: non_constant_identifier_names void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val); // ignore: non_constant_identifier_names diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index e2c2b4db..5788e41e 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -59,6 +59,8 @@ class CwtchNotifier { } void handleMessage(String type, dynamic data) { + EnvironmentConfig.debugLog("Handing Message $type ${data.toString()}"); + //EnvironmentConfig.debugLog("NewEvent $type $data"); switch (type) { case "CwtchStarted": @@ -68,25 +70,24 @@ class CwtchNotifier { appState.SetAppError(data["Error"]); break; case "NewPeer": - // empty events can be caused by the testing framework - if (data["Online"] == null) { - break; - } // EnvironmentConfig.debugLog("NewPeer $data"); // if tag != v1-defaultPassword then it is either encrypted OR it is an unencrypted account created during pre-beta... profileCN.add(data["Identity"], data["name"], data["picture"], data["defaultPicture"], data["ContactsJson"], data["ServerList"], data["Online"] == "true", data["autostart"] == "true", data["tag"] != "v1-defaultPassword"); // Update Profile Attributes - profileCN.getProfile(data["Identity"])?.setAttribute(0, flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-1")); - profileCN.getProfile(data["Identity"])?.setAttribute(1, flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-2")); - profileCN.getProfile(data["Identity"])?.setAttribute(2, flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-3")); - profileCN.getProfile(data["Identity"])?.setAvailabilityStatus(flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-status") ?? ""); + EnvironmentConfig.debugLog("Looking up Profile Attributes ${data["Identity"]} ${profileCN.getProfile(data["Identity"])}"); + flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-1").then((value) => profileCN.getProfile(data["Identity"])?.setAttribute(0, value)); + flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-2").then((value) => profileCN.getProfile(data["Identity"])?.setAttribute(1, value)); + flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-attribute-3").then((value) => profileCN.getProfile(data["Identity"])?.setAttribute(2, value)); + flwtchState.cwtch.GetProfileAttribute(data["Identity"], "profile.profile-status").then((value) => profileCN.getProfile(data["Identity"])?.setAvailabilityStatus(value ?? "")); + + EnvironmentConfig.debugLog("Looking up Profile Information for Contact..."); profileCN.getProfile(data["Identity"])?.contactList.contacts.forEach((contact) { - contact.setAttribute(0, flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-1")); - contact.setAttribute(1, flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-2")); - contact.setAttribute(2, flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-3")); - contact.setAvailabilityStatus(flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-status") ?? ""); + flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-1").then((value) => contact.setAttribute(0, value)); + flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-2").then((value) => contact.setAttribute(1, value)); + flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-attribute-3").then((value) => contact.setAttribute(2, value)); + flwtchState.cwtch.GetConversationAttribute(data["Identity"], contact.identifier, "public.profile.profile-status").then((value) => contact.setAvailabilityStatus(value ?? "")); }); break; @@ -392,6 +393,7 @@ class CwtchNotifier { String fileKey = data['Data']; var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]); if (contact != null) { + EnvironmentConfig.debugLog("waiting for download from $contact"); profileCN.getProfile(data["ProfileOnion"])?.waitForDownloadComplete(contact.identifier, fileKey); } } else if (data['Path'] == "profile.profile-attribute-1" || data['Path'] == "profile.profile-attribute-2" || data['Path'] == "profile.profile-attribute-3") { diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index 086760c9..10a4414a 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -967,7 +967,7 @@ class CwtchFfi implements Cwtch { } @override - String? GetProfileAttribute(String profile, String key) { + Future GetProfileAttribute(String profile, String key) { var getProfileAttributeC = library.lookup>("c_GetProfileAttribute"); // ignore: non_constant_identifier_names final GetProfileAttribute = getProfileAttributeC.asFunction(); @@ -982,17 +982,17 @@ class CwtchFfi implements Cwtch { try { dynamic attributeResult = json.decode(jsonMessage); if (attributeResult["Exists"]) { - return attributeResult["Value"]; + return Future.value(attributeResult["Value"]); } } catch (e) { EnvironmentConfig.debugLog("error getting profile attribute: $e"); } - return null; + return Future.value(null); } @override - String? GetConversationAttribute(String profile, int conversation, String key) { + Future GetConversationAttribute(String profile, int conversation, String key) { var getConversationAttributeC = library.lookup>("c_GetConversationAttribute"); // ignore: non_constant_identifier_names final GetConversationAttribute = getConversationAttributeC.asFunction(); @@ -1007,13 +1007,13 @@ class CwtchFfi implements Cwtch { try { dynamic attributeResult = json.decode(jsonMessage); if (attributeResult["Exists"]) { - return attributeResult["Value"]; + return Future.value(attributeResult["Value"]); } } catch (e) { EnvironmentConfig.debugLog("error getting profile attribute: $e"); } - return null; + return Future.value(null); } @override diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index 17d55b9e..7278ffeb 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -390,21 +390,25 @@ class CwtchGomobile implements Cwtch { } @override - String? GetProfileAttribute(String profile, String key) { - dynamic attributeResult = cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "key": key}); - if (attributeResult["Exists"]) { - return attributeResult["Value"]; - } - return null; + Future GetProfileAttribute(String profile, String key) async { + return await cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "key": key}).then((dynamic json) { + var value = jsonDecode(json); + if (value["Exists"]) { + return value["Value"]; + } + return null; + }); } @override - String? GetConversationAttribute(String profile, int conversation, String key) { - dynamic attributeResult = cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "conversation": conversation, "key": key}); - if (attributeResult["Exists"]) { - return attributeResult["Value"]; - } - return null; + Future GetConversationAttribute(String profile, int conversation, String key) async { + return await cwtchPlatform.invokeMethod("GetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "key": key}).then((dynamic json) { + var value = jsonDecode(json); + if (value["Exists"]) { + return value["Value"]; + } + return null; + }); } @override diff --git a/lib/main.dart b/lib/main.dart index 94309a3d..b22e6b88 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -87,7 +87,6 @@ class FlwtchState extends State with WindowListener { print("initState: running..."); windowManager.addListener(this); - print("initState: registering notification, shutdown handlers..."); profs = ProfileListState(); notificationClickChannel.setMethodCallHandler(_externalNotificationClicked); @@ -307,8 +306,7 @@ class FlwtchState extends State with WindowListener { globalAppState.focus = false; } - void onWindowClose() { - } + void onWindowClose() {} @override void dispose() { diff --git a/lib/models/contact.dart b/lib/models/contact.dart index a12e19db..70121234 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -264,6 +264,15 @@ class ContactInfoState extends ChangeNotifier { } } + bool canSend() { + if (this.isGroup == true) { + // We now have an out of sync warning so we will mark these as online... + return this.status == "Synced"; + } else { + return this.isOnline(); + } + } + ConversationNotificationPolicy get notificationsPolicy => _notificationPolicy; set notificationsPolicy(ConversationNotificationPolicy newVal) { diff --git a/lib/models/message_draft.dart b/lib/models/message_draft.dart index 0112569e..0ffb98ab 100644 --- a/lib/models/message_draft.dart +++ b/lib/models/message_draft.dart @@ -1,24 +1,26 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; /// A "MessageDraft" structure that stores information about in-progress message drafts. /// MessageDraft stores text, quoted replies, and attached images. /// Only one draft is stored per conversation. class MessageDraft extends ChangeNotifier { - String? _messageText; QuotedReference? _quotedReference; + TextEditingController ctrlCompose = TextEditingController(); + static MessageDraft empty() { return MessageDraft(); } bool isEmpty() { - return (this._messageText == null && this._quotedReference == null) || (this._messageText != null && this._messageText!.isEmpty); + return (this._quotedReference == null) || (this.messageText.isEmpty); } - String? get messageText => _messageText; + String get messageText => ctrlCompose.text; - set messageText(String? text) { - this._messageText = text; + set messageText(String text) { + this.ctrlCompose.text = text; notifyListeners(); } @@ -35,6 +37,18 @@ class MessageDraft extends ChangeNotifier { this._quotedReference = null; notifyListeners(); } + + void clearDraft() { + this._quotedReference = null; + this.ctrlCompose.clear(); + notifyListeners(); + } + + @override + void dispose() { + ctrlCompose.dispose(); + super.dispose(); + } } /// A QuotedReference encapsulates the state of replied-to message. diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 95fe93ef..e3463032 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -23,8 +23,7 @@ abstract class NotificationsManager { // NullNotificationsManager ignores all notification requests class NullNotificationsManager implements NotificationsManager { @override - Future notify( - String message, String profile, int conversationId) async {} + Future notify(String message, String profile, int conversationId) async {} } // Windows Notification Manager uses https://pub.dev/packages/desktoasts to implement @@ -34,7 +33,6 @@ class WindowsNotificationManager implements NotificationsManager { bool initialized = false; late Future Function(String, int) notificationSelectConvo; - WindowsNotificationManager(Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; scheduleMicrotask(() async { @@ -83,28 +81,26 @@ class WindowsNotificationManager implements NotificationsManager { * WinToast.instance().clear(); await WinToast.instance().showToast( - toast: Toast( - duration: ToastDuration.short, - children: [ - ToastChildAudio(source: ToastAudioSource.im), - ToastChildVisual( - binding: ToastVisualBinding(children: [ - ToastVisualBindingChildText( - text: message, - id: 1, - ), - ])), - ToastChildActions(children: [ - ToastAction( - content: "Open", - arguments: jsonEncode(NotificationPayload(profile, conversationId)), - ), - ToastAction( - content: "Close", - arguments: "close", - ), - ]), - ])); + toast: Toast(duration: ToastDuration.short, children: [ + ToastChildAudio(source: ToastAudioSource.im), + ToastChildVisual( + binding: ToastVisualBinding(children: [ + ToastVisualBindingChildText( + text: message, + id: 1, + ), + ])), + ToastChildActions(children: [ + ToastAction( + content: "Open", + arguments: jsonEncode(NotificationPayload(profile, conversationId)), + ), + ToastAction( + content: "Close", + arguments: "close", + ), + ]), + ])); active = false; }*/ } @@ -142,8 +138,7 @@ class NixNotificationManager implements NotificationsManager { Future detectLinuxAssetsPath() async { var devStat = FileStat.stat("assets"); var localStat = FileStat.stat("data/flutter_assets"); - var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + - "/.local/share/cwtch/data/flutter_assets"); + var homeStat = FileStat.stat((Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets"); var rootStat = FileStat.stat("/usr/share/cwtch/data/flutter_assets"); if ((await devStat).type == FileSystemEntityType.directory) { @@ -151,16 +146,14 @@ class NixNotificationManager implements NotificationsManager { } else if ((await localStat).type == FileSystemEntityType.directory) { return path.join(Directory.current.path, "data/flutter_assets/"); } else if ((await homeStat).type == FileSystemEntityType.directory) { - return (Platform.environment["HOME"] ?? "") + - "/.local/share/cwtch/data/flutter_assets/"; + return (Platform.environment["HOME"] ?? "") + "/.local/share/cwtch/data/flutter_assets/"; } else if ((await rootStat).type == FileSystemEntityType.directory) { return "/usr/share/cwtch/data/flutter_assets/"; } return ""; } - NixNotificationManager( - Future Function(String, int) notificationSelectConvo) { + NixNotificationManager(Future Function(String, int) notificationSelectConvo) { this.notificationSelectConvo = notificationSelectConvo; flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -171,26 +164,14 @@ class NixNotificationManager implements NotificationsManager { linuxAssetsPath = ""; } - var linuxIcon = - FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); + var linuxIcon = FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')); - final LinuxInitializationSettings initializationSettingsLinux = - LinuxInitializationSettings( - defaultActionName: 'Open notification', - defaultIcon: linuxIcon, - defaultSuppressSound: true); + final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification', defaultIcon: linuxIcon, defaultSuppressSound: true); final InitializationSettings initializationSettings = - InitializationSettings( - android: null, - iOS: null, - macOS: DarwinInitializationSettings(defaultPresentSound: false), - linux: initializationSettingsLinux); + InitializationSettings(android: null, iOS: null, macOS: DarwinInitializationSettings(defaultPresentSound: false), linux: initializationSettingsLinux); - flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - MacOSFlutterLocalNotificationsPlugin>() - ?.requestPermissions( + flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions( alert: true, badge: false, sound: false, @@ -202,8 +183,7 @@ class NixNotificationManager implements NotificationsManager { }); } - Future notify( - String message, String profile, int conversationId) async { + Future notify(String message, String profile, int conversationId) async { if (!globalAppState.focus) { // Warning: Only use title field on Linux, body field will render links as clickable await flutterLocalNotificationsPlugin.show( @@ -211,11 +191,7 @@ class NixNotificationManager implements NotificationsManager { message, '', NotificationDetails( - linux: LinuxNotificationDetails( - suppressSound: true, - category: LinuxNotificationCategory.imReceived, - icon: FilePathLinuxIcon( - path.join(linuxAssetsPath, 'assets/knott.png')))), + linux: LinuxNotificationDetails(suppressSound: true, category: LinuxNotificationCategory.imReceived, icon: FilePathLinuxIcon(path.join(linuxAssetsPath, 'assets/knott.png')))), payload: jsonEncode(NotificationPayload(profile, conversationId))); } } @@ -230,9 +206,7 @@ class NixNotificationManager implements NotificationsManager { } } -NotificationsManager newDesktopNotificationsManager( - Future Function(String profileOnion, int convoId) - notificationSelectConvo) { +NotificationsManager newDesktopNotificationsManager(Future Function(String profileOnion, int convoId) notificationSelectConvo) { // We don't want notifications in Dev Mode if (EnvironmentConfig.TEST_MODE) { return NullNotificationsManager(); @@ -242,22 +216,19 @@ NotificationsManager newDesktopNotificationsManager( try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog( - "Failed to create LinuxNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog("Failed to create LinuxNotificationManager. Switching off notifications."); } } else if (Platform.isMacOS) { try { return NixNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog( - "Failed to create NixNotificationManager. Switching off notifications."); + EnvironmentConfig.debugLog("Failed to create NixNotificationManager. Switching off notifications."); } } else if (Platform.isWindows) { try { return WindowsNotificationManager(notificationSelectConvo); } catch (e) { - EnvironmentConfig.debugLog( - "Failed to create Windows desktoasts notification manager"); + EnvironmentConfig.debugLog("Failed to create Windows desktoasts notification manager"); } } diff --git a/lib/settings.dart b/lib/settings.dart index 281ecf5c..a0ba35ce 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -192,6 +192,11 @@ class Settings extends ChangeNotifier { double get fontScaling => _fontScaling; + // a convenience function to scale fonts dynamically... + TextStyle scaleFonts(TextStyle input) { + return input.copyWith(fontSize: (input.fontSize ?? 12) * this.fontScaling); + } + /// Switch the Locale of the App switchLocale(Locale newLocale) { locale = newLocale; diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 730cff48..aa10f2c9 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -19,6 +19,12 @@ import 'neon2.dart'; const mode_light = "light"; const mode_dark = "dark"; +final TextStyle defaultSmallTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.normal, fontSize: 10); +final TextStyle defaultMessageTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.normal, fontSize: 12); +final TextStyle defaultFormLabelTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 20); +final TextStyle defaultTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12); +final TextStyle defaultTextButtonStyle = defaultTextStyle.copyWith(fontWeight: FontWeight.bold); + final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, ghost_theme: {mode_light: GhostLight(), mode_dark: GhostDark()}, diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index ac0afa7b..15bc10aa 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -44,7 +44,6 @@ class MessageView extends StatefulWidget { } class _MessageViewState extends State { - final ctrlrCompose = TextEditingController(); final focusNode = FocusNode(); int selectedContact = -1; ItemPositionsListener scrollListener = ItemPositionsListener.create(); @@ -68,7 +67,6 @@ class _MessageViewState extends State { showDown = false; } }); - ctrlrCompose.text = Provider.of(context, listen: false).messageDraft.messageText ?? ""; super.initState(); } @@ -88,7 +86,6 @@ class _MessageViewState extends State { @override void dispose() { focusNode.dispose(); - ctrlrCompose.dispose(); super.dispose(); } @@ -321,22 +318,22 @@ class _MessageViewState extends State { void _sendMessage([String? ignoredParam]) { // Do this after we trim to preserve enter-behaviour... - bool isOffline = Provider.of(context, listen: false).isOnline() == false; + bool cannotSend = Provider.of(context, listen: false).canSend() == false; bool performingAntiSpam = Provider.of(context, listen: false).antispamTickets == 0; bool isGroup = Provider.of(context, listen: false).isGroup; - if (isOffline || (isGroup && performingAntiSpam)) { + if (cannotSend || (isGroup && performingAntiSpam)) { return; } // Trim message - final messageWithoutNewLine = ctrlrCompose.value.text.trimRight(); - ctrlrCompose.value = TextEditingValue(text: messageWithoutNewLine, selection: TextSelection.fromPosition(TextPosition(offset: messageWithoutNewLine.length))); + var messageText = Provider.of(context, listen: false).messageDraft.messageText ?? ""; + final messageWithoutNewLine = messageText.trimRight(); // peers and groups currently have different length constraints (servers can store less)... - var actualMessageLength = ctrlrCompose.value.text.length; + var actualMessageLength = messageText.length; var lengthOk = (isGroup && actualMessageLength < GroupMessageLengthMax) || actualMessageLength <= P2PMessageLengthMax; - if (ctrlrCompose.value.text.isNotEmpty && lengthOk) { + if (messageWithoutNewLine.isNotEmpty && lengthOk) { if (Provider.of(context, listen: false).selectedConversation != null && Provider.of(context, listen: false).messageDraft.getQuotedMessage() != null) { var conversationId = Provider.of(context, listen: false).selectedConversation!; MessageCache? cache = Provider.of(context, listen: false).contactList.getContact(conversationId)?.messageCache; @@ -347,7 +344,7 @@ class _MessageViewState extends State { var bytes1 = utf8.encode(data!.metadata.senderHandle + data.wrapper); var digest1 = sha256.convert(bytes1); var contentHash = base64Encode(digest1.bytes); - var quotedMessage = jsonEncode(QuotedMessageStructure(contentHash, ctrlrCompose.value.text)); + var quotedMessage = jsonEncode(QuotedMessageStructure(contentHash, messageWithoutNewLine)); ChatMessage cm = new ChatMessage(o: QuotedMessageOverlay, d: quotedMessage); Provider.of(context, listen: false) .cwtch @@ -359,7 +356,7 @@ class _MessageViewState extends State { Provider.of(context, listen: false).messageDraft.clearQuotedReference(); }); } else { - ChatMessage cm = new ChatMessage(o: TextMessageOverlay, d: ctrlrCompose.value.text); + ChatMessage cm = new ChatMessage(o: TextMessageOverlay, d: messageWithoutNewLine); Provider.of(context, listen: false) .cwtch .SendMessage(Provider.of(context, listen: false).profileOnion, Provider.of(context, listen: false).identifier, jsonEncode(cm)) @@ -391,8 +388,7 @@ class _MessageViewState extends State { // At this point we have decided to send the text to the backend, failure is still possible // but it will show as an error-ed message, as such the draft can be purged. - Provider.of(context, listen: false).messageDraft = MessageDraft.empty(); - ctrlrCompose.clear(); + Provider.of(context, listen: false).messageDraft.clearDraft(); var profileOnion = Provider.of(context, listen: false).profileOnion; var identifier = Provider.of(context, listen: false).identifier; @@ -424,7 +420,7 @@ class _MessageViewState extends State { var wdgMessage = Padding( padding: EdgeInsets.all(8), child: SelectableLinkify( - text: ctrlrCompose.text + '\n', + text: Provider.of(context).messageDraft.messageText + '\n', options: LinkifyOptions(messageFormatting: true, parseLinks: showClickableLinks, looseUrl: true, defaultToHttps: true), linkifiers: [UrlLinkifier()], onOpen: showClickableLinks ? null : null, @@ -468,7 +464,7 @@ class _MessageViewState extends State { margin: EdgeInsets.all(2), // 164 minimum height + 16px for every line of text so the entire message is displayed when previewed. - height: 164 + ((ctrlrCompose.text.split("\n").length - 1) * 16), + height: 164 + ((Provider.of(context).messageDraft.messageText.split("\n").length - 1) * 16), child: Column( children: [ Row(mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [preview]), @@ -483,11 +479,11 @@ class _MessageViewState extends State { } Widget _buildComposeBox(BuildContext context) { - bool isOffline = Provider.of(context).isOnline() == false; + bool cannotSend = Provider.of(context).canSend() == false; bool isGroup = Provider.of(context).isGroup; var showToolbar = Provider.of(context).isExperimentEnabled(FormattingExperiment); - var charLength = ctrlrCompose.value.text.characters.length; - var expectedLength = ctrlrCompose.value.text.length; + var charLength = Provider.of(context).messageDraft.messageText.characters.length; + var expectedLength = Provider.of(context).messageDraft.messageText.length; var numberOfBytesMoreThanChar = (expectedLength - charLength); var bold = IconButton( @@ -495,12 +491,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipBoldText, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "**" + selected + "**"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 2, extentOffset: selection.start + 2); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -509,12 +507,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipItalicize, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "*" + selected + "*"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 1, extentOffset: selection.start + 1); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -523,12 +523,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipCode, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "`" + selected + "`"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 1, extentOffset: selection.start + 1); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -537,12 +539,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipSuperscript, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "^" + selected + "^"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 1, extentOffset: selection.start + 1); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -551,12 +555,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipSubscript, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "_" + selected + "_"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 1, extentOffset: selection.start + 1); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -565,12 +571,14 @@ class _MessageViewState extends State { tooltip: AppLocalizations.of(context)!.tooltipStrikethrough, onPressed: () { setState(() { + var ctrlrCompose = Provider.of(context, listen: false).messageDraft.ctrlCompose; var selected = ctrlrCompose.selection.textInside(ctrlrCompose.text); var selection = ctrlrCompose.selection; var start = ctrlrCompose.selection.start; var end = ctrlrCompose.selection.end; ctrlrCompose.text = ctrlrCompose.text.replaceRange(start, end, "~~" + selected + "~~"); ctrlrCompose.selection = selection.copyWith(baseOffset: selection.start + 2, extentOffset: selection.start + 2); + Provider.of(context, listen: false).messageDraft.ctrlCompose = ctrlrCompose; }); }); @@ -600,7 +608,7 @@ class _MessageViewState extends State { padding: EdgeInsets.all(8), child: TextFormField( key: Key('txtCompose'), - controller: ctrlrCompose, + controller: Provider.of(context).messageDraft.ctrlCompose, focusNode: focusNode, autofocus: !Platform.isAndroid, textInputAction: TextInputAction.newline, @@ -615,18 +623,17 @@ class _MessageViewState extends State { style: TextStyle( fontFamily: "Inter", fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.w500, + fontWeight: FontWeight.w300, ), enabled: true, // always allow editing... onChanged: (String x) { - Provider.of(context, listen: false).messageDraft.messageText = x; setState(() { // we need to force a rerender here to update the max length count }); }, decoration: InputDecoration( - hintText: isOffline ? "" : AppLocalizations.of(context)!.placeholderEnterMessage, + hintText: AppLocalizations.of(context)!.placeholderEnterMessage, hintStyle: TextStyle(fontFamily: "Inter", fontSize: 10.0 * Provider.of(context).fontScaling, color: Provider.of(context).theme.sendHintTextColor), enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, @@ -635,13 +642,13 @@ class _MessageViewState extends State { key: Key("btnSend"), style: ElevatedButton.styleFrom(padding: EdgeInsets.all(0.0), shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(45.0))), child: Tooltip( - message: isOffline + message: cannotSend ? (isGroup ? AppLocalizations.of(context)!.serverNotSynced : AppLocalizations.of(context)!.peerOfflineMessage) : (isGroup && Provider.of(context, listen: false).antispamTickets == 0) ? AppLocalizations.of(context)!.acquiringTicketsFromServer : AppLocalizations.of(context)!.sendMessage, child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of(context).theme.defaultButtonTextColor)), - onPressed: isOffline || (isGroup && Provider.of(context, listen: false).antispamTickets == 0) ? null : _sendMessage, + onPressed: cannotSend || (isGroup && Provider.of(context, listen: false).antispamTickets == 0) ? null : _sendMessage, ))), ))); @@ -727,7 +734,8 @@ class _MessageViewState extends State { if (event is RawKeyUpEvent) { if ((data.logicalKey == LogicalKeyboardKey.enter && !event.isShiftPressed) || data.logicalKey == LogicalKeyboardKey.numpadEnter && !event.isShiftPressed) { // Don't send when inserting a new line that is not at the end of the message - if (ctrlrCompose.selection.baseOffset != ctrlrCompose.text.length) { + if (Provider.of(context, listen: false).messageDraft.ctrlCompose.selection.baseOffset != + Provider.of(context, listen: false).messageDraft.ctrlCompose.text.length) { return; } _sendMessage(); @@ -735,8 +743,6 @@ class _MessageViewState extends State { } } - void placeHolder() => {}; - // explicitly passing BuildContext ctx here is important, change at risk to own health // otherwise some Providers will become inaccessible to subwidgets...? // https://stackoverflow.com/a/63818697 diff --git a/lib/widgets/cwtchlabel.dart b/lib/widgets/cwtchlabel.dart index 07ac3874..9cfa8b11 100644 --- a/lib/widgets/cwtchlabel.dart +++ b/lib/widgets/cwtchlabel.dart @@ -1,3 +1,4 @@ +import 'package:cwtch/themes/opaque.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; @@ -18,7 +19,7 @@ class _CwtchLabelState extends State { return Consumer(builder: (context, theme, child) { return Text( widget.label, - style: TextStyle(fontSize: 20, color: theme.current().mainTextColor), + style: Provider.of(context).scaleFonts(defaultFormLabelTextStyle), ); }); } diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index badadf70..a8bb683b 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -7,7 +7,9 @@ import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/filedownloadprogress.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; +import 'package:cwtch/widgets/messageBubbleWidgetHelpers.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -147,18 +149,10 @@ class FileBubbleState extends State { var wdgSender = Visibility( visible: widget.interactive, child: Container( - height: 14 * Provider.of(context).fontScaling, - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration(), - child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle( - fontSize: 9.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.bold, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)))); + height: 14 * Provider.of(context).fontScaling, clipBehavior: Clip.hardEdge, decoration: BoxDecoration(), child: compileSenderWidget(context, fromMe, senderDisplayStr))); var isPreview = false; var wdgMessage = !showFileSharing - ? Text(AppLocalizations.of(context)!.messageEnableFileSharing) + ? Text(AppLocalizations.of(context)!.messageEnableFileSharing, style: Provider.of(context).scaleFonts(defaultTextStyle)) : fromMe ? senderFileChrome(AppLocalizations.of(context)!.messageFileSent, widget.nameSuggestion, widget.rootHash, widget.fileSize) : (fileChrome(AppLocalizations.of(context)!.messageFileOffered + ":", widget.nameSuggestion, widget.rootHash, widget.fileSize, @@ -182,11 +176,13 @@ class FileBubbleState extends State { }, ))); } else { - wdgDecorations = Visibility(visible: widget.interactive, child: Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F')); + wdgDecorations = Visibility( + visible: widget.interactive, child: Text(AppLocalizations.of(context)!.fileSavedTo + ': ' + path + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle))); } } else if (downloadActive) { if (!downloadGotManifest) { - wdgDecorations = Visibility(visible: widget.interactive, child: Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F')); + wdgDecorations = Visibility( + visible: widget.interactive, child: Text(AppLocalizations.of(context)!.retrievingManifestMessage + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle))); } else { wdgDecorations = Visibility( visible: widget.interactive, @@ -199,19 +195,19 @@ class FileBubbleState extends State { // in this case, the download was done in a previous application launch, // so we probably have to request an info lookup if (!downloadInterrupted) { - wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F'); + wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle)); // We should have already requested this... } else { var path = Provider.of(context).downloadFinalPath(widget.fileKey()) ?? ""; wdgDecorations = Visibility( visible: widget.interactive, child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F'), - ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton)) + Text(AppLocalizations.of(context)!.fileInterrupted + ': ' + path + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle)), + ElevatedButton(onPressed: _btnResume, child: Text(AppLocalizations.of(context)!.verfiyResumeButton, style: Provider.of(context).scaleFonts(defaultTextButtonStyle))) ])); } } else if (!senderIsContact) { - wdgDecorations = Text(AppLocalizations.of(context)!.msgAddToAccept); + wdgDecorations = Text(AppLocalizations.of(context)!.msgAddToAccept, style: Provider.of(context).scaleFonts(defaultTextStyle)); } else if (!widget.isAuto || Provider.of(context).attributes["file-missing"] == "false") { //Note: we need this second case to account for scenarios where a user deletes the downloaded file, we won't automatically // fetch it again, so we need to offer the user the ability to restart.. @@ -220,7 +216,10 @@ class FileBubbleState extends State { child: Center( widthFactor: 1, child: Wrap(children: [ - Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F'), onPressed: _btnAccept)), + Padding( + padding: EdgeInsets.all(5), + child: ElevatedButton( + child: Text(AppLocalizations.of(context)!.downloadFileButton + '\u202F', style: Provider.of(context).scaleFonts(defaultTextButtonStyle)), onPressed: _btnAccept)), ]))); } else { wdgDecorations = Container(); @@ -278,7 +277,7 @@ class FileBubbleState extends State { } } else { try { - selectedFileName = await FilePicker.platform.saveFile( + selectedFileName = await FilePicker.platform.saveFile( fileName: widget.nameSuggestion, lockParentWindow: true, ); @@ -308,52 +307,35 @@ class FileBubbleState extends State { // Construct an file chrome for the sender Widget senderFileChrome(String chrome, String fileName, String rootHash, int fileSize) { + var settings = Provider.of(context); return ListTile( visualDensity: VisualDensity.compact, title: Wrap(direction: Axis.horizontal, alignment: WrapAlignment.start, children: [ SelectableText( chrome + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - fontSize: 12 * Provider.of(context).fontScaling, - ), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, ), SelectableText( fileName + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontWeight: FontWeight.bold, - overflow: TextOverflow.ellipsis, - fontFamily: "Inter", - fontSize: 12 * Provider.of(context).fontScaling, - ), + style: + settings.scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.parent, maxLines: 2, ), SelectableText( prettyBytes(fileSize) + '\u202F' + '\n', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontSize: 10 * Provider.of(context).fontScaling, - fontFamily: "Inter", - ), + style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, maxLines: 2, ) ]), subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontSize: 10 * Provider.of(context).fontScaling, - fontFamily: "RobotoMono", - ), + style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, maxLines: 4, textWidthBasis: TextWidthBasis.parent, @@ -363,50 +345,35 @@ class FileBubbleState extends State { // Construct an file chrome Widget fileChrome(String chrome, String fileName, String rootHash, int fileSize, String speed) { + var settings = Provider.of(context); return ListTile( visualDensity: VisualDensity.compact, title: Wrap(direction: Axis.horizontal, alignment: WrapAlignment.start, children: [ SelectableText( chrome + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor, - fontSize: 12 * Provider.of(context).fontScaling, - fontFamily: "Inter", - ), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, ), SelectableText( fileName + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor, - fontWeight: FontWeight.bold, - overflow: TextOverflow.ellipsis, - fontFamily: "Inter", - ), + style: settings + .scaleFonts(defaultMessageTextStyle.copyWith(overflow: TextOverflow.ellipsis, fontWeight: FontWeight.bold, color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.parent, maxLines: 2, ), SelectableText( AppLocalizations.of(context)!.labelFilesize + ': ' + prettyBytes(fileSize) + '\u202F' + '\n', - style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor, - fontFamily: "Inter", - fontSize: 10 * Provider.of(context).fontScaling, - ), + style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, maxLines: 2, ) ]), subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontSize: 10 * Provider.of(context).fontScaling, - fontFamily: "RobotoMono", - ), + style: settings.scaleFonts(defaultSmallTextStyle.copyWith(fontFamily: "RobotoMono", color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, maxLines: 4, textWidthBasis: TextWidthBasis.parent, @@ -416,11 +383,7 @@ class FileBubbleState extends State { visible: speed != "0 B/s", child: SelectableText( speed + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - fontFamily: "Inter", - fontSize: 10 * Provider.of(context).fontScaling, - ), + style: settings.scaleFonts(defaultSmallTextStyle.copyWith(color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, maxLines: 1, textWidthBasis: TextWidthBasis.longestLine, diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 9d361893..de10f11d 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -5,6 +5,7 @@ import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -13,6 +14,7 @@ import 'package:intl/intl.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../settings.dart'; +import 'messageBubbleWidgetHelpers.dart'; import 'messagebubbledecorations.dart'; // Like MessageBubble but for displaying chat overlay 100/101 invitations @@ -54,15 +56,7 @@ class InvitationBubbleState extends State { } } - var wdgSender = Center( - widthFactor: 1, - child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle( - fontSize: 9.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.bold, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); - + var wdgSender = compileSenderWidget(context, fromMe, senderDisplayStr); // 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 = widget.inviteNick == Provider.of(context).onion; @@ -71,7 +65,7 @@ class InvitationBubbleState extends State { } var wdgMessage = isGroup && !showGroupInvite - ? Text(AppLocalizations.of(context)!.groupInviteSettingsWarning) + ? Text(AppLocalizations.of(context)!.groupInviteSettingsWarning, style: Provider.of(context).scaleFonts(defaultTextStyle)) : fromMe ? senderInviteChrome( AppLocalizations.of(context)!.sendAnInvitation, isGroup ? Provider.of(context).contactList.findContact(widget.inviteTarget)!.nickname : widget.inviteTarget) @@ -83,15 +77,21 @@ class InvitationBubbleState extends State { } else if (fromMe) { wdgDecorations = MessageBubbleDecoration(ackd: Provider.of(context).ackd, errored: Provider.of(context).error, fromMe: fromMe, messageDate: messageDate); } else if (isAccepted) { - wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F'); + wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle)); } else if (this.rejected) { - wdgDecorations = Text(AppLocalizations.of(context)!.rejected + '\u202F'); + wdgDecorations = Text(AppLocalizations.of(context)!.rejected + '\u202F', style: Provider.of(context).scaleFonts(defaultTextStyle)); } else { wdgDecorations = Center( widthFactor: 1, child: Wrap(children: [ - Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.rejectGroupBtn + '\u202F'), onPressed: _btnReject)), - Padding(padding: EdgeInsets.all(5), child: ElevatedButton(child: Text(AppLocalizations.of(context)!.acceptGroupBtn + '\u202F'), onPressed: _btnAccept)), + Padding( + padding: EdgeInsets.all(5), + child: ElevatedButton( + child: Text(AppLocalizations.of(context)!.rejectGroupBtn + '\u202F', style: Provider.of(context).scaleFonts(defaultTextButtonStyle)), onPressed: _btnReject)), + Padding( + padding: EdgeInsets.all(5), + child: ElevatedButton( + child: Text(AppLocalizations.of(context)!.acceptGroupBtn + '\u202F', style: Provider.of(context).scaleFonts(defaultTextButtonStyle)), onPressed: _btnAccept)), ])); } @@ -149,21 +149,19 @@ class InvitationBubbleState extends State { // Construct an invite chrome for the sender Widget senderInviteChrome(String chrome, String targetName) { + var settings = Provider.of(context); + return Wrap(children: [ SelectableText( chrome + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - ), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, ), SelectableText( targetName + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor, - ), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromMeTextColor)), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, @@ -173,19 +171,19 @@ class InvitationBubbleState extends State { // Construct an invite chrome Widget inviteChrome(String chrome, String targetName, String targetId) { + var settings = Provider.of(context); + return Wrap(children: [ SelectableText( chrome + '\u202F', - style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor, - ), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, maxLines: 2, ), SelectableText( targetName + '\u202F', - style: TextStyle(color: Provider.of(context).theme.messageFromOtherTextColor), + style: settings.scaleFonts(defaultMessageTextStyle.copyWith(color: Provider.of(context).theme.messageFromOtherTextColor)), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, diff --git a/lib/widgets/messageBubbleWidgetHelpers.dart b/lib/widgets/messageBubbleWidgetHelpers.dart new file mode 100644 index 00000000..118c22b4 --- /dev/null +++ b/lib/widgets/messageBubbleWidgetHelpers.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../controllers/open_link_modal.dart'; +import '../settings.dart'; +import '../themes/opaque.dart'; +import '../third_party/linkify/flutter_linkify.dart'; + +Widget compileSenderWidget(BuildContext context, bool fromMe, String senderDisplayStr) { + return Container( + height: 14 * Provider.of(context).fontScaling, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration(), + child: SelectableText(senderDisplayStr, + maxLines: 1, + style: TextStyle( + fontSize: 9.0 * Provider.of(context).fontScaling, + fontWeight: FontWeight.bold, + fontFamily: "Inter", + overflow: TextOverflow.clip, + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, + ))); +} + +Widget compileMessageContentWidget(BuildContext context, bool fromMe, String content, FocusNode focus, bool formatMessages, bool showClickableLinks) { + return SelectableLinkify( + text: content + '\u202F', + // TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler? + options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: showClickableLinks, looseUrl: true, defaultToHttps: true), + linkifiers: [UrlLinkifier()], + onOpen: showClickableLinks + ? (link) { + modalOpenLink(context, link); + } + : null, + //key: Key(myKey), + focusNode: focus, + style: Provider.of(context) + .scaleFonts(defaultMessageTextStyle.copyWith(color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)), + linkStyle: Provider.of(context) + .scaleFonts(defaultMessageTextStyle.copyWith(color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)), + codeStyle: Provider.of(context).scaleFonts(defaultMessageTextStyle.copyWith( + fontFamily: "RobotoMono", + color: fromMe ? Provider.of(context).theme.messageFromOtherTextColor : Provider.of(context).theme.messageFromMeTextColor, + backgroundColor: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor : Provider.of(context).theme.messageFromMeBackgroundColor)), + textAlign: TextAlign.left, + textWidthBasis: TextWidthBasis.longestLine, + ); +} diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index 6fb7179d..77515db5 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cwtch/controllers/open_link_modal.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/message.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/third_party/linkify/flutter_linkify.dart'; import 'package:cwtch/models/profile.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; @@ -10,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; +import 'messageBubbleWidgetHelpers.dart'; import 'messagebubbledecorations.dart'; class MessageBubble extends StatefulWidget { @@ -42,56 +44,9 @@ class MessageBubbleState extends State { senderDisplayStr = Provider.of(context).senderHandle; } } - var wdgSender = Container( - height: 14 * Provider.of(context).fontScaling, - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration(), - child: SelectableText(senderDisplayStr, - maxLines: 1, - style: TextStyle( - fontSize: 9.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.bold, - fontFamily: "Inter", - overflow: TextOverflow.clip, - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, - ))); - - var wdgMessage = SelectableLinkify( - text: widget.content + '\u202F', - // TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler? - options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: showClickableLinks, looseUrl: true, defaultToHttps: true), - linkifiers: [UrlLinkifier()], - onOpen: showClickableLinks - ? (link) { - modalOpenLink(context, link); - } - : null, - //key: Key(myKey), - focusNode: _focus, - style: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, - ), - linkStyle: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), - codeStyle: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - // note: these colors are flipped - color: fromMe ? Provider.of(context).theme.messageFromOtherTextColor : Provider.of(context).theme.messageFromMeTextColor, - backgroundColor: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor : Provider.of(context).theme.messageFromMeBackgroundColor), - textAlign: TextAlign.left, - textWidthBasis: TextWidthBasis.longestLine, - ); - + var wdgSender = compileSenderWidget(context, fromMe, senderDisplayStr); + var wdgMessage = compileMessageContentWidget(context, fromMe, widget.content, _focus, formatMessages, showClickableLinks); var wdgDecorations = MessageBubbleDecoration(ackd: Provider.of(context).ackd, errored: Provider.of(context).error, fromMe: fromMe, messageDate: messageDate); - var error = Provider.of(context).error; return LayoutBuilder(builder: (context, constraints) { diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 2d3faa34..59681304 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -7,6 +7,7 @@ import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/third_party/base32/base32.dart'; import 'package:cwtch/views/contactsview.dart'; import 'package:cwtch/widgets/staticmessagebubble.dart'; @@ -307,7 +308,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi bottomRight: Radius.circular(8), ), ), - child: Padding(padding: EdgeInsets.all(9.0), child: Text(AppLocalizations.of(context)!.newMessagesLabel))); + child: Padding(padding: EdgeInsets.all(9.0), child: Text(AppLocalizations.of(context)!.newMessagesLabel, style: Provider.of(context).scaleFonts(defaultTextButtonStyle)))); } void _runAnimation(Offset pixelsPerSecond, Size size) { diff --git a/lib/widgets/quotedmessage.dart b/lib/widgets/quotedmessage.dart index 70567c45..dadd0f1a 100644 --- a/lib/widgets/quotedmessage.dart +++ b/lib/widgets/quotedmessage.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../settings.dart'; +import 'messageBubbleWidgetHelpers.dart'; import 'messagebubbledecorations.dart'; class QuotedMessageBubble extends StatefulWidget { @@ -43,53 +44,11 @@ class QuotedMessageBubbleState extends State { } } - var wdgSender = Container( - height: 14 * Provider.of(context).fontScaling, - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration(), - child: SelectableText(senderDisplayStr, - style: TextStyle( - fontSize: 9.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.bold, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); + var wdgSender = compileSenderWidget(context, fromMe, senderDisplayStr); var showClickableLinks = Provider.of(context).isExperimentEnabled(ClickableLinksExperiment); var formatMessages = Provider.of(context).isExperimentEnabled(FormattingExperiment); - - var wdgMessage = SelectableLinkify( - text: widget.body + '\u202F', - // TODO: onOpen breaks the "selectable" functionality. Maybe something to do with gesture handler? - options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: showClickableLinks, looseUrl: true, defaultToHttps: true), - linkifiers: [UrlLinkifier()], - onOpen: showClickableLinks - ? (link) { - modalOpenLink(context, link); - } - : null, - //key: Key(myKey), - focusNode: _focus, - style: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, - ), - linkStyle: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "Inter", - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), - codeStyle: TextStyle( - fontSize: 12.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.normal, - fontFamily: "RobotoMono", - // note: these colors are flipped - color: fromMe ? Provider.of(context).theme.messageFromOtherTextColor : Provider.of(context).theme.messageFromMeTextColor, - backgroundColor: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor : Provider.of(context).theme.messageFromMeBackgroundColor), - textAlign: TextAlign.left, - textWidthBasis: TextWidthBasis.longestLine, - ); + var wdgMessage = compileMessageContentWidget(context, fromMe, widget.body, _focus, formatMessages, showClickableLinks); var wdgQuote = FutureBuilder( future: widget.quotedMessage, @@ -118,7 +77,7 @@ class QuotedMessageBubbleState extends State { var wdgReplyingTo = SelectableText( AppLocalizations.of(context)!.replyingTo.replaceAll("%1", qMessageSender), - style: TextStyle(fontSize: 10, color: qTextColor.withOpacity(0.8)), + style: Provider.of(context).scaleFonts(TextStyle(fontSize: 10, color: qTextColor.withOpacity(0.8))), ); // Swap the background color for quoted tweets.. return MouseRegion( diff --git a/lib/widgets/staticmessagebubble.dart b/lib/widgets/staticmessagebubble.dart index bd8e6187..ad19bd56 100644 --- a/lib/widgets/staticmessagebubble.dart +++ b/lib/widgets/staticmessagebubble.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; +import 'messageBubbleWidgetHelpers.dart'; import 'messagebubbledecorations.dart'; class StaticMessageBubble extends StatefulWidget { @@ -40,12 +41,7 @@ class StaticMessageBubbleState extends State { senderDisplayStr = widget.profile.nickname; } - var wdgSender = SelectableText(senderDisplayStr, - style: TextStyle( - fontSize: 9.0 * Provider.of(context).fontScaling, - fontWeight: FontWeight.bold, - fontFamily: "Inter", - color: fromMe ? widget.settings.theme.messageFromMeTextColor : widget.settings.theme.messageFromOtherTextColor)); + var wdgSender = compileSenderWidget(context, fromMe, senderDisplayStr); var wdgDecorations = MessageBubbleDecoration(ackd: widget.metadata.ackd, errored: widget.metadata.error, fromMe: fromMe, messageDate: messageDate); From 01b5c41208528499ee5cc0e61116dc36d893be4f Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 11:20:23 -0700 Subject: [PATCH 11/20] Update Cwtch --- LIBCWTCH-GO.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index 9259fe11..727819aa 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -2023-05-09-13-30-v0.0.3-24-g5b2f3cf +2023-05-16-16-25-v0.0.4 \ No newline at end of file From 67a99c903a76376a35bc0225e2f9421b071f3b6a Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 11:24:09 -0700 Subject: [PATCH 12/20] Fix Up Quotes --- lib/models/messages/quotedmessage.dart | 11 ++--------- lib/models/messages/textmessage.dart | 16 ++-------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/lib/models/messages/quotedmessage.dart b/lib/models/messages/quotedmessage.dart index fc00b20f..81e4ef0c 100644 --- a/lib/models/messages/quotedmessage.dart +++ b/lib/models/messages/quotedmessage.dart @@ -4,6 +4,7 @@ import 'package:cwtch/config.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/messages/malformedmessage.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; +import 'package:cwtch/widgets/messageBubbleWidgetHelpers.dart'; import 'package:cwtch/widgets/messagerow.dart'; import 'package:cwtch/widgets/quotedmessage.dart'; import 'package:flutter/widgets.dart'; @@ -39,15 +40,7 @@ class QuotedMessage extends Message { ); var content = message["body"]; var formatMessages = Provider.of(bcontext).isExperimentEnabled(FormattingExperiment); - return SelectableLinkify( - text: content + '\u202F', - options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: false, looseUrl: true, defaultToHttps: true), - linkifiers: [UrlLinkifier()], - onOpen: null, - textAlign: TextAlign.left, - style: TextStyle(fontSize: 12.0 * Provider.of(context).fontScaling, fontWeight: FontWeight.normal, fontFamily: "Inter", overflow: TextOverflow.ellipsis), - codeStyle: TextStyle(fontSize: 12.0 * Provider.of(context).fontScaling, fontWeight: FontWeight.normal, fontFamily: "Inter", overflow: TextOverflow.ellipsis), - textWidthBasis: TextWidthBasis.longestLine); + return compileMessageContentWidget(context, false, content, FocusNode(), formatMessages, false); } catch (e) { return MalformedBubble(); } diff --git a/lib/models/messages/textmessage.dart b/lib/models/messages/textmessage.dart index 1833dfff..c15555a6 100644 --- a/lib/models/messages/textmessage.dart +++ b/lib/models/messages/textmessage.dart @@ -12,6 +12,7 @@ import 'package:provider/provider.dart'; import '../../settings.dart'; import '../../third_party/linkify/flutter_linkify.dart'; +import '../../widgets/messageBubbleWidgetHelpers.dart'; class TextMessage extends Message { final MessageMetadata metadata; @@ -25,20 +26,7 @@ class TextMessage extends Message { value: this.metadata, builder: (bcontext, child) { var formatMessages = Provider.of(bcontext).isExperimentEnabled(FormattingExperiment); - return SelectableLinkify( - text: content + '\u202F', - options: LinkifyOptions(messageFormatting: formatMessages, parseLinks: false, looseUrl: true, defaultToHttps: true), - linkifiers: [UrlLinkifier()], - onOpen: null, - textAlign: TextAlign.left, - style: TextStyle(overflow: TextOverflow.fade, fontFamily: "Inter", fontSize: 12.0 * Provider.of(context).fontScaling), - linkStyle: TextStyle(overflow: TextOverflow.fade, fontFamily: "Inter", fontSize: 12.0 * Provider.of(context).fontScaling), - codeStyle: TextStyle( - overflow: TextOverflow.ellipsis, - fontFamily: "RobotoMono", - ), - textWidthBasis: TextWidthBasis.parent, - ); + return compileMessageContentWidget(context, false, content, FocusNode(), formatMessages, false);; }); } From ea228643415adb854bcb5931caad9b0d7a3b9211 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 12:05:14 -0700 Subject: [PATCH 13/20] Fix Android File Downloading Stuck Notification / Small Settings Font Tweaks --- .../kotlin/im/cwtch/flwtch/FlwtchWorker.kt | 59 +++++++++++-------- lib/models/messages/textmessage.dart | 3 +- lib/themes/opaque.dart | 7 ++- lib/views/globalsettingsview.dart | 23 +++----- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt b/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt index 4fbd74c9..c83491a5 100644 --- a/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt +++ b/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt @@ -84,6 +84,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) : Log.i(TAG, "startCwtch success, starting coroutine AppbusEvent loop...") val downloadIDs = mutableMapOf() + val downloadFinishedIDs = mutableMapOf() var flags = PendingIntent.FLAG_UPDATE_CURRENT if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { flags = flags or PendingIntent.FLAG_IMMUTABLE @@ -167,32 +168,36 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) : val title = data.getString("NameSuggestion"); val progress = data.getString("Progress").toInt(); val progressMax = data.getString("FileSizeInChunks").toInt(); - if (!downloadIDs.containsKey(fileKey)) { - downloadIDs.put(fileKey, downloadIDs.count()); - } - var dlID = downloadIDs.get(fileKey); - if (dlID == null) { - dlID = 0; - } - if (progress >= 0) { - val channelId = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - createDownloadNotificationChannel(fileKey, fileKey) - } 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 newNotification = NotificationCompat.Builder(applicationContext, channelId) - .setOngoing(true) - .setContentTitle("Downloading")//todo: translate - .setContentText(title) - .setSmallIcon(android.R.drawable.stat_sys_download) - .setProgress(progressMax, progress, false) - .setSound(null) - //.setSilent(true) - .build(); - notificationManager.notify(dlID, newNotification); + + // if we have seen a download finished update for this key then ignore it + if (!downloadFinishedIDs.containsKey(fileKey)) { + if (!downloadIDs.containsKey(fileKey)) { + downloadIDs.put(fileKey, downloadIDs.count()); + } + var dlID = downloadIDs.get(fileKey); + if (dlID == null) { + dlID = 0; + } + if (progress >= 0) { + val channelId = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createDownloadNotificationChannel(fileKey, fileKey) + } 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 newNotification = NotificationCompat.Builder(applicationContext, channelId) + .setOngoing(true) + .setContentTitle("Downloading")//todo: translate + .setContentText(title) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setProgress(progressMax, progress, false) + .setSound(null) + //.setSilent(true) + .build(); + notificationManager.notify(dlID, newNotification); + } } } catch (e: Exception) { Log.d("FlwtchWorker->FileDownloadProgressUpdate", e.toString() + " :: " + e.getStackTrace()); @@ -216,6 +221,8 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) : Files.delete(sourcePath); } } + // Suppress future notifications... + downloadFinishedIDs.put(fileKey, downloadIDs.count()); if (downloadIDs.containsKey(fileKey)) { notificationManager.cancel(downloadIDs.get(fileKey) ?: 0); } diff --git a/lib/models/messages/textmessage.dart b/lib/models/messages/textmessage.dart index c15555a6..bbbb7f23 100644 --- a/lib/models/messages/textmessage.dart +++ b/lib/models/messages/textmessage.dart @@ -26,7 +26,8 @@ class TextMessage extends Message { value: this.metadata, builder: (bcontext, child) { var formatMessages = Provider.of(bcontext).isExperimentEnabled(FormattingExperiment); - return compileMessageContentWidget(context, false, content, FocusNode(), formatMessages, false);; + return compileMessageContentWidget(context, false, content, FocusNode(), formatMessages, false); + ; }); } diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index aa10f2c9..7fdaff31 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -24,6 +24,7 @@ final TextStyle defaultMessageTextStyle = TextStyle(fontFamily: "Inter", fontWei final TextStyle defaultFormLabelTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 20); final TextStyle defaultTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12); final TextStyle defaultTextButtonStyle = defaultTextStyle.copyWith(fontWeight: FontWeight.bold); +final TextStyle defaultDropDownMenuItemTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 16); final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, @@ -205,8 +206,8 @@ ThemeData mkThemeData(Settings opaque) { textTheme: TextTheme( // NOTE: The following font scales were arrived at after consulting the material text scale // docs: https://m3.material.io/styles/typography/type-scale-tokens and some trial and error - displayMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor), displaySmall: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor), + displayMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor), displayLarge: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor), titleSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor), titleLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor), @@ -218,8 +219,8 @@ ThemeData mkThemeData(Settings opaque) { headlineMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 26.0, color: opaque.current().mainTextColor), headlineLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 28.0, color: opaque.current().mainTextColor), labelSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w100, fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor), - labelLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w200, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor), - labelMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w300, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor), + labelMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w300, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor), + labelLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w200, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor), ), switchTheme: SwitchThemeData( overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 36ec04c7..62d8cb5d 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -128,7 +128,8 @@ class _GlobalSettingsViewState extends State { items: AppLocalizations.supportedLocales.map>((Locale value) { return DropdownMenuItem( value: value.toString(), - child: Text(key: Key("dropdownLanguage" + value.languageCode), getLanguageFull(context, value.languageCode, value.countryCode)), + child: Text( + key: Key("dropdownLanguage" + value.languageCode), getLanguageFull(context, value.languageCode, value.countryCode), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList()))), SwitchListTile( @@ -165,7 +166,7 @@ class _GlobalSettingsViewState extends State { items: themes.keys.map>((String themeId) { return DropdownMenuItem( value: themeId, - child: Text(getThemeName(context, themeId)), //"ddi_$themeId", key: Key("ddi_$themeId")), + child: Text(getThemeName(context, themeId), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), //"ddi_$themeId", key: Key("ddi_$themeId")), ); }).toList())), leading: Icon(Icons.palette, color: settings.current().mainTextColor), @@ -185,7 +186,7 @@ class _GlobalSettingsViewState extends State { items: Settings.uiColumnModeOptions(false).map>((DualpaneMode value) { return DropdownMenuItem( value: value.toString(), - child: Text(Settings.uiColumnModeToString(value, context)), + child: Text(Settings.uiColumnModeToString(value, context), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList()))), ListTile( @@ -193,7 +194,6 @@ class _GlobalSettingsViewState extends State { AppLocalizations.of(context)!.settingUIColumnLandscape, textWidthBasis: TextWidthBasis.longestLine, softWrap: true, - style: TextStyle(color: settings.current().mainTextColor), ), leading: Icon(Icons.stay_primary_landscape, color: settings.current().mainTextColor), trailing: Container( @@ -210,10 +210,7 @@ class _GlobalSettingsViewState extends State { items: Settings.uiColumnModeOptions(true).map>((DualpaneMode value) { return DropdownMenuItem( value: value.toString(), - child: Text( - Settings.uiColumnModeToString(value, context), - overflow: TextOverflow.ellipsis, - ), + child: Text(Settings.uiColumnModeToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList())))), ListTile( @@ -305,10 +302,7 @@ class _GlobalSettingsViewState extends State { items: NotificationPolicy.values.map>((NotificationPolicy value) { return DropdownMenuItem( value: value, - child: Text( - Settings.notificationPolicyToString(value, context), - overflow: TextOverflow.ellipsis, - ), + child: Text(Settings.notificationPolicyToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList())), leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), @@ -328,10 +322,7 @@ class _GlobalSettingsViewState extends State { items: NotificationContent.values.map>((NotificationContent value) { return DropdownMenuItem( value: value, - child: Text( - Settings.notificationContentToString(value, context), - overflow: TextOverflow.ellipsis, - ), + child: Text(Settings.notificationContentToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList())), leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), From a2a09966e62292c14b8ac2abc968cf6dc9518514 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 14:40:55 -0700 Subject: [PATCH 14/20] More small fixes / remove extra logging --- lib/cwtch/cwtchNotifier.dart | 2 -- lib/models/contact.dart | 2 +- lib/views/globalsettingsview.dart | 4 +++- lib/views/messageview.dart | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 5788e41e..dd115db7 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -59,8 +59,6 @@ class CwtchNotifier { } void handleMessage(String type, dynamic data) { - EnvironmentConfig.debugLog("Handing Message $type ${data.toString()}"); - //EnvironmentConfig.debugLog("NewEvent $type $data"); switch (type) { case "CwtchStarted": diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 70121234..ab1e65a5 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -267,7 +267,7 @@ class ContactInfoState extends ChangeNotifier { bool canSend() { if (this.isGroup == true) { // We now have an out of sync warning so we will mark these as online... - return this.status == "Synced"; + return this.status == "Synced" && this.antispamTickets > 0; } else { return this.isOnline(); } diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 62d8cb5d..d285a5ac 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -129,7 +129,9 @@ class _GlobalSettingsViewState extends State { return DropdownMenuItem( value: value.toString(), child: Text( - key: Key("dropdownLanguage" + value.languageCode), getLanguageFull(context, value.languageCode, value.countryCode), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), + key: Key("dropdownLanguage" + value.languageCode), + getLanguageFull(context, value.languageCode, value.countryCode), + style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), ); }).toList()))), SwitchListTile( diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 15bc10aa..b421f508 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -319,9 +319,8 @@ class _MessageViewState extends State { void _sendMessage([String? ignoredParam]) { // Do this after we trim to preserve enter-behaviour... bool cannotSend = Provider.of(context, listen: false).canSend() == false; - bool performingAntiSpam = Provider.of(context, listen: false).antispamTickets == 0; bool isGroup = Provider.of(context, listen: false).isGroup; - if (cannotSend || (isGroup && performingAntiSpam)) { + if (cannotSend) { return; } From ea701546e7f39880a31881e191d10dc7a128df60 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 18 May 2023 14:44:11 -0700 Subject: [PATCH 15/20] Fixup Translate Position to minimize space when hidden --- lib/widgets/messagerow.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 59681304..0a43b93a 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -150,8 +150,8 @@ class MessageRowState extends State with SingleTickerProviderStateMi if (fromMe) { widgetRow = [ wdgSpacer, - wdgSeeReplies, wdgTranslateMessage, + wdgSeeReplies, wdgReply, actualMessage, ]; From 103c1e08b558c92b0389d088544c742e92fc90f1 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 22 May 2023 09:11:52 -0700 Subject: [PATCH 16/20] Add Support for Swedish and Swahili --- lib/l10n/intl_cy.arb | 7 +- lib/l10n/intl_da.arb | 7 +- lib/l10n/intl_de.arb | 7 +- lib/l10n/intl_el.arb | 7 +- lib/l10n/intl_en.arb | 7 +- lib/l10n/intl_es.arb | 7 +- lib/l10n/intl_fr.arb | 7 +- lib/l10n/intl_it.arb | 7 +- lib/l10n/intl_ja.arb | 7 +- lib/l10n/intl_ko.arb | 7 +- lib/l10n/intl_lb.arb | 7 +- lib/l10n/intl_nl.arb | 7 +- lib/l10n/intl_no.arb | 7 +- lib/l10n/intl_pl.arb | 7 +- lib/l10n/intl_pt.arb | 7 +- lib/l10n/intl_pt_BR.arb | 7 +- lib/l10n/intl_ro.arb | 7 +- lib/l10n/intl_ru.arb | 7 +- lib/l10n/intl_sk.arb | 9 +- lib/l10n/intl_sv.arb | 391 ++++++++++++++++++++++++++++++ lib/l10n/intl_sw.arb | 391 ++++++++++++++++++++++++++++++ lib/l10n/intl_tr.arb | 7 +- lib/views/globalsettingsview.dart | 6 + 23 files changed, 889 insertions(+), 41 deletions(-) create mode 100644 lib/l10n/intl_sv.arb create mode 100644 lib/l10n/intl_sw.arb diff --git a/lib/l10n/intl_cy.arb b/lib/l10n/intl_cy.arb index 83b9b4e6..13f56541 100644 --- a/lib/l10n/intl_cy.arb +++ b/lib/l10n/intl_cy.arb @@ -1,6 +1,10 @@ { "@@locale": "cy", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Testun maint rhagosodedig (ffactor graddfa:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_da.arb b/lib/l10n/intl_da.arb index 702a5934..bd2e7775 100644 --- a/lib/l10n/intl_da.arb +++ b/lib/l10n/intl_da.arb @@ -1,6 +1,10 @@ { "@@locale": "da", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Standard størrelse tekst (skaleringsfaktor:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 4b80e704..d4931909 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,10 @@ { "@@locale": "de", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Starten oder Stoppen des Profils", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Text in Standardgröße (Skalierungsfaktor:", "localeJa": "Japanese \/ 日本語", @@ -26,7 +30,6 @@ "profileAutostartLabel": "Autostart", "profileEnabled": "Aktivieren", "profileAutostartDescription": "Legt fest, ob das Profil beim Starten automatisch gestartet wird", - "profileEnabledDescription": "Starten oder Stoppen des Profils", "acquiringTicketsFromServer": "Antispam-Herausforderung meistern", "acquiredTicketsFromServer": "Antispam-Herausforderung abgeschlossen", "shareProfileMenuTooltop": "Profil teilen über...", diff --git a/lib/l10n/intl_el.arb b/lib/l10n/intl_el.arb index d4556bc8..3f726089 100644 --- a/lib/l10n/intl_el.arb +++ b/lib/l10n/intl_el.arb @@ -1,6 +1,10 @@ { "@@locale": "el", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Font Scaling", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index ac55acc0..f2fb3950 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,10 @@ { "@@locale": "en", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Font Scaling", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 06099453..06686bf8 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,10 @@ { "@@locale": "es", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Tamaño predeterminado de texto (factor de escala:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 5728eae9..fd406508 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,10 @@ { "@@locale": "fr", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Taille par défaut du texte (échelle:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index c61693bb..fab9b85c 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,10 @@ { "@@locale": "it", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_ja.arb b/lib/l10n/intl_ja.arb index 7e4ba409..1aff0cee 100644 --- a/lib/l10n/intl_ja.arb +++ b/lib/l10n/intl_ja.arb @@ -1,6 +1,10 @@ { "@@locale": "ja", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Font Scaling", "localeJa": "Japanese \/ 日本語", @@ -64,7 +68,6 @@ "profileInfoHint": "ブログ、ウェブサイト、簡単な経歴など、ご自身に関する公開情報をここに追加してください。", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileEnabled": "Enable", "localeNl": "Dutch \/ Dutch", "experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes", diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index 5966e50f..7a02a9d1 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -1,6 +1,10 @@ { "@@locale": "ko", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "프로필 시각 또는 중지", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Font Scaling", "localeJa": "Japanese \/ 日本語", @@ -124,7 +128,6 @@ "profileAutostartDescription": "시작 시 프로필이 자동으로 시작되는지 여부를 제어합니다.", "profileAutostartLabel": "자동 시작", "profileEnabled": "허락", - "profileEnabledDescription": "프로필 시각 또는 중지", "replyingTo": "%1에 회신", "tooltipCode": "Code \/ Monospace", "tooltipStrikethrough": "Strikethrough", diff --git a/lib/l10n/intl_lb.arb b/lib/l10n/intl_lb.arb index 7ebe3934..badfde0c 100644 --- a/lib/l10n/intl_lb.arb +++ b/lib/l10n/intl_lb.arb @@ -1,6 +1,10 @@ { "@@locale": "lb", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Font Scaling", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index fd56d378..72120675 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1,6 +1,10 @@ { "@@locale": "nl", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Start of stop het profiel", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Standaardtekstgrootte (schaalfactor:", "localeJa": "Japanese \/ 日本語", @@ -25,7 +29,6 @@ "profileAutostartDescription": "Regelt of het profiel automatisch wordt gestart bij het opstarten", "profileAutostartLabel": "Automatisch starten", "profileEnabled": "Inschakelen", - "profileEnabledDescription": "Start of stop het profiel", "localeSk": "Slowaaks \/ Slovák", "localePtBr": "Braziliaans Portugees \/ Português do Brasil", "acquiredTicketsFromServer": "Anti-spam uitdaging voltooid", diff --git a/lib/l10n/intl_no.arb b/lib/l10n/intl_no.arb index f68d4503..56917098 100644 --- a/lib/l10n/intl_no.arb +++ b/lib/l10n/intl_no.arb @@ -1,6 +1,10 @@ { "@@locale": "no", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Standard tekststørrelse (skaleringsfaktor:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 82633a30..917ad6e2 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,10 @@ { "@@locale": "pl", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Domyślny rozmiar tekstu (skalowanie:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index db81bbe9..1b1f215f 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,10 @@ { "@@locale": "pt", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Texto tamanho padrão (fator de escala: ", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_pt_BR.arb b/lib/l10n/intl_pt_BR.arb index 353fa95e..c6d157e0 100644 --- a/lib/l10n/intl_pt_BR.arb +++ b/lib/l10n/intl_pt_BR.arb @@ -1,6 +1,10 @@ { "@@locale": "pt_BR", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Texto tamanho padrão (fator de escala: ", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index c45553bb..8839ce56 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -1,6 +1,10 @@ { "@@locale": "ro", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Dimensiunea implicită a textului (factor de scară:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 20945b0e..4031680a 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,10 @@ { "@@locale": "ru", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Размер текста по умолчанию (коэффициент масштабирования:", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Start or stop the profile", "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", "profileEnabled": "Enable", "profileAutostartLabel": "Autostart", diff --git a/lib/l10n/intl_sk.arb b/lib/l10n/intl_sk.arb index a3872b93..a6ff965a 100644 --- a/lib/l10n/intl_sk.arb +++ b/lib/l10n/intl_sk.arb @@ -1,6 +1,10 @@ { "@@locale": "sk", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Spustiť alebo zastaviť profil", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Predvolená veľkosť textu (mierka):", "localeJa": "Japanese \/ 日本語", @@ -383,6 +387,5 @@ "createGroupBtn": " Vytvoriť", "defaultGroupName": "Úžasná Skupina", "createGroupTitle": "Vytvoriť Skupinu", - "profileEnabled": "Povoliť", - "profileEnabledDescription": "Spustiť alebo zastaviť profil" + "profileEnabled": "Povoliť" } \ No newline at end of file diff --git a/lib/l10n/intl_sv.arb b/lib/l10n/intl_sv.arb new file mode 100644 index 00000000..fc627774 --- /dev/null +++ b/lib/l10n/intl_sv.arb @@ -0,0 +1,391 @@ +{ + "@@locale": "sv", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Aktivera eller inaktivera profilen", + "localeSw": "Swahili \/ Kiswahili", + "createGroupTitle": "Skapa grupp", + "serverLabel": "Server", + "defaultGroupName": "Fantastisk grupp", + "createGroupBtn": "Skapa", + "profileOnionLabel": "Skicka den här adressen till personer du vill ansluta till", + "addPeerTab": "Lägg till en kontakt", + "createGroupTab": "Skapa en grupp", + "joinGroupTab": "Gå med i en grupp", + "peerAddress": "Adress", + "peerName": "Namn", + "server": "Server", + "invitation": "Inbjudan", + "groupAddr": "Adress", + "addPeer": "Lägg till kontakt", + "createGroup": "Skapa grupp", + "joinGroup": "Gå med i grupp", + "newBulletinLabel": "Ny rapport", + "postNewBulletinLabel": "Lägg upp ny rapport", + "titlePlaceholder": "titel...", + "pasteAddressToAddContact": "Klistra in en cwtch-adress, inbjudan eller nyckelpaket här för att lägga till en ny konversation", + "blocked": "Blockerad", + "search": "Sök...", + "invitationLabel": "Inbjudan", + "serverInfo": "Server info", + "serverConnectivityConnected": "Server ansluten", + "serverConnectivityDisconnected": "Server frånkopplad", + "serverSynced": "Synkroniserad", + "serverNotSynced": "Synkroniserar nya meddelanden (det kan ta lite tid)...", + "viewServerInfo": "Server info", + "groupNameLabel": "Gruppens namn", + "saveBtn": "Spara", + "inviteToGroupLabel": "Bjud in till grupp", + "inviteBtn": "Bjud in", + "deleteBtn": "Ta bort", + "update": "Uppdatera", + "searchList": "Söklista", + "peerNotOnline": "Kontakten är offline. Program kan inte användas just nu.", + "addListItemBtn": "Lägg till", + "membershipDescription": "Nedan finns en lista över användare som har skickat meddelanden till gruppen. Den kanske inte innehåller alla användare som har åtkomst till gruppen dock.", + "dmTooltip": "Klicka för DM", + "couldNotSendMsgError": "Det gick inte att skicka detta meddelande", + "acknowledgedLabel": "Bekräftad", + "pendingLabel": "Väntar", + "peerBlockedMessage": "Kontakten är blockerad", + "peerOfflineMessage": "Kontakten är offline, meddelanden kan inte levereras just nu", + "copyBtn": "Kopiera", + "newGroupBtn": "Skapa ny grupp", + "acceptGroupInviteLabel": "Vill du acceptera inbjudan till", + "acceptGroupBtn": "Acceptera", + "rejectGroupBtn": "Avvisa", + "chatBtn": "Chatt", + "bulletinsBtn": "Rapporter", + "listsBtn": "Listor", + "puzzleGameBtn": "Pussel", + "addressLabel": "Adress", + "copiedToClipboardNotification": "Kopierat till urklipp", + "displayNameLabel": "Visningsnamn", + "blockBtn": "Blockera kontakt", + "savePeerHistory": "Spara historik", + "savePeerHistoryDescription": "Avgör om historik som är kopplad till kontakten ska tas bort.", + "dontSavePeerHistory": "Rensa historik", + "unblockBtn": "Avblockera kontakt", + "editProfileTitle": "Redigera profil", + "addProfileTitle": "Lägg till en ny profil", + "profileName": "Visningsnamn", + "defaultProfileName": "Alice", + "newProfile": "Ny profil", + "editProfile": "Redigera profil", + "radioUsePassword": "Lösenord", + "radioNoPassword": "Okrypterad (inget lösenord)", + "noPasswordWarning": "Att inte använda ett lösenord på detta konto innebär att all data som lagras lokalt är okrypterat", + "yourDisplayName": "Ditt visningsnamn", + "currentPasswordLabel": "Nuvarande lösenord", + "password1Label": "Lösenord", + "password2Label": "Ange lösenordet på nytt", + "passwordErrorEmpty": "Lösenordet kan inte vara tomt", + "createProfileBtn": "Skapa profil", + "saveProfileBtn": "Spara profil", + "passwordErrorMatch": "Lösenorden matchar inte", + "passwordChangeError": "Fel vid ändring av lösenord: Det angivna lösenordet avvisades", + "deleteProfileBtn": "Ta bort profil", + "deleteConfirmLabel": "Skriv DELETE för att bekräfta", + "deleteProfileConfirmBtn": "Ta bort profilen", + "deleteConfirmText": "TA BORT", + "addNewProfileBtn": "Lägg till en ny profil", + "enterProfilePassword": "Ange ett lösenord för att se dina profiler", + "password": "Lösenord", + "error0ProfilesLoadedForPassword": "0 profiler laddade med det lösenordet", + "yourProfiles": "Dina profiler", + "yourServers": "Dina servrar", + "unlock": "Lås upp", + "cwtchSettingsTitle": "Cwtch-inställningar", + "versionBuilddate": "Version: %1 Byggd: %2", + "zoomLabel": "Gränssnittszoom (påverkar främst storleken på text och knappar)", + "blockUnknownLabel": "Blockera okända kontakter", + "settingLanguage": "Språk", + "localeEn": "Engelska \/ English", + "localeFr": "Franska \/ Français", + "localePt": "Portugisiska \/ Portuguesa", + "localeDe": "Tyska \/ Deutsch", + "settingInterfaceZoom": "Zoomnivå", + "largeTextLabel": "Stor", + "settingTheme": "Använd ljusa teman", + "themeLight": "Ljust", + "themeDark": "Mörkt", + "experimentsEnabled": "Aktivera experimentella funktioner", + "versionTor": "Version %1 med tor %2", + "version": "Version %1", + "builddate": "Byggt: %2", + "defaultScalingText": "Teckensnittsskalning", + "smallTextLabel": "Liten", + "loadingTor": "Laddar tor...", + "viewGroupMembershipTooltip": "Visa gruppmedlemskap", + "networkStatusDisconnected": "Frånkopplad från internet, kontrollera din anslutning", + "networkStatusAttemptingTor": "Försöker ansluta till Tor-nätverket", + "networkStatusConnecting": "Ansluter till nätverk och kontakter...", + "networkStatusOnline": "Uppkopplad", + "newConnectionPaneTitle": "Ny anslutning", + "addListItem": "Lägg till ett nytt listobjekt", + "addNewItem": "Lägg till ett nytt objekt i listan", + "todoPlaceholder": "Att göra...", + "localeEs": "Spanska \/ Español", + "localeIt": "Italienska \/ Italiano", + "enableGroups": "Aktivera gruppchatt", + "enterCurrentPasswordForDelete": "Ange aktuellt lösenord för att ta bort den här profilen.", + "conversationSettings": "Konversationsinställningar", + "invalidImportString": "Ogiltig importsträng", + "contactAlreadyExists": "Kontakten finns redan", + "tooltipOpenSettings": "Öppna inställningsfönstret", + "tooltipAddContact": "Lägg till en ny kontakt eller konversation", + "titleManageContacts": "Konversationer", + "tooltipUnlockProfiles": "Lås upp krypterade profiler genom att ange deras lösenord.", + "titleManageProfiles": "Hantera Cwtch-profiler", + "descriptionExperiments": "Cwtch experimentella funktioner är frivilliga. De utökar funktionaliteten av Cwtch med t.ex. gruppchatt eller integration av botar vilket försämrar säkerhet och integritet jämfört med traditionell 1:1 metadataresistent chatt.", + "descriptionExperimentsGroups": "Grupper tillåter Cwtch att ansluta till opålitlig serverinfrastruktur för att möjliggöra kommunikation med mer än en kontakt.", + "descriptionBlockUnknownConnections": "Om det här alternativet är aktiverat stängs automatiskt anslutningar från Cwtch-användare som inte finns i din kontaktlista.", + "successfullAddedContact": "Har lagts till ", + "titleManageServers": "Hantera servrar", + "inviteToGroup": "Du har blivit inbjuden att gå med i en grupp:", + "leaveConversation": "Lämna denna konversation", + "reallyLeaveThisGroupPrompt": "Är du säker på att du vill lämna den här konversationen? Alla meddelanden och attribut kommer att raderas.", + "yesLeave": "Ja, lämna denna konversation", + "newPassword": "Nytt lösenord", + "chatHistoryDefault": "Den här konversationen kommer att raderas när Cwtch stängs! Meddelandehistorik kan aktiveras per konversation via menyn Inställningar uppe till höger.", + "accepted": "Accepterad!", + "rejected": "Avvisad!", + "contactSuggestion": "Detta är ett kontaktförslag för:", + "sendAnInvitation": "Du skickade en inbjudan till:", + "torStatus": "Tor-status", + "torVersion": "Tor-version", + "resetTor": "Återställ", + "cancel": "Avbryt", + "sendMessage": "Skicka meddelande", + "sendInvite": "Skicka en kontakt- eller gruppinbjudan", + "deleteProfileSuccess": "Profilen har tagits bort", + "addServerFirst": "Du måste lägga till en server innan du kan skapa en grupp", + "nickChangeSuccess": "Profilens smeknamn har ändrats", + "createProfileToBegin": "Skapa eller lås upp en profil för att börja", + "addContactFirst": "Lägg till eller välj en kontakt för att börja chatta.", + "torNetworkStatus": "Tor nätverksstatus", + "debugLog": "Aktivera debug-logg", + "profileDeleteSuccess": "Profilen har tagits bort", + "malformedMessage": "Felaktigt meddelande", + "shutdownCwtchTooltip": "Stäng ner Cwtch", + "shutdownCwtchDialog": "Är du säker på att du vill stänga ner Cwtch? Detta kommer att stänga alla anslutningar och avsluta programmet.", + "shutdownCwtchAction": "Stäng ner Cwtch", + "shutdownCwtchDialogTitle": "Stänga ner Cwtch?", + "groupInviteSettingsWarning": "Du har blivit inbjuden att gå med i en grupp! Aktivera gruppchatt i Inställningar för att se denna inbjudan.", + "tooltipShowPassword": "Visa lösenord", + "tooltipHidePassword": "Dölj lösenordet", + "notificationNewMessageFromPeer": "Nytt meddelande från en kontakt!", + "notificationNewMessageFromGroup": "Nytt meddelande i en grupp!", + "tooltipAcceptContactRequest": "Acceptera kontaktförfrågan.", + "tooltipReplyToThisMessage": "Svara på meddelande", + "tooltipRejectContactRequest": "Neka kontaktförfrågan", + "tooltipRemoveThisQuotedMessage": "Ta bort citerat meddelande.", + "localePl": "Polska \/ Polski", + "settingUIColumnPortrait": "UI-kolumner i stående läge", + "settingUIColumnOptionSame": "Samma som stående läge", + "settingUIColumnLandscape": "UI-kolumner i liggande läge", + "settingUIColumnSingle": "Enkel", + "settingUIColumnDouble12Ratio": "Dubbel (1:2)", + "settingUIColumnDouble14Ratio": "Dubbel (1:4)", + "contactGoto": "Gå till konversation med %1", + "addContact": "Lägg till kontakt", + "addContactConfirm": "Lägg till kontakt %1", + "encryptedProfileDescription": "Genom att kryptera en profil med ett lösenord skyddas den från andra personer som också kan använda den här enheten. Krypterade profiler kan inte dekrypteras, visas eller nås förrän rätt lösenord har angetts för att låsa upp dem.", + "plainProfileDescription": "Vi rekommenderar att du skyddar dina Cwtch-profiler med ett lösenord. Om du inte anger ett lösenord för den här profilen kan alla som har åtkomst till den här enheten komma åt information om den här profilen, inklusive kontakter, meddelanden och känsliga kryptografiska nycklar.", + "placeholderEnterMessage": "Skriv ett meddelande...", + "blockedMessageMessage": "Det här meddelandet kommer från en profil som du har blockerat.", + "showMessageButton": "Visa meddelande", + "blockUnknownConnectionsEnabledDescription": "Anslutningar från okända kontakter blockeras. Du kan ändra detta i Inställningar", + "archiveConversation": "Arkivera denna konversation", + "streamerModeLabel": "Streaming\/presentationsläge", + "descriptionStreamerMode": "Aktivera för att dölja privat information (exempelvis profil och kontaktadresser) vilket kan vara lämpligt vid streaming eller presentation.", + "retrievingManifestMessage": "Hämtar filinformation...", + "openFolderButton": "Öppna mapp", + "downloadFileButton": "Ladda ner", + "labelFilename": "Filnamn", + "labelFilesize": "Storlek", + "messageEnableFileSharing": "Aktivera fildelning för att kunna se meddelandet.", + "messageFileSent": "Du skickade en fil", + "messageFileOffered": "Kontakten försöker skicka en fil till dig", + "tooltipSendFile": "Skicka fil", + "settingFileSharing": "Fildelning", + "descriptionFileSharing": "Fildelning gör att du kan skicka och ta emot filer från Cwtch-kontakter och grupper. Observera att om du delar en fil med en grupp kommer medlemmarna i den gruppen behöva ansluta direkt till dig med Cwtch för att kunna ladda ner filen.", + "titleManageProfilesShort": "Profiler", + "addServerTitle": "Lägg till server", + "editServerTitle": "Redigera server", + "serverAddress": "Serveradress", + "serverDescriptionLabel": "Serverbeskrivning", + "serverDescriptionDescription": "Din beskrivning av servern. Endast synligt för dig, kommer aldrig att delas", + "serverEnabled": "Server startad", + "serverEnabledDescription": "Starta eller stoppa servern", + "serverAutostartLabel": "Autostart", + "serverAutostartDescription": "Styr om programmet automatiskt startar servern vid start", + "saveServerButton": "Spara server", + "serversManagerTitleLong": "Servrar du är värd för", + "serversManagerTitleShort": "Servrar", + "addServerTooltip": "Lägg till server", + "unlockServerTip": "Skapa eller lås upp en server för att börja!", + "unlockProfileTip": "Skapa eller lås upp en profil för att börja!", + "enterServerPassword": "Ange lösenord för att låsa upp servern", + "settingServers": "Server-värd", + "settingServersDescription": "Server-värd gör det möjligt att vara värd för och hantera Cwtch-servrar", + "copyAddress": "Kopiera adress", + "enterCurrentPasswordForDeleteServer": "Ange lösenord för att radera den här servern", + "deleteServerSuccess": "Servern har tagits bort", + "deleteServerConfirmBtn": "Bekräfta borttagning av servern", + "plainServerDescription": "Vi rekommenderar att du skyddar dina Cwtch-servrar med ett lösenord. Om du inte anger ett lösenord på den här servern kan alla som har åtkomst till den här enheten komma åt information om den här servern, inklusive känsliga kryptografiska nycklar.", + "encryptedServerDescription": "Genom att kryptera en server med ett lösenord skyddas den från andra personer som också kan använda den här enheten. Krypterade servrar kan inte dekrypteras, visas eller nås förrän rätt lösenord har angetts för att låsa upp dem.", + "fileSavedTo": "Sparad till", + "fileInterrupted": "Avbruten", + "fileCheckingStatus": "Kontrollera status för nedladdning", + "verfiyResumeButton": "Verifiera\/återuppta", + "copyServerKeys": "Kopiera nycklar", + "localeRU": "Ryska \/ Русский", + "newMessagesLabel": "Nya meddelanden", + "importLocalServerLabel": "Importera en lokal server", + "importLocalServerSelectText": "Välj lokal server", + "importLocalServerButton": "Importera %1", + "groupsOnThisServerLabel": "Grupper jag är med i på den här servern", + "fieldDescriptionLabel": "Beskrivning", + "manageKnownServersButton": "Hantera kända servrar", + "displayNameTooltip": "Ange ett visningsnamn", + "manageKnownServersLong": "Hantera kända servrar", + "manageKnownServersShort": "Servrar", + "serverMetricsLabel": "Serverinfo", + "serverTotalMessagesLabel": "Antal meddelanden", + "serverConnectionsLabel": "Anslutningar", + "enableExperimentClickableLinks": "Aktivera klickbara länkar", + "experimentClickableLinksDescription": "Med klickbara länkar aktiverat kan du klicka på webbadresser som delas i meddelanden", + "settingImagePreviews": "Förhandsgranskningar av bilder och profilbilder", + "settingImagePreviewsDescription": "Bilder och profilbilder kommer att laddas ner och förhandsgranskas automatiskt. Vi rekommenderar att du inte aktiverar detta om du använder Cwtch med opålitliga kontakter.", + "settingDownloadFolder": "Hämtade filer", + "themeNameCwtch": "Cwtch", + "themeNameWitch": "Häxa", + "themeNameVampire": "Vampyr", + "themeNameGhost": "Spöke", + "themeNamePumpkin": "Pumpa", + "themeNameMermaid": "Sjöjungfru", + "themeNameMidnight": "Midnatt", + "themeNameNeon1": "Neon1", + "themeNameNeon2": "Neon2", + "themeColorLabel": "Färgtema", + "loadingCwtch": "Laddar Cwtch...", + "storageMigrationModalMessage": "Migrerar profiler till nytt lagringsformat. Detta kan ta några minuter...", + "msgFileTooBig": "Filstorleken får inte överstiga 10 GB", + "msgConfirmSend": "Är du säker på att du vill skicka", + "btnSendFile": "Skicka fil", + "msgAddToAccept": "Lägg till det här kontot i dina kontakter för att acceptera den här filen.", + "torSettingsEnabledAdvanced": "Aktivera avancerad Tor-konfiguration", + "torSettingsEnabledAdvancedDescription": "Använd en befintlig Tor-tjänst på ditt system, eller ändra parametrarna för Cwtch Tor-tjänst", + "torSettingsCustomSocksPort": "Anpassad SOCKS-port", + "torSettingsCustomSocksPortDescription": "Använd en anpassad port för dataanslutningar till Tor-proxyn", + "torSettingsCustomControlPort": "Anpassad kontrollport", + "torSettingsCustomControlPortDescription": "Använd en anpassad port för kontrollanslutningar till Tor-proxyn", + "torSettingsUseCustomTorServiceConfiguration": "Använd en anpassad konfiguration av Tor (torrc)", + "torSettingsUseCustomTorServiceConfigurastionDescription": "Åsidosätt standard-konfigurationen för Tor. Varning: Detta kan vara farligt. Använd bara om du vet vad du gör.", + "torSettingsErrorSettingPort": "Portnumret måste vara mellan 1 och 65535", + "fileSharingSettingsDownloadFolderDescription": "När filer laddas ned automatiskt (t.ex. bildfiler, när förhandsgranskning är aktiverat) behövs en standardplats att ladda ner filerna till.", + "fileSharingSettingsDownloadFolderTooltip": "Bläddra för att välja en annan standardmapp för nedladdade filer.", + "descriptionACNCircuitInfo": "Detaljerad information om den väg som det anonyma kommunikationsnätverket använder för att ansluta till den här konversationen.", + "labelACNCircuitInfo": "Info om ACN-vägen", + "labelTorNetwork": "Tor-nätverket", + "torSettingsEnableCache": "Lagra konsensus i cache", + "torSettingsEnabledCacheDescription": "Lagra nedladdad Tor-konsensus i cache för att återanvända nästa gång Cwtch öppnas. Detta gör att Tor kan starta snabbare. Om detta är inaktiverat kommer Cwtch rensa cache vid uppstart.", + "tooltipSelectACustomProfileImage": "Välj en anpassad profilbild", + "notificationPolicyOptIn": "Välj", + "notificationPolicyMute": "Tysta", + "conversationNotificationPolicyOptIn": "Välj", + "notificationPolicyDefaultAll": "Återställ standard", + "conversationNotificationPolicyDefault": "Standard", + "conversationNotificationPolicyNever": "Aldrig", + "notificationPolicySettingLabel": "Aviseringspolicy", + "notificationContentSettingLabel": "Aviseringsinnehåll", + "notificationPolicySettingDescription": "Styr programmets standardaviseringsbeteende", + "notificationContentSettingDescription": "Styr innehållet i konversationsaviseringar", + "settingGroupBehaviour": "Beteende", + "settingsGroupAppearance": "Utseende", + "settingsGroupExperiments": "Experiment", + "conversationNotificationPolicySettingLabel": "Policy för konversationsaviseringar", + "conversationNotificationPolicySettingDescription": "Ändra aviseringar för den här konversationen", + "notificationContentSimpleEvent": "Enkel händelse", + "notificationContentContactInfo": "Info om konversation", + "newMessageNotificationSimple": "Nytt meddelande", + "newMessageNotificationConversationInfo": "Nytt meddelande från %1", + "localeRo": "Rumänska \/ Română", + "localeLb": "Luxemburgiska \/ Lëtzebuergesch", + "localeNo": "Norska \/ Norsk", + "localeEl": "Grekiska \/ Ελληνικά", + "localeCy": "Walesiska \/ Cymraeg", + "localeDa": "Danska \/ Dansk", + "exportProfile": "Exportera profil", + "exportProfileTooltip": "Säkerhetskopiera den här profilen till en krypterad fil. Den krypterade filen kan importeras till en annan Cwtch-app.", + "importProfileTooltip": "Använd en krypterad Cwtch-säkerhetskopia för att importera en profil skapad i en annan instans av Cwtch.", + "importProfile": "Importera profil", + "failedToImportProfile": "Fel vid import av profil", + "successfullyImportedProfile": "Profilen har importerats: %profile", + "shuttingDownApp": "Stänger ner...", + "clickableLinksWarning": "Om du öppnar den här webbadressen startar en applikation utanför Cwtch som kan avslöja metadata eller på annat sätt äventyra säkerheten för Cwtch. Öppna bara webbadresser från personer du litar på. Är du säker på att du vill fortsätta?", + "clickableLinkOpen": "Öppna URL", + "clickableLinksCopy": "Kopiera URL", + "clickableLinkError": "Fel uppstod vid försök att öppna URL", + "formattingExperiment": "Meddelandeformatering", + "messageFormattingDescription": "Aktivera RTF-formatering i visade meddelanden, t.ex. **fet** och *kursiv*", + "thisFeatureRequiresGroupExpermientsToBeEnabled": "Den här funktionen kräver att Grupper är aktiverat i Inställningar.", + "settingAndroidPowerExemption": "Undanta Android batterioptimering", + "settingAndroidPowerExemptionDescription": "Valfritt: Begär att Android ska undanta Cwtch från optimerad energihantering. Detta kommer att leda till bättre stabilitet till priset av större batterianvändning.", + "settingsAndroidPowerReenablePopup": "Det går inte att aktivera batterioptimering från Cwtch. Gå till Android \/ Inställningar \/ Appar \/ Cwtch \/ Batteri och välj \"Optimerad\"", + "okButton": "OK", + "tooltipBoldText": "Fet", + "tooltipBackToMessageEditing": "Tillbaka till meddelanderedigering", + "tooltipItalicize": "Kursiv", + "tooltipSuperscript": "Upphöjd", + "tooltipSubscript": "Nedsänkt", + "tooltipStrikethrough": "Överstruket", + "tooltipCode": "Kod \/ Monospace", + "tooltipPreviewFormatting": "Förhandsgranska meddelandeformatering", + "manageSharedFiles": "Hantera delade filer", + "stopSharingFile": "Sluta dela fil", + "restartFileShare": "Dela fil", + "viewReplies": "Visa svar på detta meddelande", + "headingReplies": "Svar", + "messageNoReplies": "Det finns inga svar på detta meddelande.", + "fileDownloadUnavailable": "Den här filen verkar inte vara tillgänglig för nedladdning. Avsändaren kan ha inaktiverat nedladdningar för den här filen.", + "replyingTo": "Svarar %1", + "tooltipPinConversation": "Fäst konversationen högst upp i \"Konversationer\".", + "tooltipUnpinConversation": "Ta bort konversationen från toppen av \"Konversationer\"", + "localeTr": "Turkiska \/ Türk", + "errorDownloadDirectoryDoesNotExist": "Fildelning kan inte aktiveras eftersom nedladdningsmappen inte har ställts in eller är inställd på en mapp som inte finns.", + "acquiringTicketsFromServer": "Utför Antispam-test", + "acquiredTicketsFromServer": "Antispam-testet slutfört", + "shareProfileMenuTooltop": "Dela profil via...", + "shareMenuQRCode": "Visa QR-kod", + "enableExperimentQRCode": "QR-koder", + "experimentQRCodeDescription": "QR-kodstöd tillåter delning av data (som profilidentitet) med QR-koder", + "localeNl": "Nederländska \/ Dutch", + "localePtBr": "Brasiliansk portugisiska \/ Português do Brasil", + "profileAutostartLabel": "Starta automatiskt", + "profileEnabled": "Aktivera", + "profileAutostartDescription": "Styr om profilen ska startas automatiskt vid programstart", + "localeSk": "Slovakiska \/ Slovák", + "localeKo": "Koreanska \/ 한국어", + "blodeuweddExperimentEnable": "Blodeuwedd-assistenten", + "blodeuweddDescription": "Blodeuwedd-assistenten lägger till nya funktioner till Cwtch, såsom sammanfattning av koversationer och meddelandeöversättning. Allt via en språkmodell som körs i datorn.", + "blodeuweddNotSupported": "Denna version av Cwtch har kompilerats utan stöd för Blodeuwedd-assistenten.", + "blodeuweddPath": "Katalogen där Blodeuwedd finns på din dator.", + "blodeuweddSummarize": "Sammanfatta konversation", + "blodeuweddTranslate": "Översätt meddelande", + "blodeuweddWarning": "Blodeuwedd använder en lokal språkmodell och en uppsättning små hjälpmodeller för att driva dess funktionalitet. Dessa tekniker är ofta mycket effektiva, de är inte felfria.\n\nÄven om vi har vidtagit åtgärder för att minimera risken, finns det fortfarande en möjlighet att data från Blodeuwedd kan vara felaktigt, missvisande och\/eller stötande.\n\nPå grund av det kräver Blodeuwedd nedladdning av två ytterligare komponenter separat från Cwtch, Blodeuwedd Model (eller annan kompatibel modell) och Blodeuwedd Runner.\n\nLäs på https:\/\/docs.cwtch.im\/docs\/settings\/experiments\/blodeuwedd för mer information om hur du skaffar dessa komponenter och konfigurerar dem.", + "blodeuweddProcessing": "Blodeuwedd arbetar...", + "availabilityStatusAvailable": "Tillgänglig", + "availabilityStatusAway": "Borta", + "availabilityStatusBusy": "Upptagen", + "availabilityStatusTooltip": "Ange tillgänglighetsstatus", + "profileInfoHint": "Lägg till lite offentlig information om dig själv här, t.ex. blogg, webbplatser, kortfattad biografi.", + "profileInfoHint2": "Du kan lägga till upp till 3 fält.", + "profileInfoHint3": "Kontakter kommer att kunna se denna information under konversationsinställningar", + "retryConnection": "Försök igen", + "retryConnectionTooltip": "Cwtch försöker ansluta till noder regelbundet, men du kan be Cwtch att försöka tidigare genom att trycka på den här knappen.", + "localeSv": "Svenska \/ Svenska", + "localeJa": "Japanska \/ 日本語", + "fontScalingDescription": "Justera den relativa skalningsfaktorn för teckensnitt som tillämpas på text och widgets." +} \ No newline at end of file diff --git a/lib/l10n/intl_sw.arb b/lib/l10n/intl_sw.arb new file mode 100644 index 00000000..1242cd57 --- /dev/null +++ b/lib/l10n/intl_sw.arb @@ -0,0 +1,391 @@ +{ + "@@locale": "sw", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", + "localeSv": "Kiswidi \/ Svenska", + "localeJa": "Kijapani \/ 日本語", + "localeSw": "Kiswahili \/ Kiswahili", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "retryConnectionTooltip": "Cwtch retries peers regularly, but you can tell Cwtch to try sooner by pushing this button.", + "retryConnection": "Retry", + "profileInfoHint3": "Contacts will be able to see this information in Conversation Settings ", + "profileInfoHint2": "You can add up to 3 fields.", + "profileInfoHint": "Add some public information about yourself here e.g. blog, websites, brief bio.", + "availabilityStatusTooltip": "Set your availability status", + "availabilityStatusBusy": "Busy", + "availabilityStatusAway": "Away", + "availabilityStatusAvailable": "Available", + "blodeuweddWarning": "Blodeuwedd uses a local language model and a set of small auxiliary models to power its functionality. These techniques are often very effective they are not without error. \n\nWhile we have taken efforts to minimize the risk, there is still the possibility that Blodeuwedd outputs will be incorrect, hallucinated and\/or offensive.\n\nBecause of that Blodeuwedd requires downloading two additional components separate from Cwtch, the Blodeuwedd Model (or a compatible model) and the Blodeuwedd Runner. \n\nSee https:\/\/docs.cwtch.im\/docs\/settings\/experiments\/blodeuwedd for more information on obtaining these components and setting them up.", + "blodeuweddProcessing": "Blodeuwedd is processing...", + "blodeuweddTranslate": "Translate Message", + "blodeuweddSummarize": "Summarize Conversation", + "blodeuweddPath": "The directory where the Blodeuwedd is located on your computer.", + "blodeuweddNotSupported": "This version of Cwtch has been compiled without support for the Blodeuwedd Assistant.", + "blodeuweddDescription": "The Blodeuwedd assistant adds new features to Cwtch such as chat transcript summarization and message translation via a locally hosted language model.", + "blodeuweddExperimentEnable": "Blodeuwedd Assistant", + "localeKo": "Korean \/ 한국어", + "localeSk": "Slovak \/ Slovák", + "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", + "profileEnabled": "Enable", + "profileAutostartLabel": "Autostart", + "localePtBr": "Brazilian Portuguese \/ Português do Brasil", + "localeNl": "Dutch \/ Dutch", + "experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes", + "enableExperimentQRCode": "QR Codes", + "shareMenuQRCode": "Show QR Code", + "shareProfileMenuTooltop": "Share profile via...", + "acquiredTicketsFromServer": "Antispam Challenge Complete", + "acquiringTicketsFromServer": "Performing Antispam Challenge", + "errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.", + "localeTr": "Turkish \/ Türk", + "tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"", + "tooltipPinConversation": "Pin conversation to the top of \"Conversations\"", + "replyingTo": "Replying to %1", + "fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.", + "messageNoReplies": "There are no replies to this message.", + "headingReplies": "Replies", + "viewReplies": "View replies to this message", + "restartFileShare": "Start Sharing File", + "stopSharingFile": "Stop Sharing File", + "manageSharedFiles": "Manage Shared Files", + "tooltipPreviewFormatting": "Preview Message Formatting", + "tooltipCode": "Code \/ Monospace", + "tooltipStrikethrough": "Strikethrough", + "tooltipSubscript": "Subscript", + "tooltipSuperscript": "Superscript", + "tooltipItalicize": "Italic", + "tooltipBackToMessageEditing": "Back to Message Editing", + "tooltipBoldText": "Bold", + "okButton": "OK", + "settingsAndroidPowerReenablePopup": "Cannot re-enable Battery Optimization from within Cwtch. Please go to Android \/ Settings \/ Apps \/ Cwtch \/ Battery and set Usage to 'Optimized'", + "settingAndroidPowerExemptionDescription": "Optional: Request Android to exempt Cwtch from optimized power management. This will result in better stability at the cost of greater battery use.", + "settingAndroidPowerExemption": "Android Ignore Battery Optimizations", + "thisFeatureRequiresGroupExpermientsToBeEnabled": "This feature requires the Groups Experiment to be enabled in Settings", + "messageFormattingDescription": "Enable rich text formatting in displayed messages e.g. **bold** and *italic*", + "formattingExperiment": "Message Formatting", + "clickableLinkError": "Error encountered while attempting to open URL", + "clickableLinksCopy": "Copy URL", + "clickableLinkOpen": "Open URL", + "clickableLinksWarning": "Opening this URL will launch an application outside of Cwtch and may reveal metadata or otherwise compromise the security of Cwtch. Only open URLs from people you trust. Are you sure you want to continue?", + "shuttingDownApp": "Shutting down...", + "successfullyImportedProfile": "Successfully Imported Profile: %profile", + "failedToImportProfile": "Error Importing Profile", + "importProfileTooltip": "Use an encrypted Cwtch backup to bring in a profile created in another instance of Cwtch.", + "importProfile": "Import Profile", + "exportProfileTooltip": "Backup this profile to an encrypted file. The encrypted file can be imported into another Cwtch app.", + "exportProfile": "Export Profile", + "localeDa": "Danish \/ Dansk", + "localeCy": "Welsh \/ Cymraeg", + "localeEl": "Greek \/ Ελληνικά", + "localeNo": "Norwegian \/ Norsk", + "localeLb": "Luxembourgish \/ Lëtzebuergesch", + "localeRo": "Romanian \/ Română", + "newMessageNotificationConversationInfo": "New Message From %1", + "newMessageNotificationSimple": "New Message", + "notificationContentContactInfo": "Conversation Information", + "notificationContentSimpleEvent": "Plain Event", + "conversationNotificationPolicySettingDescription": "Control notification behaviour for this conversation", + "conversationNotificationPolicySettingLabel": "Conversation Notification Policy", + "settingsGroupExperiments": "Experiments", + "settingsGroupAppearance": "Appearance", + "settingGroupBehaviour": "Behaviour", + "notificationContentSettingDescription": "Controls the contents of conversation notifications", + "notificationPolicySettingDescription": "Controls the default application notification behaviour", + "notificationContentSettingLabel": "Notification Content", + "notificationPolicySettingLabel": "Notification Policy", + "conversationNotificationPolicyNever": "Never", + "conversationNotificationPolicyOptIn": "Opt In", + "conversationNotificationPolicyDefault": "Default", + "notificationPolicyDefaultAll": "Default All", + "notificationPolicyOptIn": "Opt In", + "notificationPolicyMute": "Mute", + "tooltipSelectACustomProfileImage": "Select a Custom Profile Image", + "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", + "torSettingsEnableCache": "Cache Tor Consensus", + "labelTorNetwork": "Tor Network", + "descriptionACNCircuitInfo": "In depth information about the path that the anonymous communication network is using to connect to this conversation.", + "labelACNCircuitInfo": "ACN Circuit Info", + "fileSharingSettingsDownloadFolderTooltip": "Browse to select a different default folder for downloaded files.", + "fileSharingSettingsDownloadFolderDescription": "When files are downloaded automatically (e.g. image files, when image previews are enabled) a default location to download the files to is needed.", + "torSettingsErrorSettingPort": "Port Number must be between 1 and 65535", + "torSettingsUseCustomTorServiceConfigurastionDescription": "Override the default tor configuration. Warning: This could be dangerous. Only turn this on if you know what you are doing.", + "torSettingsUseCustomTorServiceConfiguration": "Use a Custom Tor Service Configuration (torrc)", + "torSettingsCustomControlPortDescription": "Use a custom port for control connections to the Tor proxy", + "torSettingsCustomControlPort": "Custom Control Port", + "torSettingsCustomSocksPortDescription": "Use a custom port for data connections to the Tor proxy", + "torSettingsCustomSocksPort": "Custom SOCKS Port", + "torSettingsEnabledAdvancedDescription": "Use an existing Tor service on your system, or change the parameters of the Cwtch Tor Service", + "torSettingsEnabledAdvanced": "Enable Advanced Tor Configuration", + "msgAddToAccept": "Add this account to your contacts in order to accept this file.", + "btnSendFile": "Send File", + "msgConfirmSend": "Are you sure you want to send", + "msgFileTooBig": "File size cannot exceed 10 GB", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images and Profile Pictures will be downloaded and previewed automatically. We recommend that you do not enable this Experiment if you use Cwtch with untrusted contacts.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "newMessagesLabel": "New Messages", + "localeRU": "Russian \/ Русский", + "copyServerKeys": "Copy keys", + "verfiyResumeButton": "Verify\/resume", + "fileCheckingStatus": "Checking download status", + "fileInterrupted": "Interrupted", + "fileSavedTo": "Saved to", + "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", + "deleteServerConfirmBtn": "Really delete server", + "deleteServerSuccess": "Successfully deleted server", + "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", + "copyAddress": "Copy Address", + "settingServersDescription": "The hosting servers experiment enables hosting and managing Cwtch servers", + "settingServers": "Hosting Servers", + "enterServerPassword": "Enter password to unlock server", + "unlockProfileTip": "Please create or unlock a profile to begin!", + "unlockServerTip": "Please create or unlock a server to begin!", + "addServerTooltip": "Add new server", + "serversManagerTitleShort": "Servers", + "serversManagerTitleLong": "Servers You Host", + "saveServerButton": "Save Server", + "serverAutostartDescription": "Controls if the application will automatically launch the server on start", + "serverAutostartLabel": "Autostart", + "serverEnabledDescription": "Start or stop the server", + "serverEnabled": "Server Enabled", + "serverDescriptionDescription": "Your description of the server for personal management use only, will never be shared", + "serverDescriptionLabel": "Server Description", + "serverAddress": "Server Address", + "editServerTitle": "Edit Server", + "addServerTitle": "Add Server", + "titleManageProfilesShort": "Profiles", + "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", + "settingFileSharing": "File Sharing", + "tooltipSendFile": "Send File", + "messageFileOffered": "Contact is offering to send you a file", + "messageFileSent": "You sent a file", + "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", + "labelFilesize": "Size", + "labelFilename": "Filename", + "downloadFileButton": "Download", + "openFolderButton": "Open Folder", + "retrievingManifestMessage": "Retrieving file information...", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", + "streamerModeLabel": "Streamer\/Presentation Mode", + "archiveConversation": "Archive this Conversation", + "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", + "showMessageButton": "Show Message", + "blockedMessageMessage": "This message is from a profile you have blocked.", + "placeholderEnterMessage": "Type a message...", + "plainProfileDescription": "We recommend that you protect your Cwtch profiles with a password. If you do not set a password on this profile then anyone who has access to this device may be able to access information about this profile, including contacts, messages and sensitive cryptographic keys.", + "encryptedProfileDescription": "Encrypting a profile with a password protects it from other people who may also use this device. Encrypted profiles cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "addContactConfirm": "Add contact %1", + "addContact": "Add contact", + "contactGoto": "Go to conversation with %1", + "settingUIColumnOptionSame": "Same as portrait mode setting", + "settingUIColumnDouble14Ratio": "Double (1:4)", + "settingUIColumnDouble12Ratio": "Double (1:2)", + "settingUIColumnSingle": "Single", + "settingUIColumnLandscape": "UI Columns in Landscape Mode", + "settingUIColumnPortrait": "UI Columns in Portrait Mode", + "localePl": "Polish \/ Polski", + "tooltipRemoveThisQuotedMessage": "Remove quoted message.", + "tooltipReplyToThisMessage": "Reply to this message", + "tooltipRejectContactRequest": "Reject this contact request", + "tooltipAcceptContactRequest": "Accept this contact request.", + "notificationNewMessageFromGroup": "New message in a group!", + "notificationNewMessageFromPeer": "New message from a contact!", + "tooltipHidePassword": "Hide Password", + "tooltipShowPassword": "Show Password", + "groupInviteSettingsWarning": "You have been invited to join a group! Please enable the Group Chat Experiment in Settings to view this Invitation.", + "shutdownCwtchAction": "Shutdown Cwtch", + "shutdownCwtchDialog": "Are you sure you want to shutdown Cwtch? This will close all connections, and exit the application.", + "shutdownCwtchDialogTitle": "Shutdown Cwtch?", + "shutdownCwtchTooltip": "Shutdown Cwtch", + "malformedMessage": "Malformed message", + "profileDeleteSuccess": "Successfully deleted profile", + "debugLog": "Turn on console debug logging", + "torNetworkStatus": "Tor network status", + "addContactFirst": "Add or pick a contact to begin chatting.", + "createProfileToBegin": "Please create or unlock a profile to begin", + "nickChangeSuccess": "Profile nickname changed successfully", + "addServerFirst": "You need to add a server before you can create a group", + "deleteProfileSuccess": "Successfully deleted profile", + "sendInvite": "Send a contact or group invite", + "sendMessage": "Send Message", + "cancel": "Cancel", + "resetTor": "Reset", + "torStatus": "Tor Status", + "torVersion": "Tor Version", + "sendAnInvitation": "You sent an invitation for: ", + "contactSuggestion": "This is a contact suggestion for: ", + "rejected": "Rejected!", + "accepted": "Accepted!", + "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.", + "newPassword": "New Password", + "yesLeave": "Yes, Leave This Conversation", + "reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.", + "leaveConversation": "Leave This Conversation", + "inviteToGroup": "You have been invited to join a group:", + "titleManageServers": "Manage Servers", + "successfullAddedContact": "Successfully added ", + "descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.", + "descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.", + "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.", + "titleManageProfiles": "Manage Cwtch Profiles", + "tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.", + "titleManageContacts": "Conversations", + "tooltipAddContact": "Add a new contact or conversation", + "tooltipOpenSettings": "Open the settings pane", + "contactAlreadyExists": "Contact Already Exists", + "invalidImportString": "Invalid import string", + "conversationSettings": "Conversation Settings", + "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", + "enableGroups": "Enable Group Chat", + "localeIt": "Italian \/ Italiano", + "localeEs": "Spanish \/ Español", + "todoPlaceholder": "Todo...", + "addNewItem": "Add a new item to the list", + "addListItem": "Add a New List Item", + "newConnectionPaneTitle": "New Connection", + "networkStatusOnline": "Online", + "networkStatusConnecting": "Connecting to network and contacts...", + "networkStatusAttemptingTor": "Attempting to connect to Tor network", + "networkStatusDisconnected": "Disconnected from the internet, check your connection", + "viewGroupMembershipTooltip": "View Group Membership", + "loadingTor": "Loading tor...", + "smallTextLabel": "Small", + "defaultScalingText": "Font Scaling", + "builddate": "Built on: %2", + "version": "Version %1", + "versionTor": "Version %1 with tor %2", + "experimentsEnabled": "Enable Experiments", + "themeDark": "Dark", + "themeLight": "Light", + "settingTheme": "Use Light Themes", + "largeTextLabel": "Large", + "settingInterfaceZoom": "Zoom level", + "localeDe": "German \/ Deutsch", + "localePt": "Portuguese \/ Portuguesa", + "localeFr": "French \/ Français", + "localeEn": "English \/ English", + "settingLanguage": "Language", + "blockUnknownLabel": "Block Unknown Contacts", + "zoomLabel": "Interface zoom (mostly affects text and button sizes)", + "versionBuilddate": "Version: %1 Built on: %2", + "cwtchSettingsTitle": "Cwtch Settings", + "unlock": "Unlock", + "yourServers": "Your Servers", + "yourProfiles": "Your Profiles", + "error0ProfilesLoadedForPassword": "0 profiles loaded with that password", + "password": "Password", + "enterProfilePassword": "Enter a password to view your profiles", + "addNewProfileBtn": "Add new profile", + "deleteConfirmText": "DELETE", + "deleteProfileConfirmBtn": "Really Delete Profile", + "deleteConfirmLabel": "Type DELETE to confirm", + "deleteProfileBtn": "Delete Profile", + "passwordChangeError": "Error changing password: Supplied password rejected", + "passwordErrorMatch": "Passwords do not match", + "saveProfileBtn": "Save Profile", + "createProfileBtn": "Create Profile", + "passwordErrorEmpty": "Password cannot be empty", + "password2Label": "Reenter password", + "password1Label": "Password", + "currentPasswordLabel": "Current Password", + "yourDisplayName": "Your Display Name", + "profileOnionLabel": "Send this address to contacts you want to connect with", + "noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted", + "radioNoPassword": "Unencrypted (No password)", + "radioUsePassword": "Password", + "editProfile": "Edit Profile", + "newProfile": "New Profile", + "defaultProfileName": "Alice", + "profileName": "Display name", + "editProfileTitle": "Edit Profile", + "addProfileTitle": "Add new profile", + "deleteBtn": "Delete", + "unblockBtn": "Unblock Contact", + "dontSavePeerHistory": "Delete History", + "savePeerHistoryDescription": "Determines whether to delete any history associated with the contact.", + "savePeerHistory": "Save History", + "blockBtn": "Block Contact", + "saveBtn": "Save", + "displayNameLabel": "Display Name", + "copiedToClipboardNotification": "Copied to Clipboard", + "addressLabel": "Address", + "puzzleGameBtn": "Puzzle Game", + "bulletinsBtn": "Bulletins", + "listsBtn": "Lists", + "chatBtn": "Chat", + "rejectGroupBtn": "Reject", + "acceptGroupBtn": "Accept", + "acceptGroupInviteLabel": "Do you want to accept the invitation to", + "newGroupBtn": "Create new group", + "copyBtn": "Copy", + "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", + "peerBlockedMessage": "Contact is blocked", + "pendingLabel": "Pending", + "acknowledgedLabel": "Acknowledged", + "couldNotSendMsgError": "Could not send this message", + "dmTooltip": "Click to DM", + "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.", + "addListItemBtn": "Add Item", + "peerNotOnline": "Contact is offline. Applications cannot be used right now.", + "searchList": "Search List", + "update": "Update", + "inviteBtn": "Invite", + "inviteToGroupLabel": "Invite to group", + "groupNameLabel": "Group Name", + "viewServerInfo": "Server Info", + "serverNotSynced": "Syncing New Messages (This can take some time)...", + "serverSynced": "Synced", + "serverConnectivityDisconnected": "Server Disconnected", + "serverConnectivityConnected": "Server Connected", + "serverInfo": "Server Information", + "invitationLabel": "Invitation", + "serverLabel": "Server", + "search": "Search...", + "blocked": "Blocked", + "pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation", + "titlePlaceholder": "title...", + "postNewBulletinLabel": "Post new bulletin", + "newBulletinLabel": "New Bulletin", + "joinGroup": "Join group", + "createGroup": "Create group", + "addPeer": "Add Contact", + "groupAddr": "Address", + "invitation": "Invitation", + "server": "Server", + "peerName": "Name", + "peerAddress": "Address", + "joinGroupTab": "Join a group", + "createGroupTab": "Create a group", + "addPeerTab": "Add a contact", + "createGroupBtn": "Create", + "defaultGroupName": "Awesome Group", + "createGroupTitle": "Create Group" +} \ No newline at end of file diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index bb84b074..c8ce566a 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -1,6 +1,10 @@ { "@@locale": "tr", - "@@last_modified": "2023-05-15T21:16:36+02:00", + "@@last_modified": "2023-05-22T18:04:36+02:00", + "localeUk": "Ukrainian \/ українською", + "profileEnabledDescription": "Profili başlat veya durdur", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "defaultScalingText": "Varsayılan metin boyutu (ölçek faktörü: ", "localeJa": "Japanese \/ 日本語", @@ -23,7 +27,6 @@ "blodeuweddExperimentEnable": "Blodeuwedd Assistant", "localeKo": "Korean \/ 한국어", "localeSk": "Slovak \/ Slovák", - "profileEnabledDescription": "Profili başlat veya durdur", "profileAutostartLabel": "Otomatik başlatma", "profileAutostartDescription": "Profilin başlangıçta otomatik olarak başlatılıp başlatılmayacağını kontrol eder", "profileEnabled": "Etkinleştir", diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index d285a5ac..6c9c8067 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -740,6 +740,12 @@ String getLanguageFull(context, String languageCode, String? countryCode) { if (languageCode == "ja") { return AppLocalizations.of(context)!.localeJa; } + if (languageCode == "sv") { + return AppLocalizations.of(context)!.localeSv; + } + if (languageCode == "sw") { + return AppLocalizations.of(context)!.localeSw; + } return languageCode; } From 2d1808972125fe48c815c51ccab0bcf8a042b878 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Tue, 23 May 2023 11:01:29 -0700 Subject: [PATCH 17/20] More font fixups --- lib/themes/opaque.dart | 10 +++++++--- lib/views/globalsettingsview.dart | 8 +++++--- lib/views/groupsettingsview.dart | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 7fdaff31..ff1300eb 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -184,6 +184,7 @@ ThemeData mkThemeData(Settings opaque) { ? opaque.current().defaultButtonDisabledColor : null), enableFeedback: true, + textStyle: MaterialStateProperty.all(opaque.scaleFonts(defaultTextButtonStyle)), padding: MaterialStateProperty.all(EdgeInsets.all(20)), shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius: BorderRadius.circular(6.0), @@ -193,9 +194,12 @@ ThemeData mkThemeData(Settings opaque) { scrollbarTheme: ScrollbarThemeData(isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)), tabBarTheme: TabBarTheme( - labelColor: opaque.current().mainTextColor, - unselectedLabelColor: opaque.current().mainTextColor, - indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor))), + labelColor: opaque.current().mainTextColor, + unselectedLabelColor: opaque.current().mainTextColor, + indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor)), + labelStyle: opaque.scaleFonts(defaultTextButtonStyle), + unselectedLabelStyle: opaque.scaleFonts(defaultTextStyle), + ), dialogTheme: DialogTheme( backgroundColor: opaque.current().backgroundPaneColor, titleTextStyle: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, color: opaque.current().mainTextColor), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 6c9c8067..a213931a 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -129,9 +129,11 @@ class _GlobalSettingsViewState extends State { return DropdownMenuItem( value: value.toString(), child: Text( - key: Key("dropdownLanguage" + value.languageCode), - getLanguageFull(context, value.languageCode, value.countryCode), - style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), + key: Key("dropdownLanguage" + value.languageCode), + getLanguageFull(context, value.languageCode, value.countryCode), + style: settings.scaleFonts(defaultDropDownMenuItemTextStyle), + overflow: TextOverflow.ellipsis, + ), ); }).toList()))), SwitchListTile( diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 492c0847..275b7636 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -2,6 +2,7 @@ import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:flutter/services.dart'; import 'package:cwtch/widgets/buttontextfield.dart'; import 'package:cwtch/widgets/cwtchlabel.dart'; @@ -180,7 +181,7 @@ class _GroupSettingsViewState extends State { icon: Icon(CwtchIcons.leave_group), label: Text( AppLocalizations.of(context)!.leaveConversation, - style: TextStyle(decoration: TextDecoration.underline), + style: settings.scaleFonts(defaultTextButtonStyle.copyWith(decoration: TextDecoration.underline)), ), )) ]) From 3f262afcac7f328ce6c2d9ac300ff150d34f2671 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Tue, 23 May 2023 11:05:02 -0700 Subject: [PATCH 18/20] Add support for Ukrainian and additional Swahili translations --- lib/l10n/intl_cy.arb | 2 +- lib/l10n/intl_da.arb | 2 +- lib/l10n/intl_de.arb | 2 +- lib/l10n/intl_el.arb | 2 +- lib/l10n/intl_en.arb | 2 +- lib/l10n/intl_es.arb | 2 +- lib/l10n/intl_fr.arb | 2 +- lib/l10n/intl_it.arb | 2 +- lib/l10n/intl_ja.arb | 2 +- lib/l10n/intl_ko.arb | 2 +- lib/l10n/intl_lb.arb | 2 +- lib/l10n/intl_nl.arb | 2 +- lib/l10n/intl_no.arb | 2 +- lib/l10n/intl_pl.arb | 2 +- lib/l10n/intl_pt.arb | 2 +- lib/l10n/intl_pt_BR.arb | 2 +- lib/l10n/intl_ro.arb | 2 +- lib/l10n/intl_ru.arb | 2 +- lib/l10n/intl_sk.arb | 2 +- lib/l10n/intl_sv.arb | 4 +- lib/l10n/intl_sw.arb | 20 +- lib/l10n/intl_tr.arb | 2 +- lib/l10n/intl_uk.arb | 391 ++++++++++++++++++++++++++++++ lib/views/globalsettingsview.dart | 3 + 24 files changed, 426 insertions(+), 32 deletions(-) create mode 100644 lib/l10n/intl_uk.arb diff --git a/lib/l10n/intl_cy.arb b/lib/l10n/intl_cy.arb index 13f56541..188f2034 100644 --- a/lib/l10n/intl_cy.arb +++ b/lib/l10n/intl_cy.arb @@ -1,6 +1,6 @@ { "@@locale": "cy", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_da.arb b/lib/l10n/intl_da.arb index bd2e7775..5dade851 100644 --- a/lib/l10n/intl_da.arb +++ b/lib/l10n/intl_da.arb @@ -1,6 +1,6 @@ { "@@locale": "da", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index d4931909..06275f15 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,6 @@ { "@@locale": "de", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Starten oder Stoppen des Profils", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_el.arb b/lib/l10n/intl_el.arb index 3f726089..6e3448f6 100644 --- a/lib/l10n/intl_el.arb +++ b/lib/l10n/intl_el.arb @@ -1,6 +1,6 @@ { "@@locale": "el", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f2fb3950..af6c527f 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,6 @@ { "@@locale": "en", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 06686bf8..b4bc9708 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,6 @@ { "@@locale": "es", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index fd406508..1b6201e6 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,6 @@ { "@@locale": "fr", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index fab9b85c..9af8c251 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,6 @@ { "@@locale": "it", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ja.arb b/lib/l10n/intl_ja.arb index 1aff0cee..16d39d97 100644 --- a/lib/l10n/intl_ja.arb +++ b/lib/l10n/intl_ja.arb @@ -1,6 +1,6 @@ { "@@locale": "ja", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index 7a02a9d1..a64db5c8 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -1,6 +1,6 @@ { "@@locale": "ko", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "프로필 시각 또는 중지", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_lb.arb b/lib/l10n/intl_lb.arb index badfde0c..16379fcd 100644 --- a/lib/l10n/intl_lb.arb +++ b/lib/l10n/intl_lb.arb @@ -1,6 +1,6 @@ { "@@locale": "lb", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index 72120675..ac616a48 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1,6 +1,6 @@ { "@@locale": "nl", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Start of stop het profiel", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_no.arb b/lib/l10n/intl_no.arb index 56917098..8dc6e2a5 100644 --- a/lib/l10n/intl_no.arb +++ b/lib/l10n/intl_no.arb @@ -1,6 +1,6 @@ { "@@locale": "no", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 917ad6e2..de43d5c5 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,6 @@ { "@@locale": "pl", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 1b1f215f..02fa9cda 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,6 @@ { "@@locale": "pt", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pt_BR.arb b/lib/l10n/intl_pt_BR.arb index c6d157e0..11f1cdc7 100644 --- a/lib/l10n/intl_pt_BR.arb +++ b/lib/l10n/intl_pt_BR.arb @@ -1,6 +1,6 @@ { "@@locale": "pt_BR", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index 8839ce56..efe626b4 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -1,6 +1,6 @@ { "@@locale": "ro", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 4031680a..87265757 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,6 @@ { "@@locale": "ru", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_sk.arb b/lib/l10n/intl_sk.arb index a6ff965a..77feb2c0 100644 --- a/lib/l10n/intl_sk.arb +++ b/lib/l10n/intl_sk.arb @@ -1,6 +1,6 @@ { "@@locale": "sk", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Spustiť alebo zastaviť profil", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_sv.arb b/lib/l10n/intl_sv.arb index fc627774..3b6e485b 100644 --- a/lib/l10n/intl_sv.arb +++ b/lib/l10n/intl_sv.arb @@ -1,7 +1,7 @@ { "@@locale": "sv", - "@@last_modified": "2023-05-22T18:04:36+02:00", - "localeUk": "Ukrainian \/ українською", + "@@last_modified": "2023-05-23T17:30:29+02:00", + "localeUk": "Ukrainska \/ українською", "profileEnabledDescription": "Aktivera eller inaktivera profilen", "localeSw": "Swahili \/ Kiswahili", "createGroupTitle": "Skapa grupp", diff --git a/lib/l10n/intl_sw.arb b/lib/l10n/intl_sw.arb index 1242cd57..34da932f 100644 --- a/lib/l10n/intl_sw.arb +++ b/lib/l10n/intl_sw.arb @@ -1,21 +1,21 @@ { "@@locale": "sw", - "@@last_modified": "2023-05-22T18:04:36+02:00", - "localeUk": "Ukrainian \/ українською", + "@@last_modified": "2023-05-23T17:30:29+02:00", + "availabilityStatusAvailable": "Inapatikana", + "availabilityStatusAway": "Sipo karibu", + "availabilityStatusTooltip": "Weka hali ya upatikanaji wako", + "profileInfoHint": "Ongeza taarifa za umma kukuhusu hapa kwa mfano blogu, tovuti, wasifu mfupi.", + "profileInfoHint2": "Unaweza kuongeza hadi sehemu 3.", + "profileInfoHint3": "Anwani zitaweza kuona maelezo haya katika Mipangilio ya Mazungumzo", + "retryConnection": "Jaribu tena", + "retryConnectionTooltip": "Cwtch retries wenzao mara kwa mara, lakini unaweza kuwaambia Cwtch kujaribu mapema kwa kufinya hiki kitufe", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", + "localeUk": "Kiukreni \/ українською", "localeSv": "Kiswidi \/ Svenska", "localeJa": "Kijapani \/ 日本語", "localeSw": "Kiswahili \/ Kiswahili", "profileEnabledDescription": "Activate or Deactivate the profile.", - "retryConnectionTooltip": "Cwtch retries peers regularly, but you can tell Cwtch to try sooner by pushing this button.", - "retryConnection": "Retry", - "profileInfoHint3": "Contacts will be able to see this information in Conversation Settings ", - "profileInfoHint2": "You can add up to 3 fields.", - "profileInfoHint": "Add some public information about yourself here e.g. blog, websites, brief bio.", - "availabilityStatusTooltip": "Set your availability status", "availabilityStatusBusy": "Busy", - "availabilityStatusAway": "Away", - "availabilityStatusAvailable": "Available", "blodeuweddWarning": "Blodeuwedd uses a local language model and a set of small auxiliary models to power its functionality. These techniques are often very effective they are not without error. \n\nWhile we have taken efforts to minimize the risk, there is still the possibility that Blodeuwedd outputs will be incorrect, hallucinated and\/or offensive.\n\nBecause of that Blodeuwedd requires downloading two additional components separate from Cwtch, the Blodeuwedd Model (or a compatible model) and the Blodeuwedd Runner. \n\nSee https:\/\/docs.cwtch.im\/docs\/settings\/experiments\/blodeuwedd for more information on obtaining these components and setting them up.", "blodeuweddProcessing": "Blodeuwedd is processing...", "blodeuweddTranslate": "Translate Message", diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index c8ce566a..7998523d 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -1,6 +1,6 @@ { "@@locale": "tr", - "@@last_modified": "2023-05-22T18:04:36+02:00", + "@@last_modified": "2023-05-23T17:30:29+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Profili başlat veya durdur", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_uk.arb b/lib/l10n/intl_uk.arb new file mode 100644 index 00000000..b750e433 --- /dev/null +++ b/lib/l10n/intl_uk.arb @@ -0,0 +1,391 @@ +{ + "@@locale": "uk", + "@@last_modified": "2023-05-23T17:30:29+02:00", + "localeUk": "Ukrainian \/ українською", + "localeSw": "Swahili \/ Kiswahili", + "localeSv": "Swedish \/ Svenska", + "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", + "localeJa": "Japanese \/ 日本語", + "retryConnectionTooltip": "Cwtch retries peers regularly, but you can tell Cwtch to try sooner by pushing this button.", + "retryConnection": "Retry", + "profileInfoHint3": "Contacts will be able to see this information in Conversation Settings ", + "profileInfoHint2": "You can add up to 3 fields.", + "profileInfoHint": "Add some public information about yourself here e.g. blog, websites, brief bio.", + "availabilityStatusTooltip": "Set your availability status", + "availabilityStatusBusy": "Busy", + "availabilityStatusAway": "Away", + "availabilityStatusAvailable": "Available", + "blodeuweddWarning": "Blodeuwedd uses a local language model and a set of small auxiliary models to power its functionality. These techniques are often very effective they are not without error. \n\nWhile we have taken efforts to minimize the risk, there is still the possibility that Blodeuwedd outputs will be incorrect, hallucinated and\/or offensive.\n\nBecause of that Blodeuwedd requires downloading two additional components separate from Cwtch, the Blodeuwedd Model (or a compatible model) and the Blodeuwedd Runner. \n\nSee https:\/\/docs.cwtch.im\/docs\/settings\/experiments\/blodeuwedd for more information on obtaining these components and setting them up.", + "blodeuweddProcessing": "Blodeuwedd is processing...", + "blodeuweddTranslate": "Translate Message", + "blodeuweddSummarize": "Summarize Conversation", + "blodeuweddPath": "The directory where the Blodeuwedd is located on your computer.", + "blodeuweddNotSupported": "This version of Cwtch has been compiled without support for the Blodeuwedd Assistant.", + "blodeuweddDescription": "The Blodeuwedd assistant adds new features to Cwtch such as chat transcript summarization and message translation via a locally hosted language model.", + "blodeuweddExperimentEnable": "Blodeuwedd Assistant", + "localeKo": "Korean \/ 한국어", + "localeSk": "Slovak \/ Slovák", + "profileEnabledDescription": "Activate or Deactivate the profile.", + "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", + "profileEnabled": "Enable", + "profileAutostartLabel": "Autostart", + "localePtBr": "Brazilian Portuguese \/ Português do Brasil", + "localeNl": "Dutch \/ Dutch", + "experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes", + "enableExperimentQRCode": "QR Codes", + "shareMenuQRCode": "Show QR Code", + "shareProfileMenuTooltop": "Share profile via...", + "acquiredTicketsFromServer": "Antispam Challenge Complete", + "acquiringTicketsFromServer": "Performing Antispam Challenge", + "errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.", + "localeTr": "Turkish \/ Türk", + "tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"", + "tooltipPinConversation": "Pin conversation to the top of \"Conversations\"", + "replyingTo": "Replying to %1", + "fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.", + "messageNoReplies": "There are no replies to this message.", + "headingReplies": "Replies", + "viewReplies": "View replies to this message", + "restartFileShare": "Start Sharing File", + "stopSharingFile": "Stop Sharing File", + "manageSharedFiles": "Manage Shared Files", + "tooltipPreviewFormatting": "Preview Message Formatting", + "tooltipCode": "Code \/ Monospace", + "tooltipStrikethrough": "Strikethrough", + "tooltipSubscript": "Subscript", + "tooltipSuperscript": "Superscript", + "tooltipItalicize": "Italic", + "tooltipBackToMessageEditing": "Back to Message Editing", + "tooltipBoldText": "Bold", + "okButton": "OK", + "settingsAndroidPowerReenablePopup": "Cannot re-enable Battery Optimization from within Cwtch. Please go to Android \/ Settings \/ Apps \/ Cwtch \/ Battery and set Usage to 'Optimized'", + "settingAndroidPowerExemptionDescription": "Optional: Request Android to exempt Cwtch from optimized power management. This will result in better stability at the cost of greater battery use.", + "settingAndroidPowerExemption": "Android Ignore Battery Optimizations", + "thisFeatureRequiresGroupExpermientsToBeEnabled": "This feature requires the Groups Experiment to be enabled in Settings", + "messageFormattingDescription": "Enable rich text formatting in displayed messages e.g. **bold** and *italic*", + "formattingExperiment": "Message Formatting", + "clickableLinkError": "Error encountered while attempting to open URL", + "clickableLinksCopy": "Copy URL", + "clickableLinkOpen": "Open URL", + "clickableLinksWarning": "Opening this URL will launch an application outside of Cwtch and may reveal metadata or otherwise compromise the security of Cwtch. Only open URLs from people you trust. Are you sure you want to continue?", + "shuttingDownApp": "Shutting down...", + "successfullyImportedProfile": "Successfully Imported Profile: %profile", + "failedToImportProfile": "Error Importing Profile", + "importProfileTooltip": "Use an encrypted Cwtch backup to bring in a profile created in another instance of Cwtch.", + "importProfile": "Import Profile", + "exportProfileTooltip": "Backup this profile to an encrypted file. The encrypted file can be imported into another Cwtch app.", + "exportProfile": "Export Profile", + "localeDa": "Danish \/ Dansk", + "localeCy": "Welsh \/ Cymraeg", + "localeEl": "Greek \/ Ελληνικά", + "localeNo": "Norwegian \/ Norsk", + "localeLb": "Luxembourgish \/ Lëtzebuergesch", + "localeRo": "Romanian \/ Română", + "newMessageNotificationConversationInfo": "New Message From %1", + "newMessageNotificationSimple": "New Message", + "notificationContentContactInfo": "Conversation Information", + "notificationContentSimpleEvent": "Plain Event", + "conversationNotificationPolicySettingDescription": "Control notification behaviour for this conversation", + "conversationNotificationPolicySettingLabel": "Conversation Notification Policy", + "settingsGroupExperiments": "Experiments", + "settingsGroupAppearance": "Appearance", + "settingGroupBehaviour": "Behaviour", + "notificationContentSettingDescription": "Controls the contents of conversation notifications", + "notificationPolicySettingDescription": "Controls the default application notification behaviour", + "notificationContentSettingLabel": "Notification Content", + "notificationPolicySettingLabel": "Notification Policy", + "conversationNotificationPolicyNever": "Never", + "conversationNotificationPolicyOptIn": "Opt In", + "conversationNotificationPolicyDefault": "Default", + "notificationPolicyDefaultAll": "Default All", + "notificationPolicyOptIn": "Opt In", + "notificationPolicyMute": "Mute", + "tooltipSelectACustomProfileImage": "Select a Custom Profile Image", + "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", + "torSettingsEnableCache": "Cache Tor Consensus", + "labelTorNetwork": "Tor Network", + "descriptionACNCircuitInfo": "In depth information about the path that the anonymous communication network is using to connect to this conversation.", + "labelACNCircuitInfo": "ACN Circuit Info", + "fileSharingSettingsDownloadFolderTooltip": "Browse to select a different default folder for downloaded files.", + "fileSharingSettingsDownloadFolderDescription": "When files are downloaded automatically (e.g. image files, when image previews are enabled) a default location to download the files to is needed.", + "torSettingsErrorSettingPort": "Port Number must be between 1 and 65535", + "torSettingsUseCustomTorServiceConfigurastionDescription": "Override the default tor configuration. Warning: This could be dangerous. Only turn this on if you know what you are doing.", + "torSettingsUseCustomTorServiceConfiguration": "Use a Custom Tor Service Configuration (torrc)", + "torSettingsCustomControlPortDescription": "Use a custom port for control connections to the Tor proxy", + "torSettingsCustomControlPort": "Custom Control Port", + "torSettingsCustomSocksPortDescription": "Use a custom port for data connections to the Tor proxy", + "torSettingsCustomSocksPort": "Custom SOCKS Port", + "torSettingsEnabledAdvancedDescription": "Use an existing Tor service on your system, or change the parameters of the Cwtch Tor Service", + "torSettingsEnabledAdvanced": "Enable Advanced Tor Configuration", + "msgAddToAccept": "Add this account to your contacts in order to accept this file.", + "btnSendFile": "Send File", + "msgConfirmSend": "Are you sure you want to send", + "msgFileTooBig": "File size cannot exceed 10 GB", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images and Profile Pictures will be downloaded and previewed automatically. We recommend that you do not enable this Experiment if you use Cwtch with untrusted contacts.", + "settingImagePreviews": "Image Previews and Profile Pictures", + "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", + "enableExperimentClickableLinks": "Enable Clickable Links", + "serverConnectionsLabel": "Connection", + "serverTotalMessagesLabel": "Total Messages", + "serverMetricsLabel": "Server Metrics", + "manageKnownServersShort": "Servers", + "manageKnownServersLong": "Manage Known Servers", + "displayNameTooltip": "Please enter a display name", + "manageKnownServersButton": "Manage Known Servers", + "fieldDescriptionLabel": "Description", + "groupsOnThisServerLabel": "Groups I am in hosted on this server", + "importLocalServerButton": "Import %1", + "importLocalServerSelectText": "Select Local Server", + "importLocalServerLabel": "Import a locally hosted server", + "newMessagesLabel": "New Messages", + "localeRU": "Russian \/ Русский", + "copyServerKeys": "Copy keys", + "verfiyResumeButton": "Verify\/resume", + "fileCheckingStatus": "Checking download status", + "fileInterrupted": "Interrupted", + "fileSavedTo": "Saved to", + "encryptedServerDescription": "Encrypting a server with a password protects it from other people who may also use this device. Encrypted servers cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "plainServerDescription": "We recommend that you protect your Cwtch servers with a password. If you do not set a password on this server then anyone who has access to this device may be able to access information about this server, including sensitive cryptographic keys.", + "deleteServerConfirmBtn": "Really delete server", + "deleteServerSuccess": "Successfully deleted server", + "enterCurrentPasswordForDeleteServer": "Please enter current password to delete this server", + "copyAddress": "Copy Address", + "settingServersDescription": "The hosting servers experiment enables hosting and managing Cwtch servers", + "settingServers": "Hosting Servers", + "enterServerPassword": "Enter password to unlock server", + "unlockProfileTip": "Please create or unlock a profile to begin!", + "unlockServerTip": "Please create or unlock a server to begin!", + "addServerTooltip": "Add new server", + "serversManagerTitleShort": "Servers", + "serversManagerTitleLong": "Servers You Host", + "saveServerButton": "Save Server", + "serverAutostartDescription": "Controls if the application will automatically launch the server on start", + "serverAutostartLabel": "Autostart", + "serverEnabledDescription": "Start or stop the server", + "serverEnabled": "Server Enabled", + "serverDescriptionDescription": "Your description of the server for personal management use only, will never be shared", + "serverDescriptionLabel": "Server Description", + "serverAddress": "Server Address", + "editServerTitle": "Edit Server", + "addServerTitle": "Add Server", + "titleManageProfilesShort": "Profiles", + "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", + "settingFileSharing": "File Sharing", + "tooltipSendFile": "Send File", + "messageFileOffered": "Contact is offering to send you a file", + "messageFileSent": "You sent a file", + "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", + "labelFilesize": "Size", + "labelFilename": "Filename", + "downloadFileButton": "Download", + "openFolderButton": "Open Folder", + "retrievingManifestMessage": "Retrieving file information...", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", + "streamerModeLabel": "Streamer\/Presentation Mode", + "archiveConversation": "Archive this Conversation", + "blockUnknownConnectionsEnabledDescription": "Connections from unknown contacts are blocked. You can change this in Settings", + "showMessageButton": "Show Message", + "blockedMessageMessage": "This message is from a profile you have blocked.", + "placeholderEnterMessage": "Type a message...", + "plainProfileDescription": "We recommend that you protect your Cwtch profiles with a password. If you do not set a password on this profile then anyone who has access to this device may be able to access information about this profile, including contacts, messages and sensitive cryptographic keys.", + "encryptedProfileDescription": "Encrypting a profile with a password protects it from other people who may also use this device. Encrypted profiles cannot be decrypted, displayed or accessed until the correct password is entered to unlock them.", + "addContactConfirm": "Add contact %1", + "addContact": "Add contact", + "contactGoto": "Go to conversation with %1", + "settingUIColumnOptionSame": "Same as portrait mode setting", + "settingUIColumnDouble14Ratio": "Double (1:4)", + "settingUIColumnDouble12Ratio": "Double (1:2)", + "settingUIColumnSingle": "Single", + "settingUIColumnLandscape": "UI Columns in Landscape Mode", + "settingUIColumnPortrait": "UI Columns in Portrait Mode", + "localePl": "Polish \/ Polski", + "tooltipRemoveThisQuotedMessage": "Remove quoted message.", + "tooltipReplyToThisMessage": "Reply to this message", + "tooltipRejectContactRequest": "Reject this contact request", + "tooltipAcceptContactRequest": "Accept this contact request.", + "notificationNewMessageFromGroup": "New message in a group!", + "notificationNewMessageFromPeer": "New message from a contact!", + "tooltipHidePassword": "Hide Password", + "tooltipShowPassword": "Show Password", + "groupInviteSettingsWarning": "You have been invited to join a group! Please enable the Group Chat Experiment in Settings to view this Invitation.", + "shutdownCwtchAction": "Shutdown Cwtch", + "shutdownCwtchDialog": "Are you sure you want to shutdown Cwtch? This will close all connections, and exit the application.", + "shutdownCwtchDialogTitle": "Shutdown Cwtch?", + "shutdownCwtchTooltip": "Shutdown Cwtch", + "malformedMessage": "Malformed message", + "profileDeleteSuccess": "Successfully deleted profile", + "debugLog": "Turn on console debug logging", + "torNetworkStatus": "Tor network status", + "addContactFirst": "Add or pick a contact to begin chatting.", + "createProfileToBegin": "Please create or unlock a profile to begin", + "nickChangeSuccess": "Profile nickname changed successfully", + "addServerFirst": "You need to add a server before you can create a group", + "deleteProfileSuccess": "Successfully deleted profile", + "sendInvite": "Send a contact or group invite", + "sendMessage": "Send Message", + "cancel": "Cancel", + "resetTor": "Reset", + "torStatus": "Tor Status", + "torVersion": "Tor Version", + "sendAnInvitation": "You sent an invitation for: ", + "contactSuggestion": "This is a contact suggestion for: ", + "rejected": "Rejected!", + "accepted": "Accepted!", + "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.", + "newPassword": "New Password", + "yesLeave": "Yes, Leave This Conversation", + "reallyLeaveThisGroupPrompt": "Are you sure you want to leave this conversation? All messages and attributes will be deleted.", + "leaveConversation": "Leave This Conversation", + "inviteToGroup": "You have been invited to join a group:", + "titleManageServers": "Manage Servers", + "successfullAddedContact": "Successfully added ", + "descriptionBlockUnknownConnections": "If turned on, this option will automatically close connections from Cwtch users that have not been added to your contact list.", + "descriptionExperimentsGroups": "The group experiment allows Cwtch to connect with untrusted server infrastructure to facilitate communication with more than one contact.", + "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.", + "titleManageProfiles": "Manage Cwtch Profiles", + "tooltipUnlockProfiles": "Unlock encrypted profiles by entering their password.", + "titleManageContacts": "Conversations", + "tooltipAddContact": "Add a new contact or conversation", + "tooltipOpenSettings": "Open the settings pane", + "contactAlreadyExists": "Contact Already Exists", + "invalidImportString": "Invalid import string", + "conversationSettings": "Conversation Settings", + "enterCurrentPasswordForDelete": "Please enter current password to delete this profile.", + "enableGroups": "Enable Group Chat", + "localeIt": "Italian \/ Italiano", + "localeEs": "Spanish \/ Español", + "todoPlaceholder": "Todo...", + "addNewItem": "Add a new item to the list", + "addListItem": "Add a New List Item", + "newConnectionPaneTitle": "New Connection", + "networkStatusOnline": "Online", + "networkStatusConnecting": "Connecting to network and contacts...", + "networkStatusAttemptingTor": "Attempting to connect to Tor network", + "networkStatusDisconnected": "Disconnected from the internet, check your connection", + "viewGroupMembershipTooltip": "View Group Membership", + "loadingTor": "Loading tor...", + "smallTextLabel": "Small", + "defaultScalingText": "Font Scaling", + "builddate": "Built on: %2", + "version": "Version %1", + "versionTor": "Version %1 with tor %2", + "experimentsEnabled": "Enable Experiments", + "themeDark": "Dark", + "themeLight": "Light", + "settingTheme": "Use Light Themes", + "largeTextLabel": "Large", + "settingInterfaceZoom": "Zoom level", + "localeDe": "German \/ Deutsch", + "localePt": "Portuguese \/ Portuguesa", + "localeFr": "French \/ Français", + "localeEn": "English \/ English", + "settingLanguage": "Language", + "blockUnknownLabel": "Block Unknown Contacts", + "zoomLabel": "Interface zoom (mostly affects text and button sizes)", + "versionBuilddate": "Version: %1 Built on: %2", + "cwtchSettingsTitle": "Cwtch Settings", + "unlock": "Unlock", + "yourServers": "Your Servers", + "yourProfiles": "Your Profiles", + "error0ProfilesLoadedForPassword": "0 profiles loaded with that password", + "password": "Password", + "enterProfilePassword": "Enter a password to view your profiles", + "addNewProfileBtn": "Add new profile", + "deleteConfirmText": "DELETE", + "deleteProfileConfirmBtn": "Really Delete Profile", + "deleteConfirmLabel": "Type DELETE to confirm", + "deleteProfileBtn": "Delete Profile", + "passwordChangeError": "Error changing password: Supplied password rejected", + "passwordErrorMatch": "Passwords do not match", + "saveProfileBtn": "Save Profile", + "createProfileBtn": "Create Profile", + "passwordErrorEmpty": "Password cannot be empty", + "password2Label": "Reenter password", + "password1Label": "Password", + "currentPasswordLabel": "Current Password", + "yourDisplayName": "Your Display Name", + "profileOnionLabel": "Send this address to contacts you want to connect with", + "noPasswordWarning": "Not using a password on this account means that all data stored locally will not be encrypted", + "radioNoPassword": "Unencrypted (No password)", + "radioUsePassword": "Password", + "editProfile": "Edit Profile", + "newProfile": "New Profile", + "defaultProfileName": "Alice", + "profileName": "Display name", + "editProfileTitle": "Edit Profile", + "addProfileTitle": "Add new profile", + "deleteBtn": "Delete", + "unblockBtn": "Unblock Contact", + "dontSavePeerHistory": "Delete History", + "savePeerHistoryDescription": "Determines whether to delete any history associated with the contact.", + "savePeerHistory": "Save History", + "blockBtn": "Block Contact", + "saveBtn": "Save", + "displayNameLabel": "Display Name", + "copiedToClipboardNotification": "Copied to Clipboard", + "addressLabel": "Address", + "puzzleGameBtn": "Puzzle Game", + "bulletinsBtn": "Bulletins", + "listsBtn": "Lists", + "chatBtn": "Chat", + "rejectGroupBtn": "Reject", + "acceptGroupBtn": "Accept", + "acceptGroupInviteLabel": "Do you want to accept the invitation to", + "newGroupBtn": "Create new group", + "copyBtn": "Copy", + "peerOfflineMessage": "Contact is offline, messages can't be delivered right now", + "peerBlockedMessage": "Contact is blocked", + "pendingLabel": "Pending", + "acknowledgedLabel": "Acknowledged", + "couldNotSendMsgError": "Could not send this message", + "dmTooltip": "Click to DM", + "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.", + "addListItemBtn": "Add Item", + "peerNotOnline": "Contact is offline. Applications cannot be used right now.", + "searchList": "Search List", + "update": "Update", + "inviteBtn": "Invite", + "inviteToGroupLabel": "Invite to group", + "groupNameLabel": "Group Name", + "viewServerInfo": "Server Info", + "serverNotSynced": "Syncing New Messages (This can take some time)...", + "serverSynced": "Synced", + "serverConnectivityDisconnected": "Server Disconnected", + "serverConnectivityConnected": "Server Connected", + "serverInfo": "Server Information", + "invitationLabel": "Invitation", + "serverLabel": "Server", + "search": "Search...", + "blocked": "Blocked", + "pasteAddressToAddContact": "Paste a cwtch address, invitation or key bundle here to add a new conversation", + "titlePlaceholder": "title...", + "postNewBulletinLabel": "Post new bulletin", + "newBulletinLabel": "New Bulletin", + "joinGroup": "Join group", + "createGroup": "Create group", + "addPeer": "Add Contact", + "groupAddr": "Address", + "invitation": "Invitation", + "server": "Server", + "peerName": "Name", + "peerAddress": "Address", + "joinGroupTab": "Join a group", + "createGroupTab": "Create a group", + "addPeerTab": "Add a contact", + "createGroupBtn": "Create", + "defaultGroupName": "Awesome Group", + "createGroupTitle": "Create Group" +} \ No newline at end of file diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index a213931a..f64ddf5d 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -748,6 +748,9 @@ String getLanguageFull(context, String languageCode, String? countryCode) { if (languageCode == "sw") { return AppLocalizations.of(context)!.localeSw; } + if (languageCode == "uk") { + return AppLocalizations.of(context)!.localeUk; + } return languageCode; } From aedc033df980c90a8b81eeb9b586950de23d3a1b Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 29 May 2023 11:29:05 -0700 Subject: [PATCH 19/20] Update Goldens --- test/buttontextfield01.png | Bin 252 -> 252 bytes test/cwtchlabel01.png | Bin 2193 -> 2205 bytes test/profileimage_init.png | Bin 6733 -> 6624 bytes test/textfield_basic.png | Bin 5192 -> 5187 bytes test/textfield_form_42.png | Bin 5154 -> 5106 bytes test/textfield_form_alpha.png | Bin 6266 -> 6273 bytes test/textfield_form_final.png | Bin 6069 -> 6032 bytes test/textfield_form_init.png | Bin 5132 -> 5103 bytes test/textfield_init.png | Bin 5032 -> 5011 bytes 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/buttontextfield01.png b/test/buttontextfield01.png index 7aa6c253e1c9e3a33fe9c97a2efc2abfa1603c6c..a4e0c16d77001421761e0f72148443ef3bff123a 100644 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0y~yV7dZii*T?3$+c0da)A_Mage(c!@6@aFM%AEVkgfK z4j`!ENa+CbmwCE4hE&XXd+j3Up#TAfgGcN>B~FfNHk;X>F2Av(RzTU9Rfhfe!F9?1 zWlo12uil-1UUKp=ySUSv?9$FO-G5;J@AjVGOa-#rH;XecG-wM0Ef?U(VqoB4F$LPy yBn5PjBQFC(;{rB@28RG<1_y-|j0_3_q$=C@qg6;F=!hD~#SEUVelF{r5}E)8@^iIkOL3H!4|tu3p`ga&N}n>g|bN@>aD+4pb z1f>Q>1`ojl3=B&+5*QeQSPU2#G?^qA8bnA{_LTSCG9eAU`nmUkE@tp_^>bP0l+XkK Dfxby1 diff --git a/test/cwtchlabel01.png b/test/cwtchlabel01.png index 89a06c5e298e185a28ff4311f33b1676e27a77bc..cb0362dfe56ba1dccd129c0c0370648e59c6f873 100644 GIT binary patch delta 362 zcmbOzI9G6jW4*hli(^Q|oVT}h`$Qcj+Ac0{OjKb!$~HsvfL*}ij}>N4A70$#>bQ8A zEkH#>qVCd+-7TleCqI)3e&?w^RVe?`?YQl0OZQ&A+jSu>{OZ}RYbT$++;jc1we$Kt z{mS379{y!I5NK=hot=S!;Xgk!3j>2has!Z^%p<_SkkG@(#8A)BW9Y!Z&|t{M!N6c} zjDeAX;h2O11H%CcY^t#+wt1E7KV9tpm#X@k*Hzb^w|)Qk(EH!FT|@bQuU&3_Py7Aj z6MI+jpY~!XhyXgZd-nC{yK6b#mWJM4lQB1D-nnWg+r7qLPW`qhS}%4_pFw77{05L? zZvR_Z?%l2b>)PZx-OSqeh4EF}mV|!Y+`a9a-tWb5W5f5}e|3D5+~!8cpKOySF!G4c bIc~r8dG&ARYf+Pco@DTJ^>bP0l+XkKva+0q delta 349 zcmbO$I8ktdW4*Pfi(^Q|oVT|&`Z7BTv|WrWaXBHxYq3G0T=EKorLKdMN0YU~lPQk; zA`N;5yb6ywj$C4Rm{DVOPy4}juhqPEcelR%aZfq)zE1e*+dWI)?x^j^Fqe!r;JtTz z&(pj53}>!hT*%MB!0<<&iG_hdL)n3Wp}`1=S&zgflX>{$Bg@hc6&2Cn<*rLc&zJxH zdj0#&J(@FE-Y4Jtw)?cRJR^fz{*CwRCaM2^{pia_&E!n$dvo2lboc1aV0&+weD4>? zfs@T$zW6>%=>Ioq=haQel$4^PkNUf8vAeZ7e4qHe<7>VveXnCoSQmBey#mAk*zAd) kO1U>TGBUA?|NF*$voLE?75DvKpf4FbUHx3vIVCg!0HWcA-2eap diff --git a/test/profileimage_init.png b/test/profileimage_init.png index 2a015e0f64e97524164e1eb99d49ebafb8728a5d..af68fa5498767a71fdea5ab569e8a48ee5b93585 100644 GIT binary patch literal 6624 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�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 diff --git a/test/textfield_basic.png b/test/textfield_basic.png index 9d9b6383b19fab2c6beaffdd41f264a37dcd34cf..5edbf82488532139ea049df389974aa57202795d 100644 GIT binary patch literal 5187 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 AVE_OC diff --git a/test/textfield_form_42.png b/test/textfield_form_42.png index d31f14cb1a8722d3c3d5e7f48e8d88b57e09d9e1..f742564f21fb9037de16836a85a438a2e7c4100e 100644 GIT binary patch literal 5106 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 literal 5154 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 b=NXZB$fM%lQi9%bVI}-A2g?ea@0I@mhL1$1 diff --git a/test/textfield_form_alpha.png b/test/textfield_form_alpha.png index 5175e0772f8be774ca501592c3f172b9fde31164..e5b67d981f04c4ed2916cd9593a55440287bfece 100644 GIT binary patch literal 6273 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 literal 6266 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 Y+}2}b@mDEEY7oZ!qKz>L;r{o(0q0fTBme*a diff --git a/test/textfield_form_final.png b/test/textfield_form_final.png index 14b246eaaf5dfb2a43a1937101ecdd535fb517fa..9fbb3e0b467b57722709f4cc50db1f361553200b 100644 GIT binary patch literal 6032 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 diff --git a/test/textfield_form_init.png b/test/textfield_form_init.png index 4ec7291d27b0a4b5abe10bf1d07efe85ec523696..f1c811e3419c112153f15744f3d0f2ccbcc6f758 100644 GIT binary patch literal 5103 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 Fe*=odaybA1 diff --git a/test/textfield_init.png b/test/textfield_init.png index fe7169e42a6f3a8ebffd498efa5de42037b9a1d4..b1da26a967ca5435832d3308661e667e852eedb1 100644 GIT binary patch literal 5011 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 B57z(y literal 5032 zcmeHLX+Trgwmvw%5_C^A$< zQ5mA77?4R@1;SVv4IzLKpp20z2!Z786MXO8_v8J0KX3kIo$su@_gddxYwfj9nuDG7 zo`1;y1A?GEcpHmz5VTbVf+W-tI{;#QqR$BYNra!X#zAH63X|YrTR0BygaE%-1R)iI zWX|C&PCH%Ao#nWa2`i^3<~{PJrl#`eCY3zAj^~%;?LM&W#96XKrV6DoEHc@}KlGtx zan=Ggi;q$dD*tBh2oi%KZF}qdi}bv-dg!gIHhNyN<$^>j)M>YOUV(8pw9E7I($x;K zbxb*<`C#Ia2SvZyHR?Drun}wB6N}nK&pXCwXHB~=iWX^I2nee9%v@epj=osE;rb0e zrq}yk_x;+zzWCL2{dk|=QO~s;x)SiAYrZe9{XNga`HP?@Ia&EQHQ6P@cW;YjsA%V% zJA*4(v$JM-%g%Q-B(^{fs%X-485Ic9RmDBkhJiBx*b4)PaZk}O;2n`lX^a;zM3$

l{DK43u}`!e`VBqjueZqS>+K}k3Id0(#La{kv`7iL z_VIlJS6Y3(+1j&$=04GS$D&)&ZB36_qofaQ$wjx_>V&*1j7LsyTG2eyIE(9u7fvq+ zL(s93DP$P^%RyEBkp9SwwwaFoW*! z5>fS2EQUFfCbL>+t=#s0qQE}%6R!6LdZL;`wK8DbDNiWsQlrM2GH;CL`%&!&LI?@H zqrYAVKUqAxoa<(k_3%UMxj@6xajy&gYF+Nmc8@;TsHUGf#y`Cix@+CSDXkHeW_LCZ zmZVTIt5NmK7K1Av8dC;EQ_~^b8wKmET(gy|*y5_3>EbTE;6{SW`iTY_?(S-!gb1+n`S&Y6o|bMJvDvK85o7s~6grcb50N ze_vd6xB3FFE$?`g@7UV(!?QCxQ@=paQxa#~YtXNZtH^2be`414k}R*x6xuee8g_?8(~_=y zy1K^ibYLWPX35AU;Dm47YT1>TzH&NSZf4DaYD|s2mbsWAucBJ!@ z@E>402qaz9qis#kW;6{vzT=OM=1ogs@CU9Z56~lx+D4q$3r|5%N-G-o1gX3g&Ha0y zrOxr$3b*OHtXiSFokrewzEOf<+a_;3Hk;e8HF4;$dHkm}W>`)+f&c*ly7J>pEk`ad2;n1}%`rt>n7OLx-cO0yd^B(ug=uncGStj>liebkK ziG^D;G?7hl)z#77;+WpKaQ1$Xj0!)K6n>7~ol1Gs<#&o$vJ0lxThNw7S2g<@EXFg>-}J{xF2+I&19JVD+grzSyOKKM`sCOvA66zOnp?fcgjyS^KU#K z^|-aJE#!@Cg*+vL7#9{>({v^!H!9|<+tAn@7v}1YE5|K#UHg11CHyrbOUHG>SNrB` z|5MjXP7K|8IIp-UH~puA@r>FeCn+7In%Y40c1TPANE*dO%&`3N8^ypy<=E*5mu?zkU9?vesB4m+I_apsO=8rfPDYEh-Y3ff0F^4>glnqO%h)7hR~bX>hmNgLviSm7tI$wWJrV37|xqT za}C}#zG>z}jd|CLR!!EK1qVClz{}MWPQ=WgCRB!O{Y6pj>2%FX2^)_XH{B(#=FQ&S7K=f9s&`(mJ8~)0qR4hcKwy=jqTt7kU^pre@KKN2P33*J*dKv4hlDZ8!afG0Rwnzl7A3_(d!IM>>anHrH8KVndivbMoIUd$5E;NFH z@Y5uxB;dLyF_prCPsrB&NNrb`*eX?=k2O%$%C=||2BgE$Hk>sgjY34?hY&qo}E zc}z^Dl*0;@b|eK;aF#+lYkne`eEw6}_Ut~oQoq9i``jie6JbafZ*~kYRvL!X4oFnU z5Jf=H-8Yeex*fR&w~5zdmvsu-S`y~7Cszb?rQW};CnvA}ov_;R@3~`I`0^fb-cv&% zch|MKZ#-;6d?%baH+$TI&M!o&Gdv}rH$OPbXvYEjA>wJ0ExhfCY>*_X<`CqGKoi71 z@5YmC?SN-*5Ee}Ym;|y7iEIx82Q8YeiUB-{EY{d&(c}jMwl<{QVvT*Nluxj)clRR0 zV&G+-*pLQt;AM`=p!DI6U>K1~VTgs)R0vxt@mPlO7dkxU^Jk8vnc9VOy*Iq1#Zx|is(}ofU!6GTR;iULw&(o$6vV%`BG}lG zcgA()wHrkYBP+1ho83J}aXGRY>hYfblW~men@(KFMzGe$^=U-VqVY=6n?`k`aC86F zmxb)#bYY~@y6KP3bD`CnuAx#?xiPz{`fnp>3<)BGIyx^Jg>MfdbyvUOT zhs4vTqx(=atRP4@Jj0qG@>fo8!Y@Xp#V|IGAJlt&gw5y=srq(KRs|3qdj2NmbS$PS zI1$qeyZqAOJz|x=sLAb9j{njS2ydJ2xyPGOl(46sX-5km6{nc4BWO0>S?`5aBJ^7j zh6k0?VB)K^ZXgU5zRG8PNHw78gLi2BJ2|*xv=MK7-Xk)_^}RLP97KbLq9tiS11p{= zJTM2TZTodV|0y)#M&=dbcTF=6s9Pw%b%U@VtwV)8Cv%A*>j253?!P zq%&?%deg?%=Q7N&AFf&Np)^n?W~KC$;&|3p%KHHayZ)zlbZTexRE2p9mj3voi@~lx zxV&W}frtcobC*Rd9ls~z+o@=}{fXC7F(1wa1z$Rua*I~kSJ3XX2h=HJ`gQQw%c_ms zHwr<}cY6LLvX0@&g{-njJ?lC!z~P767B)vEI%j7KLlnVtcS9wxUzV)f7Z%Z|4g<`m zNbR})&o8%doB4<7Dqx5XI7vfj`n|dh?hAF-W)~_`0O9*}ZAmlBjW;p~|Aataz$DU) z`N@F%fY;|qOShN!4GE_jEzH&g{o}=xF&gm1?QLj6Cq6Z;z-S@kzHI4Epe%2sfU2(L zq;(jECeF;wjw`p3K!TkJ20g^mLiOT>5d95X?7UXiL>Ujf9ckDeh=ZWtd?I5wHA}sZ za|26$mLK95?N!-I3$B||iv~x+jWvLKJRS4fq=*xwY zR&bSrZVsr3Gu+|2n!cV8uI|udqzW+5AI=E}d3f1OtN+0N;pG1(Ab#CL36azT_gYo> zyUgX>E0GMTx>%pP-r&W>9f#neY(pJ%=MA^C{HdT5lxSl5@#9nwSqlTQyiBsYT3Qv zYu)#dk~_gf!>-vL&Epk^rp@%IHO7war2J{M^)JKk$1Bp495ui(rBGQp-56 zDk*UorYg%rIqVoyP!t;vPNBa|Z*O?KiZ&A18z{##fDQRSe+CW0U0f5TxM_@{C9H(E Lw6iF~dH(ZXPdp%T From a69f3cb46e1cd88ea379014b6cf89141e0187f94 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 29 May 2023 12:36:24 -0700 Subject: [PATCH 20/20] Language Updates (Mostly Swahili) --- lib/l10n/intl_cy.arb | 2 +- lib/l10n/intl_da.arb | 2 +- lib/l10n/intl_de.arb | 2 +- lib/l10n/intl_el.arb | 2 +- lib/l10n/intl_en.arb | 2 +- lib/l10n/intl_es.arb | 2 +- lib/l10n/intl_fr.arb | 2 +- lib/l10n/intl_it.arb | 2 +- lib/l10n/intl_ja.arb | 2 +- lib/l10n/intl_ko.arb | 2 +- lib/l10n/intl_lb.arb | 2 +- lib/l10n/intl_nl.arb | 2 +- lib/l10n/intl_no.arb | 2 +- lib/l10n/intl_pl.arb | 2 +- lib/l10n/intl_pt.arb | 2 +- lib/l10n/intl_pt_BR.arb | 2 +- lib/l10n/intl_ro.arb | 2 +- lib/l10n/intl_ru.arb | 2 +- lib/l10n/intl_sk.arb | 2 +- lib/l10n/intl_sv.arb | 2 +- lib/l10n/intl_sw.arb | 186 +++++++++++++++++++------------------- lib/l10n/intl_tr.arb | 2 +- lib/l10n/intl_uk.arb | 2 +- lib/models/appstate.dart | 3 + lib/views/splashView.dart | 3 +- 25 files changed, 120 insertions(+), 116 deletions(-) diff --git a/lib/l10n/intl_cy.arb b/lib/l10n/intl_cy.arb index 188f2034..45a71f7e 100644 --- a/lib/l10n/intl_cy.arb +++ b/lib/l10n/intl_cy.arb @@ -1,6 +1,6 @@ { "@@locale": "cy", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_da.arb b/lib/l10n/intl_da.arb index 5dade851..6945fa08 100644 --- a/lib/l10n/intl_da.arb +++ b/lib/l10n/intl_da.arb @@ -1,6 +1,6 @@ { "@@locale": "da", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 06275f15..bcc10c24 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,6 @@ { "@@locale": "de", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Starten oder Stoppen des Profils", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_el.arb b/lib/l10n/intl_el.arb index 6e3448f6..8b2f929d 100644 --- a/lib/l10n/intl_el.arb +++ b/lib/l10n/intl_el.arb @@ -1,6 +1,6 @@ { "@@locale": "el", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index af6c527f..a799b740 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,6 @@ { "@@locale": "en", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index b4bc9708..8e435868 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,6 @@ { "@@locale": "es", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 1b6201e6..9eec90e4 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,6 @@ { "@@locale": "fr", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 9af8c251..e2e44daa 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,6 @@ { "@@locale": "it", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ja.arb b/lib/l10n/intl_ja.arb index 16d39d97..8def5c2d 100644 --- a/lib/l10n/intl_ja.arb +++ b/lib/l10n/intl_ja.arb @@ -1,6 +1,6 @@ { "@@locale": "ja", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index a64db5c8..848d1864 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -1,6 +1,6 @@ { "@@locale": "ko", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "프로필 시각 또는 중지", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_lb.arb b/lib/l10n/intl_lb.arb index 16379fcd..fa87d1c5 100644 --- a/lib/l10n/intl_lb.arb +++ b/lib/l10n/intl_lb.arb @@ -1,6 +1,6 @@ { "@@locale": "lb", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index ac616a48..24e1b264 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1,6 +1,6 @@ { "@@locale": "nl", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Start of stop het profiel", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_no.arb b/lib/l10n/intl_no.arb index 8dc6e2a5..3d15f48b 100644 --- a/lib/l10n/intl_no.arb +++ b/lib/l10n/intl_no.arb @@ -1,6 +1,6 @@ { "@@locale": "no", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index de43d5c5..b9406ef4 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,6 @@ { "@@locale": "pl", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 02fa9cda..5210134c 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,6 @@ { "@@locale": "pt", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_pt_BR.arb b/lib/l10n/intl_pt_BR.arb index 11f1cdc7..ddd77990 100644 --- a/lib/l10n/intl_pt_BR.arb +++ b/lib/l10n/intl_pt_BR.arb @@ -1,6 +1,6 @@ { "@@locale": "pt_BR", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index efe626b4..b448140a 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -1,6 +1,6 @@ { "@@locale": "ro", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 87265757..de45e11f 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,6 @@ { "@@locale": "ru", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Activate or Deactivate the profile.", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_sk.arb b/lib/l10n/intl_sk.arb index 77feb2c0..dfc36900 100644 --- a/lib/l10n/intl_sk.arb +++ b/lib/l10n/intl_sk.arb @@ -1,6 +1,6 @@ { "@@locale": "sk", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Spustiť alebo zastaviť profil", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_sv.arb b/lib/l10n/intl_sv.arb index 3b6e485b..520593a5 100644 --- a/lib/l10n/intl_sv.arb +++ b/lib/l10n/intl_sv.arb @@ -1,6 +1,6 @@ { "@@locale": "sv", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainska \/ українською", "profileEnabledDescription": "Aktivera eller inaktivera profilen", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_sw.arb b/lib/l10n/intl_sw.arb index 34da932f..4ced4091 100644 --- a/lib/l10n/intl_sw.arb +++ b/lib/l10n/intl_sw.arb @@ -1,6 +1,98 @@ { "@@locale": "sw", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", + "torSettingsUseCustomTorServiceConfigurastionDescription": "Batilisha usanidi chaguo-msingi wa tor. Onyo: Hii inaweza kuwa hatari. Washa hii ikiwa tu unajua unachofanya.", + "torSettingsErrorSettingPort": "Nambari ya Mlango lazima iwe kati ya 1 na 65535", + "fileSharingSettingsDownloadFolderDescription": "Faili zinapopakuliwa kiotomatiki (km faili za picha, mapitio ya picha yanapowezeshwa) eneo chaguomsingi la kupakua faili linahitajika.", + "fileSharingSettingsDownloadFolderTooltip": "Vinjari ili kuchagua folda chaguo-msingi tofauti kwa faili zilizopakuliwa.", + "labelACNCircuitInfo": "Maelezo ya Mzunguko wa ACN", + "descriptionACNCircuitInfo": "Maelezo ya kina kuhusu njia ambayo mtandao wa mawasiliano usiojulikana unatumia kuunganisha kwenye mazungumzo haya.", + "labelTorNetwork": "Mtandao wa Tor", + "torSettingsEnableCache": "Makubaliano ya Cache Tor", + "tooltipSelectACustomProfileImage": "Chagua Picha Maalum ya Wasifu", + "notificationPolicyMute": "Nyamazisha", + "notificationPolicyOptIn": "Chagua Katika", + "notificationPolicyDefaultAll": "Chaguomsingi Zote", + "availabilityStatusBusy": "Shughuli", + "conversationNotificationPolicyDefault": "Chaguomsingi", + "conversationNotificationPolicyOptIn": "Chagua kujijumuisha ", + "conversationNotificationPolicyNever": "Kamwe", + "notificationPolicySettingLabel": "Sera ya Arifa", + "notificationContentSettingLabel": "Maudhui ya Arifa", + "notificationPolicySettingDescription": "Hudhibiti tabia ya arifa ya programu chaguomsingi", + "notificationContentSettingDescription": "Hudhibiti maudhui ya arifa za mazungumzo", + "settingGroupBehaviour": "Tabia", + "settingsGroupAppearance": "Muonekano", + "settingsGroupExperiments": "Majaribio", + "conversationNotificationPolicySettingLabel": "Sera ya Arifa ya Mazungumzo", + "conversationNotificationPolicySettingDescription": "Dhibiti tabia ya arifa kwa mazungumzo haya", + "notificationContentSimpleEvent": "Tukio la wazi", + "notificationContentContactInfo": "Taarifa za Mazungumzo", + "newMessageNotificationSimple": "Ujumbe Mpya", + "newMessageNotificationConversationInfo": "Ujumbe Mpya Kutoka %1", + "localeRo": "Kiromania \/ Kirumi", + "localeLb": "Luxembourgish \/ Lëtzebuergesch", + "localeNo": "Kinorwe \/ Norsk", + "localeEl": "Kigiriki \/ Ελληνικά", + "localeCy": "Welsh \/ Cymraeg", + "localeDa": "Kidenishi \/ Dansk", + "exportProfile": "Hamisha Wasifu", + "exportProfileTooltip": "Hifadhi nakala ya wasifu huu kwa faili iliyosimbwa. Faili iliyosimbwa kwa njia fiche inaweza kuingizwa kwenye programu nyingine ya Cwtch.", + "importProfile": "Ingiza Wasifu", + "importProfileTooltip": "Tumia chelezo iliyosimbwa kwa njia fiche ya Cwtch kuleta wasifu ulioundwa katika mfano mwingine wa Cwtch.", + "failedToImportProfile": "Hitilafu katika Kuingiza Wasifu", + "successfullyImportedProfile": "Imefaulu Kuingiza Wasifu: %wasifu", + "shuttingDownApp": "Inazima...", + "clickableLinksWarning": "Kufungua URL hii itafungua programu nje ya Cwtch na kunaweza kufichua metadata au vinginevyo kuhatarisha usalama wa Cwtch. Fungua URL kutoka kwa watu unaowaamini pekee. Je, una uhakika ungependa kuendelea?", + "clickableLinkOpen": "Fungua URL", + "clickableLinksCopy": "Nakili URL", + "clickableLinkError": "Hitilafu ilitokea wakati wa kujaribu kufungua URL", + "formattingExperiment": "Uumbizaji wa Ujumbe", + "messageFormattingDescription": "Washa uumbizaji wa maandishi umbizo katika ujumbe unaoonyeshwa kwa mfano **bold** na *italic*", + "thisFeatureRequiresGroupExpermientsToBeEnabled": "Kipengele hiki kinahitaji Majaribio ya Vikundi kuwashwa katika Mipangilio", + "settingAndroidPowerExemption": "Android Puuza Uboreshaji wa Betri", + "settingAndroidPowerExemptionDescription": "Hiari: Omba Android kuondoa Cwtch kutoka kwa usimamizi bora wa nishati. Hii itasababisha uthabiti bora kwa gharama ya matumizi makubwa ya betri.", + "settingsAndroidPowerReenablePopup": "Haiwezi kuwezesha upya Uboreshaji wa Betri kutoka ndani ya Cwtch. Tafadhali nenda kwa Android \/ Mipangilio \/ Programu \/ Cwtch \/ Betri na uweke Matumizi kwa 'Imeboreshwa'", + "okButton": "sawa", + "tooltipBoldText": "Kolevu", + "tooltipBackToMessageEditing": "Rudi kwa Kuhariri Ujumbe", + "tooltipItalicize": "Italiki", + "tooltipSubscript": "Usajili", + "tooltipStrikethrough": "Strikethrough", + "tooltipCode": "Nambari \/ Nafasi moja", + "tooltipPreviewFormatting": "Hakiki Uumbizaji wa Ujumbe", + "manageSharedFiles": "Dhibiti Faili Zilizoshirikiwa", + "stopSharingFile": "Acha Kushiriki Faili", + "restartFileShare": "Anza Kushiriki Faili", + "viewReplies": "Tazama majibu kwa ujumbe huu", + "headingReplies": "Majibu", + "messageNoReplies": "Hakuna majibu kwa ujumbe huu.", + "fileDownloadUnavailable": "Faili hii inaonekana haipatikani kwa kupakuliwa. Mtumaji anaweza kuwa amezima upakuaji wa faili hii.", + "replyingTo": "Kujibu %1", + "tooltipPinConversation": "Bandika mazungumzo juu ya \"Mazungumzo\"", + "tooltipUnpinConversation": "Bandua mazungumzo kutoka sehemu ya juu ya \"Mazungumzo\"", + "localeTr": "Kituruki \/ Kituruki", + "acquiringTicketsFromServer": "Kutekeleza Changamoto ya Antispam", + "acquiredTicketsFromServer": "Changamoto ya Antispam Imekamilika", + "shareProfileMenuTooltop": "Shiriki wasifu kupitia...", + "shareMenuQRCode": "Onyesha Msimbo wa QR", + "enableExperimentQRCode": "Misimbo ya QR", + "experimentQRCodeDescription": "Usaidizi wa Msimbo wa QR huruhusu kushiriki data (kama vile utambulisho wa wasifu) kwa Misimbo ya QR", + "localeNl": "Kiholanzi \/ Kiholanzi", + "localePtBr": "Kireno cha Kibrazili \/ Português do Brasil", + "profileAutostartLabel": "Anzisha kiotomatiki", + "profileEnabled": "Wezesha", + "profileAutostartDescription": "Hudhibiti ikiwa wasifu utazinduliwa kiotomatiki inapowashwa", + "profileEnabledDescription": "Washa au Lemaza wasifu.", + "localeSk": "Kislovakia \/ Kislovakia", + "localeKo": "Kikorea \/ 한국어", + "blodeuweddExperimentEnable": "Msaidizi wa Blodeuwedd", + "blodeuweddNotSupported": "Toleo hili la Cwtch limeundwa bila usaidizi kwa Msaidizi wa Blodeuwedd.", + "retryConnectionTooltip": "Cwtch retries wenzao mara kwa mara, lakini unaweza kuwaambia Cwtch kujaribu mapema kwa kubofya hiki kitufe", + "blodeuweddPath": "The directory where the Blodeuwedd is located on your computer.", + "blodeuweddSummarize": "Fupisha Mazungumzo", + "blodeuweddTranslate": "Tafsiri Ujumbe", + "blodeuweddProcessing": "Blodeuwedd inachakata...", "availabilityStatusAvailable": "Inapatikana", "availabilityStatusAway": "Sipo karibu", "availabilityStatusTooltip": "Weka hali ya upatikanaji wako", @@ -8,108 +100,16 @@ "profileInfoHint2": "Unaweza kuongeza hadi sehemu 3.", "profileInfoHint3": "Anwani zitaweza kuona maelezo haya katika Mipangilio ya Mazungumzo", "retryConnection": "Jaribu tena", - "retryConnectionTooltip": "Cwtch retries wenzao mara kwa mara, lakini unaweza kuwaambia Cwtch kujaribu mapema kwa kufinya hiki kitufe", "fontScalingDescription": "Adjust the relative font scaling factor applied to text and widgets.", "localeUk": "Kiukreni \/ українською", "localeSv": "Kiswidi \/ Svenska", "localeJa": "Kijapani \/ 日本語", "localeSw": "Kiswahili \/ Kiswahili", - "profileEnabledDescription": "Activate or Deactivate the profile.", - "availabilityStatusBusy": "Busy", "blodeuweddWarning": "Blodeuwedd uses a local language model and a set of small auxiliary models to power its functionality. These techniques are often very effective they are not without error. \n\nWhile we have taken efforts to minimize the risk, there is still the possibility that Blodeuwedd outputs will be incorrect, hallucinated and\/or offensive.\n\nBecause of that Blodeuwedd requires downloading two additional components separate from Cwtch, the Blodeuwedd Model (or a compatible model) and the Blodeuwedd Runner. \n\nSee https:\/\/docs.cwtch.im\/docs\/settings\/experiments\/blodeuwedd for more information on obtaining these components and setting them up.", - "blodeuweddProcessing": "Blodeuwedd is processing...", - "blodeuweddTranslate": "Translate Message", - "blodeuweddSummarize": "Summarize Conversation", - "blodeuweddPath": "The directory where the Blodeuwedd is located on your computer.", - "blodeuweddNotSupported": "This version of Cwtch has been compiled without support for the Blodeuwedd Assistant.", "blodeuweddDescription": "The Blodeuwedd assistant adds new features to Cwtch such as chat transcript summarization and message translation via a locally hosted language model.", - "blodeuweddExperimentEnable": "Blodeuwedd Assistant", - "localeKo": "Korean \/ 한국어", - "localeSk": "Slovak \/ Slovák", - "profileAutostartDescription": "Controls if the profile will be automatically launched on startup", - "profileEnabled": "Enable", - "profileAutostartLabel": "Autostart", - "localePtBr": "Brazilian Portuguese \/ Português do Brasil", - "localeNl": "Dutch \/ Dutch", - "experimentQRCodeDescription": "QR Code support allows sharing data (such as profile identity) by QR Codes", - "enableExperimentQRCode": "QR Codes", - "shareMenuQRCode": "Show QR Code", - "shareProfileMenuTooltop": "Share profile via...", - "acquiredTicketsFromServer": "Antispam Challenge Complete", - "acquiringTicketsFromServer": "Performing Antispam Challenge", "errorDownloadDirectoryDoesNotExist": "Filesharing cannot be enabled because the Download Folder has not been set, or is set to a folder that does not exist.", - "localeTr": "Turkish \/ Türk", - "tooltipUnpinConversation": "Unpin conversation from the top of \"Conversations\"", - "tooltipPinConversation": "Pin conversation to the top of \"Conversations\"", - "replyingTo": "Replying to %1", - "fileDownloadUnavailable": "This file appears unavailable for download. The sender may have disabled downloads for this file.", - "messageNoReplies": "There are no replies to this message.", - "headingReplies": "Replies", - "viewReplies": "View replies to this message", - "restartFileShare": "Start Sharing File", - "stopSharingFile": "Stop Sharing File", - "manageSharedFiles": "Manage Shared Files", - "tooltipPreviewFormatting": "Preview Message Formatting", - "tooltipCode": "Code \/ Monospace", - "tooltipStrikethrough": "Strikethrough", - "tooltipSubscript": "Subscript", "tooltipSuperscript": "Superscript", - "tooltipItalicize": "Italic", - "tooltipBackToMessageEditing": "Back to Message Editing", - "tooltipBoldText": "Bold", - "okButton": "OK", - "settingsAndroidPowerReenablePopup": "Cannot re-enable Battery Optimization from within Cwtch. Please go to Android \/ Settings \/ Apps \/ Cwtch \/ Battery and set Usage to 'Optimized'", - "settingAndroidPowerExemptionDescription": "Optional: Request Android to exempt Cwtch from optimized power management. This will result in better stability at the cost of greater battery use.", - "settingAndroidPowerExemption": "Android Ignore Battery Optimizations", - "thisFeatureRequiresGroupExpermientsToBeEnabled": "This feature requires the Groups Experiment to be enabled in Settings", - "messageFormattingDescription": "Enable rich text formatting in displayed messages e.g. **bold** and *italic*", - "formattingExperiment": "Message Formatting", - "clickableLinkError": "Error encountered while attempting to open URL", - "clickableLinksCopy": "Copy URL", - "clickableLinkOpen": "Open URL", - "clickableLinksWarning": "Opening this URL will launch an application outside of Cwtch and may reveal metadata or otherwise compromise the security of Cwtch. Only open URLs from people you trust. Are you sure you want to continue?", - "shuttingDownApp": "Shutting down...", - "successfullyImportedProfile": "Successfully Imported Profile: %profile", - "failedToImportProfile": "Error Importing Profile", - "importProfileTooltip": "Use an encrypted Cwtch backup to bring in a profile created in another instance of Cwtch.", - "importProfile": "Import Profile", - "exportProfileTooltip": "Backup this profile to an encrypted file. The encrypted file can be imported into another Cwtch app.", - "exportProfile": "Export Profile", - "localeDa": "Danish \/ Dansk", - "localeCy": "Welsh \/ Cymraeg", - "localeEl": "Greek \/ Ελληνικά", - "localeNo": "Norwegian \/ Norsk", - "localeLb": "Luxembourgish \/ Lëtzebuergesch", - "localeRo": "Romanian \/ Română", - "newMessageNotificationConversationInfo": "New Message From %1", - "newMessageNotificationSimple": "New Message", - "notificationContentContactInfo": "Conversation Information", - "notificationContentSimpleEvent": "Plain Event", - "conversationNotificationPolicySettingDescription": "Control notification behaviour for this conversation", - "conversationNotificationPolicySettingLabel": "Conversation Notification Policy", - "settingsGroupExperiments": "Experiments", - "settingsGroupAppearance": "Appearance", - "settingGroupBehaviour": "Behaviour", - "notificationContentSettingDescription": "Controls the contents of conversation notifications", - "notificationPolicySettingDescription": "Controls the default application notification behaviour", - "notificationContentSettingLabel": "Notification Content", - "notificationPolicySettingLabel": "Notification Policy", - "conversationNotificationPolicyNever": "Never", - "conversationNotificationPolicyOptIn": "Opt In", - "conversationNotificationPolicyDefault": "Default", - "notificationPolicyDefaultAll": "Default All", - "notificationPolicyOptIn": "Opt In", - "notificationPolicyMute": "Mute", - "tooltipSelectACustomProfileImage": "Select a Custom Profile Image", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", - "torSettingsEnableCache": "Cache Tor Consensus", - "labelTorNetwork": "Tor Network", - "descriptionACNCircuitInfo": "In depth information about the path that the anonymous communication network is using to connect to this conversation.", - "labelACNCircuitInfo": "ACN Circuit Info", - "fileSharingSettingsDownloadFolderTooltip": "Browse to select a different default folder for downloaded files.", - "fileSharingSettingsDownloadFolderDescription": "When files are downloaded automatically (e.g. image files, when image previews are enabled) a default location to download the files to is needed.", - "torSettingsErrorSettingPort": "Port Number must be between 1 and 65535", - "torSettingsUseCustomTorServiceConfigurastionDescription": "Override the default tor configuration. Warning: This could be dangerous. Only turn this on if you know what you are doing.", "torSettingsUseCustomTorServiceConfiguration": "Use a Custom Tor Service Configuration (torrc)", "torSettingsCustomControlPortDescription": "Use a custom port for control connections to the Tor proxy", "torSettingsCustomControlPort": "Custom Control Port", diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index 7998523d..f7a7454f 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -1,6 +1,6 @@ { "@@locale": "tr", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "profileEnabledDescription": "Profili başlat veya durdur", "localeSw": "Swahili \/ Kiswahili", diff --git a/lib/l10n/intl_uk.arb b/lib/l10n/intl_uk.arb index b750e433..2fee8ede 100644 --- a/lib/l10n/intl_uk.arb +++ b/lib/l10n/intl_uk.arb @@ -1,6 +1,6 @@ { "@@locale": "uk", - "@@last_modified": "2023-05-23T17:30:29+02:00", + "@@last_modified": "2023-05-29T14:05:23+02:00", "localeUk": "Ukrainian \/ українською", "localeSw": "Swahili \/ Kiswahili", "localeSv": "Swedish \/ Svenska", diff --git a/lib/models/appstate.dart b/lib/models/appstate.dart index a00d15f7..97c1fd9c 100644 --- a/lib/models/appstate.dart +++ b/lib/models/appstate.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:cwtch/config.dart'; import 'package:flutter/widgets.dart'; enum ModalState { none, storageMigration, shutdown } @@ -30,11 +31,13 @@ class AppState extends ChangeNotifier { void SetAppError(String error) { appError = error; + EnvironmentConfig.debugLog("App Error: ${appError}"); notifyListeners(); } void SetModalState(ModalState newState) { modalState = newState; + EnvironmentConfig.debugLog("Modal State: ${newState}"); notifyListeners(); } diff --git a/lib/views/splashView.dart b/lib/views/splashView.dart index ffdc2df0..67ad2ce7 100644 --- a/lib/views/splashView.dart +++ b/lib/views/splashView.dart @@ -1,4 +1,5 @@ import 'package:cwtch/models/appstate.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -52,7 +53,7 @@ class _SplashViewState extends State { : appState.modalState == ModalState.storageMigration ? AppLocalizations.of(context)!.storageMigrationModalMessage : AppLocalizations.of(context)!.shuttingDownApp, // Todo l10n AppLocalizations.of(context)!.storageMigrationModalMessage - style: TextStyle( + style: defaultTextButtonStyle.copyWith( fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor))), Visibility( visible: appState.modalState == ModalState.storageMigration || appState.modalState == ModalState.shutdown,