Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/cwtch-ui into notifix

This commit is contained in:
erinn 2021-07-02 16:27:16 -07:00
commit 644d6b9793
24 changed files with 374 additions and 238 deletions

View File

@ -11,7 +11,7 @@ steps:
image: cirrusci/flutter:dev image: cirrusci/flutter:dev
environment: environment:
buildbot_key_b64: buildbot_key_b64:
from_secret: buildbot_key_b64 from_secret: buildbot_key_b64
commands: commands:
- mkdir ~/.ssh - mkdir ~/.ssh
- echo $buildbot_key_b64 > ~/.ssh/id_rsa.b64 - echo $buildbot_key_b64 > ~/.ssh/id_rsa.b64
@ -68,8 +68,8 @@ steps:
- name: test-build-android - name: test-build-android
image: cirrusci/flutter:dev image: cirrusci/flutter:dev
when: when:
event: pull_request event: pull_request
volumes: volumes:
- name: deps - name: deps
path: /root/.pub-cache path: /root/.pub-cache
@ -106,7 +106,7 @@ steps:
- name: deps - name: deps
path: /root/.pub-cache path: /root/.pub-cache
commands: commands:
# - flutter config --enable-linux-desktop # - flutter config --enable-linux-desktop
- flutter test --coverage - flutter test --coverage
- genhtml coverage/lcov.info -o coverage/html - genhtml coverage/lcov.info -o coverage/html
@ -209,21 +209,10 @@ steps:
- name: build-windows - name: build-windows
image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc
environment:
pfx:
from_secret: pfx
pfx_pass:
from_secret: pfx_pass
commands: commands:
- flutter pub get - flutter pub get
- $Env:version += type .\VERSION - $Env:version += type .\VERSION
- $Env:builddate += type .\BUILDDATE - $Env:builddate += type .\BUILDDATE
- $Env:buildname = 'flwtch-win-' + $Env:version + '-' + $Env:builddate
- $Env:builddir = $Env:buildname
- $Env:zip = 'cwtch-' + $Env:version + '.zip'
- $Env:zipsha = $Env:zip + '.sha512'
- $Env:msix = 'cwtch-install-' + $Env:version + '.msix'
- $Env:msixsha = $Env:msix + '.sha512'
- $Env:releasedir = "build\\windows\\runner\\Release\\" - $Env:releasedir = "build\\windows\\runner\\Release\\"
- flutter build windows --dart-define BUILD_VER=$Env:version --dart-define BUILD_DATE=$Env:builddate - flutter build windows --dart-define BUILD_VER=$Env:version --dart-define BUILD_DATE=$Env:builddate
- copy windows\libCwtch.dll $Env:releasedir - copy windows\libCwtch.dll $Env:releasedir
@ -234,22 +223,46 @@ steps:
- copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:releasedir - copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:releasedir
- copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:releasedir - copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:releasedir
- powershell -command "Expand-Archive -Path tor.zip -DestinationPath $Env:releasedir\Tor" - powershell -command "Expand-Archive -Path tor.zip -DestinationPath $Env:releasedir\Tor"
- name: package-windows
image: openpriv/nsis:latest
environment:
pfx:
from_secret: pfx
pfx_pass:
from_secret: pfx_pass
commands:
- $Env:version += type .\VERSION
- $Env:builddate += type .\BUILDDATE
- $Env:releasedir = "build\\windows\\runner\\Release\\"
- $Env:zip = 'cwtch-' + $Env:version + '.zip'
- $Env:zipsha = $Env:zip + '.sha512'
- $Env:msix = 'cwtch-install-' + $Env:version + '.msix'
- $Env:msixsha = $Env:msix + '.sha512'
- $Env:buildname = 'flwtch-win-' + $Env:version + '-' + $Env:builddate
- $Env:builddir = $Env:buildname
- echo $Env:pfx > codesign.pfx.b64 - echo $Env:pfx > codesign.pfx.b64
- certutil -decode codesign.pfx.b64 codesign.pfx - certutil -decode codesign.pfx.b64 codesign.pfx
- C:\MSIX-Toolkit\MSIX-Toolkit.x64\signtool sign /v /fd sha256 /a /f codesign.pfx /p $Env:pfx_pass /tr http://timestamp.digicert.com $Env:releasedir\cwtch.exe - signtool sign /v /fd sha256 /a /f codesign.pfx /p $Env:pfx_pass /tr http://timestamp.digicert.com $Env:releasedir\cwtch.exe
- copy windows\runner\resources\knot_128.ico $Env:releasedir\cwtch.ico
- makensis windows\nsis\cwtch-installer.nsi
- move windows\nsis\cwtch-installer.exe cwtch-installer.exe
- signtool sign /v /fd sha256 /a /f codesign.pfx /p $Env:pfx_pass /tr http://timestamp.digicert.com cwtch-installer.exe
- powershell -command "(Get-FileHash cwtch-installer.exe -Algorithm sha512).Hash" > cwtch-installer.sha512
- mkdir deploy - mkdir deploy
- mkdir deploy\$Env:builddir - mkdir deploy\$Env:builddir
- move $Env:releasedir $Env:builddir - move $Env:releasedir $Env:builddir
- powershell -command "Compress-Archive -Path $Env:builddir -DestinationPath cwtch.zip" - powershell -command "Compress-Archive -Path $Env:builddir -DestinationPath cwtch.zip"
- powershell -command "(Get-FileHash cwtch.zip -Algorithm sha512).Hash" > $Env:zipsha - powershell -command "(Get-FileHash cwtch.zip -Algorithm sha512).Hash" > $Env:zipsha
- move cwtch-installer.exe deploy\$Env:builddir\cwtch-installer.exe
- move cwtch.zip deploy\$Env:builddir\$Env:zip - move cwtch.zip deploy\$Env:builddir\$Env:zip
- move $Env:zipsha deploy\$Env:builddir - move *.sha512 deploy\$Env:builddir
- name: deploy-windows - name: deploy-windows
image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc
when: when:
event: push event: push
status: [ success ] status: [ success ]
environment: environment:
BUILDFILES_KEY: BUILDFILES_KEY:
from_secret: buildfiles_key from_secret: buildfiles_key

View File

@ -1 +1 @@
v1.0.0-7-g520d35a-2021-06-25-16-34 v1.0.0-20-gf8eedca-2021-06-30-20-48

View File

@ -178,7 +178,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
"CreateGroup" -> { "CreateGroup" -> {
val profile = (a.get("ProfileOnion") as? String) ?: "" val profile = (a.get("ProfileOnion") as? String) ?: ""
val server = (a.get("server") as? String) ?: "" val server = (a.get("server") as? String) ?: ""
val groupName = (a.get("groupname") as? String) ?: "" val groupName = (a.get("groupName") as? String) ?: ""
Cwtch.createGroup(profile, server, groupName) Cwtch.createGroup(profile, server, groupName)
} }
"DeleteProfile" -> { "DeleteProfile" -> {

View File

@ -245,6 +245,7 @@ class CwtchNotifier {
break; break;
case "ServerStateChange": case "ServerStateChange":
// Update the Server Cache // Update the Server Cache
EnvironmentConfig.debugLog("server state changes $data");
profileCN.getProfile(data["ProfileOnion"])?.updateServerStatusCache(data["GroupServer"], data["ConnectionState"]); profileCN.getProfile(data["ProfileOnion"])?.updateServerStatusCache(data["GroupServer"], data["ConnectionState"]);
profileCN.getProfile(data["ProfileOnion"])?.contactList.contacts.forEach((contact) { profileCN.getProfile(data["ProfileOnion"])?.contactList.contacts.forEach((contact) {
if (contact.isGroup == true && contact.server == data["GroupServer"]) { if (contact.isGroup == true && contact.server == data["GroupServer"]) {

View File

@ -115,6 +115,5 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''); OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''');
yield LicenseEntryWithLineBreaks(["flaticons"], "Icons made by Freepik (https://www.freepik.com) from Flaticon (www.flaticon.com)"); yield LicenseEntryWithLineBreaks(["flaticons"], "Icons made by Freepik (https://www.freepik.com) from Flaticon (www.flaticon.com)");
} }

View File

@ -190,7 +190,8 @@ class FlwtchState extends State<Flwtch> {
}, },
), ),
); );
} else { //dual pane } else {
//dual pane
Provider.of<AppState>(navKey.currentContext!, listen: false).selectedProfile = args["ProfileOnion"]; Provider.of<AppState>(navKey.currentContext!, listen: false).selectedProfile = args["ProfileOnion"];
Provider.of<AppState>(navKey.currentContext!, listen: false).selectedConversation = args["Handle"]; Provider.of<AppState>(navKey.currentContext!, listen: false).selectedConversation = args["Handle"];
} }

View File

@ -22,10 +22,7 @@ class LinuxNotificationsManager implements NotificationsManager {
} }
Future<void> notify(String message) async { Future<void> notify(String message) async {
var iconPath = Uri.file(path.join(path.current, "cwtch.png")); var iconPath = Uri.file(path.join(path.current, "cwtch.png"));
client.notify(message, appName: "cwtch", client.notify(message, appName: "cwtch", appIcon: iconPath.toString(), replacesId: this.previous_id).then((Notification value) => previous_id = value.id);
appIcon: iconPath.toString(),
replacesId: this.previous_id).then((Notification value) =>
previous_id = value.id);
} }
} }
@ -40,4 +37,4 @@ NotificationsManager newDesktopNotificationsManager() {
print("Attempted to access DBUS for notifications but failed. Switching off notifications."); print("Attempted to access DBUS for notifications but failed. Switching off notifications.");
} }
return NullNotificationsManager(); return NullNotificationsManager();
} }

View File

@ -314,7 +314,6 @@ abstract class OpaqueThemeType {
double contactOnionTextSize() { double contactOnionTextSize() {
return 18; return 18;
} }
} }
class OpaqueDark extends OpaqueThemeType { class OpaqueDark extends OpaqueThemeType {
@ -1440,4 +1439,4 @@ class Opaque extends OpaqueThemeType {
} }
} }
*/ */

View File

@ -161,26 +161,40 @@ class Settings extends ChangeNotifier {
List<int> uiColumns(bool isLandscape) { List<int> uiColumns(bool isLandscape) {
var m = (!isLandscape || uiColumnModeLandscape == DualpaneMode.CopyPortrait) ? uiColumnModePortrait : uiColumnModeLandscape; var m = (!isLandscape || uiColumnModeLandscape == DualpaneMode.CopyPortrait) ? uiColumnModePortrait : uiColumnModeLandscape;
switch(m) { switch (m) {
case DualpaneMode.Single: return [1]; case DualpaneMode.Single:
case DualpaneMode.Dual1to2: return [1, 2]; return [1];
case DualpaneMode.Dual1to4: return [1, 4]; case DualpaneMode.Dual1to2:
return [1, 2];
case DualpaneMode.Dual1to4:
return [1, 4];
} }
print("impossible column configuration: portrait/$uiColumnModePortrait landscape/$uiColumnModeLandscape"); print("impossible column configuration: portrait/$uiColumnModePortrait landscape/$uiColumnModeLandscape");
return [1]; return [1];
} }
static List<DualpaneMode> uiColumnModeOptions(bool isLandscape) { static List<DualpaneMode> uiColumnModeOptions(bool isLandscape) {
if (isLandscape) return [DualpaneMode.CopyPortrait, DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4,]; if (isLandscape)
else return [DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4]; return [
DualpaneMode.CopyPortrait,
DualpaneMode.Single,
DualpaneMode.Dual1to2,
DualpaneMode.Dual1to4,
];
else
return [DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4];
} }
static DualpaneMode uiColumnModeFromString(String m) { static DualpaneMode uiColumnModeFromString(String m) {
switch(m) { switch (m) {
case "DualpaneMode.Single": return DualpaneMode.Single; case "DualpaneMode.Single":
case "DualpaneMode.Dual1to2": return DualpaneMode.Dual1to2; return DualpaneMode.Single;
case "DualpaneMode.Dual1to4": return DualpaneMode.Dual1to4; case "DualpaneMode.Dual1to2":
case "DualpaneMode.CopyPortrait": return DualpaneMode.CopyPortrait; return DualpaneMode.Dual1to2;
case "DualpaneMode.Dual1to4":
return DualpaneMode.Dual1to4;
case "DualpaneMode.CopyPortrait":
return DualpaneMode.CopyPortrait;
} }
print("Error: ui requested translation of column mode [$m] which doesn't exist"); print("Error: ui requested translation of column mode [$m] which doesn't exist");
return DualpaneMode.Single; return DualpaneMode.Single;
@ -188,11 +202,15 @@ class Settings extends ChangeNotifier {
static String uiColumnModeToString(DualpaneMode m) { static String uiColumnModeToString(DualpaneMode m) {
// todo: translate // todo: translate
switch(m) { switch (m) {
case DualpaneMode.Single: return "Single"; case DualpaneMode.Single:
case DualpaneMode.Dual1to2: return "Double (1:2)"; return "Single";
case DualpaneMode.Dual1to4: return "Double (1:4)"; case DualpaneMode.Dual1to2:
case DualpaneMode.CopyPortrait: return "Same as portrait mode setting"; return "Double (1:2)";
case DualpaneMode.Dual1to4:
return "Double (1:4)";
case DualpaneMode.CopyPortrait:
return "Same as portrait mode setting";
} }
} }

View File

@ -152,9 +152,14 @@ class _AddContactViewState extends State<AddContactView> {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
if (globalErrorHandler.importBundleSuccess) { if (globalErrorHandler.importBundleSuccess) {
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + importBundle)); // TODO: This isn't ideal, but because onChange can be fired during this future check
ScaffoldMessenger.of(context).showSnackBar(snackBar); // and because the context can change after being popped we have this kind of double assertion...
Navigator.pop(context); // There is probably a better pattern to handle this...
if (AppLocalizations.of(context) != null) {
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.successfullAddedContact + importBundle));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
Navigator.popUntil(context, (route) => route.settings.name == "conversations");
}
} }
}); });
}, },

View File

@ -166,7 +166,10 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
autoFillHints: [AutofillHints.newPassword], autoFillHints: [AutofillHints.newPassword],
validator: (value) { validator: (value) {
// Password field can be empty when just updating the profile, not on creation // Password field can be empty when just updating the profile, not on creation
if (Provider.of<ProfileInfoState>(context).isEncrypted && Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { if (Provider.of<ProfileInfoState>(context).isEncrypted &&
Provider.of<ProfileInfoState>(context, listen: false).onion.isEmpty &&
value.isEmpty &&
usePassword) {
return AppLocalizations.of(context)!.passwordErrorEmpty; return AppLocalizations.of(context)!.passwordErrorEmpty;
} }
if (Provider.of<ErrorHandler>(context).deleteProfileError == true) { if (Provider.of<ErrorHandler>(context).deleteProfileError == true) {

View File

@ -29,7 +29,7 @@ class _DoubleColumnViewState extends State<DoubleColumnView> {
Flexible( Flexible(
flex: cols[1], flex: cols[1],
child: flwtch.selectedConversation == null child: flwtch.selectedConversation == null
? Card(child:Center(child: Text(AppLocalizations.of(context)!.addContactFirst))) ? Card(child: Center(child: Text(AppLocalizations.of(context)!.addContactFirst)))
: //dev : //dev
MultiProvider(providers: [ MultiProvider(providers: [
ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context)), ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context)),

View File

@ -169,7 +169,7 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
)), )),
AboutListTile( AboutListTile(
icon: Icon(Icons.info, color: settings.current().mainTextColor()), icon: Icon(Icons.info, color: settings.current().mainTextColor()),
applicationIcon: Padding(padding:EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)), applicationIcon: Padding(padding: EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)),
applicationName: "Cwtch (Flutter UI)", applicationName: "Cwtch (Flutter UI)",
applicationVersion: AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE), applicationVersion: AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE),
applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', applicationLegalese: '\u{a9} 2021 Open Privacy Research Society',

View File

@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cwtch/views/peersettingsview.dart'; import 'package:cwtch/views/peersettingsview.dart';
import 'package:cwtch/widgets/DropdownContacts.dart'; import 'package:cwtch/widgets/DropdownContacts.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -50,17 +51,19 @@ class _MessageViewState extends State<MessageView> {
appBar: AppBar( appBar: AppBar(
// setting leading to null makes it do the default behaviour; container() hides it // setting leading to null makes it do the default behaviour; container() hides it
leading: Provider.of<Settings>(context).uiColumns(appState.isLandscape(context)).length > 1 ? Container() : null, leading: Provider.of<Settings>(context).uiColumns(appState.isLandscape(context)).length > 1 ? Container() : null,
title: Row(children: [ title: Row(children: [
ProfileImage( ProfileImage(
imagePath: Provider.of<ContactInfoState>(context).imagePath, imagePath: Provider.of<ContactInfoState>(context).imagePath,
diameter: 42, diameter: 42,
border: Provider.of<Settings>(context).current().portraitOnlineBorderColor(), border: Provider.of<Settings>(context).current().portraitOnlineBorderColor(),
badgeTextColor: Colors.red, badgeTextColor: Colors.red,
badgeColor: Colors.red, badgeColor: Colors.red,
), ),
SizedBox( SizedBox(
width: 10, width: 10,
),Text(Provider.of<ContactInfoState>(context).nickname)]), ),
Text(Provider.of<ContactInfoState>(context).nickname)
]),
actions: [ actions: [
//IconButton(icon: Icon(Icons.chat), onPressed: _pushContactSettings), //IconButton(icon: Icon(Icons.chat), onPressed: _pushContactSettings),
//IconButton(icon: Icon(Icons.list), onPressed: _pushContactSettings), //IconButton(icon: Icon(Icons.list), onPressed: _pushContactSettings),
@ -100,11 +103,13 @@ class _MessageViewState extends State<MessageView> {
} }
void _sendMessage([String? ignoredParam]) { void _sendMessage([String? ignoredParam]) {
ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text); if (ctrlrCompose.value.text.isNotEmpty) {
Provider.of<FlwtchState>(context, listen: false) ChatMessage cm = new ChatMessage(o: 1, d: ctrlrCompose.value.text);
.cwtch Provider.of<FlwtchState>(context, listen: false)
.SendMessage(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, jsonEncode(cm)); .cwtch
_sendMessageHelper(); .SendMessage(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion, jsonEncode(cm));
_sendMessageHelper();
}
} }
void _sendInvitation([String? ignoredParam]) { void _sendInvitation([String? ignoredParam]) {
@ -135,12 +140,18 @@ class _MessageViewState extends State<MessageView> {
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of<Settings>(context).theme.defaultButtonActiveColor()))), decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of<Settings>(context).theme.defaultButtonActiveColor()))),
child: RawKeyboardListener(
focusNode: FocusNode(),
onKey: handleKeyPress,
child: TextFormField( child: TextFormField(
key: Key('txtCompose'), key: Key('txtCompose'),
controller: ctrlrCompose, controller: ctrlrCompose,
autofocus: !Platform.isAndroid,
focusNode: focusNode, focusNode: focusNode,
textInputAction: TextInputAction.send, autofocus: !Platform.isAndroid,
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: null,
onFieldSubmitted: _sendMessage, onFieldSubmitted: _sendMessage,
decoration: InputDecoration( decoration: InputDecoration(
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
@ -158,13 +169,26 @@ class _MessageViewState extends State<MessageView> {
tooltip: AppLocalizations.of(context)!.sendMessage, tooltip: AppLocalizations.of(context)!.sendMessage,
onPressed: _sendMessage, onPressed: _sendMessage,
), ),
))), )))),
), ),
], ],
), ),
); );
} }
// Send the message if enter is pressed without the shift key...
void handleKeyPress(event) {
var data = event.data as RawKeyEventData;
if (data.logicalKey == LogicalKeyboardKey.enter && !event.isShiftPressed) {
final messageWithoutNewLine = ctrlrCompose.value.text.trimRight();
ctrlrCompose.value = TextEditingValue(
text: messageWithoutNewLine
);
_sendMessage();
}
}
void placeHolder() => {}; void placeHolder() => {};
// explicitly passing BuildContext ctx here is important, change at risk to own health // explicitly passing BuildContext ctx here is important, change at risk to own health

View File

@ -40,45 +40,41 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
// Prevents Android back button from closing the app on the profile manager screen // Prevents Android back button from closing the app on the profile manager screen
// (which would shutdown connections and all kinds of other expensive to generate things) // (which would shutdown connections and all kinds of other expensive to generate things)
// TODO pop up a dialogue regarding closing the app? // TODO pop up a dialogue regarding closing the app?
builder: (context, settings, child) => builder: (context, settings, child) => WillPopScope(
WillPopScope( onWillPop: () async {
onWillPop: () async { _modalShutdown();
_modalShutdown(); return Provider.of<AppState>(context, listen: false).cwtchIsClosing;
return Provider.of<AppState>(context, listen: false).cwtchIsClosing; },
}, child: Scaffold(
child: Scaffold( backgroundColor: settings.theme.backgroundMainColor(),
backgroundColor: settings.theme.backgroundMainColor(), appBar: AppBar(
appBar: AppBar( title: Row(children: [
title: Row(children: [ Image(
Image( image: AssetImage("assets/core/knott-white.png"),
image: AssetImage("assets/core/knott-white.png"), filterQuality: FilterQuality.medium,
filterQuality: FilterQuality.medium, isAntiAlias: true,
isAntiAlias: true, width: 32,
width: 32, height: 32,
height: 32, colorBlendMode: BlendMode.dstIn,
colorBlendMode: BlendMode.dstIn, color: Provider.of<Settings>(context).theme.backgroundHilightElementColor(),
color: Provider
.of<Settings>(context)
.theme
.backgroundHilightElementColor(),
),
SizedBox(
width: 10,
),
Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor())))
]),
actions: getActions(),
), ),
floatingActionButton: FloatingActionButton( SizedBox(
onPressed: _pushAddEditProfile, width: 10,
tooltip: AppLocalizations.of(context)!.addNewProfileBtn,
child: Icon(
Icons.add,
semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn,
),
), ),
body: _buildProfileManager(), Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor())))
)), ]),
actions: getActions(),
),
floatingActionButton: FloatingActionButton(
onPressed: _pushAddEditProfile,
tooltip: AppLocalizations.of(context)!.addNewProfileBtn,
child: Icon(
Icons.add,
semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn,
),
),
body: _buildProfileManager(),
)),
); );
} }

View File

@ -33,7 +33,11 @@ class _ContactRowState extends State<ContactRow> {
diameter: 64.0, diameter: 64.0,
imagePath: contact.imagePath, imagePath: contact.imagePath,
maskOut: !contact.isOnline(), maskOut: !contact.isOnline(),
border: contact.isOnline() ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : contact.isBlocked ? Provider.of<Settings>(context).theme.portraitBlockedBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()), border: contact.isOnline()
? Provider.of<Settings>(context).theme.portraitOnlineBorderColor()
: contact.isBlocked
? Provider.of<Settings>(context).theme.portraitBlockedBorderColor()
: Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
), ),
Expanded( Expanded(
child: Padding( child: Padding(
@ -44,13 +48,16 @@ class _ContactRowState extends State<ContactRow> {
Text( Text(
contact.nickname, //(contact.isInvitation ? "invite " : "non-invite ") + (contact.isBlocked ? "blokt" : "nonblokt"),// contact.nickname, //(contact.isInvitation ? "invite " : "non-invite ") + (contact.isBlocked ? "blokt" : "nonblokt"),//
style: TextStyle(fontSize: Provider.of<Settings>(context).theme.contactOnionTextSize(), style: TextStyle(
color: contact.isBlocked ? Provider.of<Settings>(context).theme.portraitBlockedTextColor() : Provider.of<Settings>(context).theme.mainTextColor()), //Provider.of<FlwtchState>(context).biggerFont, fontSize: Provider.of<Settings>(context).theme.contactOnionTextSize(),
color: contact.isBlocked
? Provider.of<Settings>(context).theme.portraitBlockedTextColor()
: Provider.of<Settings>(context).theme.mainTextColor()), //Provider.of<FlwtchState>(context).biggerFont,
softWrap: true, softWrap: true,
overflow: TextOverflow.visible, overflow: TextOverflow.visible,
), ),
Text(contact.onion, Text(contact.onion,
style: TextStyle(color: contact.isBlocked ? Provider.of<Settings>(context).theme.portraitBlockedTextColor() : Provider.of<Settings>(context).theme.mainTextColor())), style: TextStyle(color: contact.isBlocked ? Provider.of<Settings>(context).theme.portraitBlockedTextColor() : Provider.of<Settings>(context).theme.mainTextColor())),
], ],
))), ))),
Padding( Padding(
@ -60,7 +67,10 @@ class _ContactRowState extends State<ContactRow> {
IconButton( IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
iconSize: 16, iconSize: 16,
icon: Icon(Icons.favorite, color: Provider.of<Settings>(context).theme.mainTextColor(),), icon: Icon(
Icons.favorite,
color: Provider.of<Settings>(context).theme.mainTextColor(),
),
tooltip: AppLocalizations.of(context)!.tooltipAcceptContactRequest, tooltip: AppLocalizations.of(context)!.tooltipAcceptContactRequest,
onPressed: _btnApprove, onPressed: _btnApprove,
), ),

View File

@ -66,18 +66,18 @@ class InvitationBubbleState extends State<InvitationBubble> {
return MalformedBubble(); return MalformedBubble();
} }
var wdgMessage = isGroup && !showGroupInvite ? var wdgMessage = isGroup && !showGroupInvite
Text(AppLocalizations.of(context)!.groupInviteSettingsWarning) : ? Text(AppLocalizations.of(context)!.groupInviteSettingsWarning)
fromMe : fromMe
? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation, ? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation,
isGroup ? Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget)!.nickname : Provider.of<MessageState>(context).message, myKey) isGroup ? Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget)!.nickname : Provider.of<MessageState>(context).message, myKey)
: (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of<MessageState>(context).inviteNick, : (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of<MessageState>(context).inviteNick,
Provider.of<MessageState>(context).inviteTarget, myKey)); Provider.of<MessageState>(context).inviteTarget, myKey));
Widget wdgDecorations; Widget wdgDecorations;
if (isGroup && !showGroupInvite) { if (isGroup && !showGroupInvite) {
wdgDecorations = Text('\u202F'); wdgDecorations = Text('\u202F');
} else if (fromMe) { } else if (fromMe) {
wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageState>(context).ackd, errored: Provider.of<MessageState>(context).error, fromMe: fromMe, prettyDate: prettyDate); wdgDecorations = MessageBubbleDecoration(ackd: Provider.of<MessageState>(context).ackd, errored: Provider.of<MessageState>(context).error, fromMe: fromMe, prettyDate: prettyDate);
} else if (isAccepted) { } else if (isAccepted) {
wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F'); wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F');
@ -113,7 +113,8 @@ class InvitationBubbleState extends State<InvitationBubble> {
child: Padding( child: Padding(
padding: EdgeInsets.all(9.0), padding: EdgeInsets.all(9.0),
child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [ child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [
Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(isGroup && !showGroupInvite ? CwtchIcons.enable_experiments : CwtchIcons.send_invite, size: 32))), Center(
widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(isGroup && !showGroupInvite ? CwtchIcons.enable_experiments : CwtchIcons.send_invite, size: 32))),
Center( Center(
widthFactor: 1.0, widthFactor: 1.0,
child: Column( child: Column(

View File

@ -16,16 +16,15 @@ class _MessageListState extends State<MessageList> {
@override @override
Widget build(BuildContext outerContext) { Widget build(BuildContext outerContext) {
bool isP2P = !Provider.of<ContactInfoState>(context).isGroup;
bool isP2P = !Provider.of<ContactInfoState>(context).isGroup;
bool isGroupAndSyncing = Provider.of<ContactInfoState>(context).isGroup == true && Provider.of<ContactInfoState>(context).status == "Authenticated"; bool isGroupAndSyncing = Provider.of<ContactInfoState>(context).isGroup == true && Provider.of<ContactInfoState>(context).status == "Authenticated";
bool isGroupAndSynced = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status == "Synced"; bool isGroupAndSynced = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status == "Synced";
bool isGroupAndNotAuthenticated= Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status != "Authenticated"; bool isGroupAndNotAuthenticated = Provider.of<ContactInfoState>(context).isGroup && Provider.of<ContactInfoState>(context).status != "Authenticated";
bool showEphemeralWarning = (isP2P && Provider.of<ContactInfoState>(context).savePeerHistory != "SaveHistory"); bool showEphemeralWarning = (isP2P && Provider.of<ContactInfoState>(context).savePeerHistory != "SaveHistory");
bool showOfflineWarning = Provider.of<ContactInfoState>(context).isOnline() == false; bool showOfflineWarning = Provider.of<ContactInfoState>(context).isOnline() == false;
bool showMessageWarning = showEphemeralWarning || showOfflineWarning;
bool showSyncing = isGroupAndSyncing; bool showSyncing = isGroupAndSyncing;
bool showMessageWarning = showEphemeralWarning || showOfflineWarning || showSyncing;
// Only load historical messages when the conversation is with a p2p contact OR the conversation is a server and *not* syncing. // Only load historical messages when the conversation is with a p2p contact OR the conversation is a server and *not* syncing.
bool loadMessages = isP2P || (isGroupAndSynced || isGroupAndNotAuthenticated); bool loadMessages = isP2P || (isGroupAndSynced || isGroupAndNotAuthenticated);
@ -37,18 +36,17 @@ class _MessageListState extends State<MessageList> {
child: Container( child: Container(
padding: EdgeInsets.all(5.0), padding: EdgeInsets.all(5.0),
color: Provider.of<Settings>(context).theme.defaultButtonActiveColor(), color: Provider.of<Settings>(context).theme.defaultButtonActiveColor(),
child: showSyncing ? child: showSyncing
Text(AppLocalizations.of(context)!.serverNotSynced, ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center)
textAlign: TextAlign.center) : showOfflineWarning
: showOfflineWarning ? Text(Provider.of<ContactInfoState>(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage,
? Text(Provider.of<ContactInfoState>(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, textAlign: TextAlign.center)
textAlign: TextAlign.center) // Only show the ephemeral status for peer conversations, not for groups...
// Only show the ephemeral status for peer conversations, not for groups... : (showEphemeralWarning
: (showEphemeralWarning ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center)
? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) :
: // We are not allowed to put null here, so put an empty text widge
// We are not allowed to put null here, so put an empty text widge Text("")),
Text("")),
)), )),
Expanded( Expanded(
child: Scrollbar( child: Scrollbar(
@ -63,30 +61,32 @@ class _MessageListState extends State<MessageList> {
alignment: Alignment.center, alignment: Alignment.center,
image: AssetImage("assets/core/negative_heart_512px.png"), image: AssetImage("assets/core/negative_heart_512px.png"),
colorFilter: ColorFilter.mode(Provider.of<Settings>(context).theme.hilightElementTextColor(), BlendMode.srcIn))), colorFilter: ColorFilter.mode(Provider.of<Settings>(context).theme.hilightElementTextColor(), BlendMode.srcIn))),
// Don't load messages for syncing server... // Don't load messages for syncing server...
child: loadMessages ? ListView.builder( child: loadMessages
controller: ctrlr1, ? ListView.builder(
itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages, controller: ctrlr1,
reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... itemCount: Provider.of<ContactInfoState>(outerContext).totalMessages,
itemBuilder: (itemBuilderContext, index) { reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction...
var trueIndex = Provider.of<ContactInfoState>(outerContext).totalMessages - index - 1; itemBuilder: (itemBuilderContext, index) {
return ChangeNotifierProvider( var trueIndex = Provider.of<ContactInfoState>(outerContext).totalMessages - index - 1;
key: ValueKey(trueIndex), return ChangeNotifierProvider(
create: (x) => MessageState( key: ValueKey(trueIndex),
context: itemBuilderContext, create: (x) => MessageState(
profileOnion: Provider.of<ProfileInfoState>(outerContext, listen: false).onion, context: itemBuilderContext,
// We don't want to listen for updates to the contact handle... profileOnion: Provider.of<ProfileInfoState>(outerContext, listen: false).onion,
contactHandle: Provider.of<ContactInfoState>(x, listen: false).onion, // We don't want to listen for updates to the contact handle...
messageIndex: trueIndex, contactHandle: Provider.of<ContactInfoState>(x, listen: false).onion,
), messageIndex: trueIndex,
builder: (bcontext, child) { ),
String idx = Provider.of<ContactInfoState>(outerContext).isGroup == true && Provider.of<MessageState>(bcontext).signature.isEmpty == false builder: (bcontext, child) {
? Provider.of<MessageState>(bcontext).signature String idx = Provider.of<ContactInfoState>(outerContext).isGroup == true && Provider.of<MessageState>(bcontext).signature.isEmpty == false
: trueIndex.toString(); ? Provider.of<MessageState>(bcontext).signature
return RepaintBoundary(child: MessageRow(key: Provider.of<ContactInfoState>(bcontext).getMessageKey(idx))); : trueIndex.toString();
}); return RepaintBoundary(child: MessageRow(key: Provider.of<ContactInfoState>(bcontext).getMessageKey(idx)));
}, });
) : null ))) },
)
: null)))
]))); ])));
} }
} }

View File

@ -30,43 +30,29 @@ class _ProfileRowState extends State<ProfileRow> {
padding: const EdgeInsets.all(2.0), //border size padding: const EdgeInsets.all(2.0), //border size
child: ProfileImage( child: ProfileImage(
badgeCount: 0, badgeCount: 0,
badgeColor: Provider badgeColor: Provider.of<Settings>(context).theme.portraitProfileBadgeColor(),
.of<Settings>(context) badgeTextColor: Provider.of<Settings>(context).theme.portraitProfileBadgeTextColor(),
.theme
.portraitProfileBadgeColor(),
badgeTextColor: Provider
.of<Settings>(context)
.theme
.portraitProfileBadgeTextColor(),
diameter: 64.0, diameter: 64.0,
imagePath: profile.imagePath, imagePath: profile.imagePath,
border: profile.isOnline ? Provider border: profile.isOnline ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor())),
.of<Settings>(context)
.theme
.portraitOnlineBorderColor() : Provider
.of<Settings>(context)
.theme
.portraitOfflineBorderColor())),
Expanded( Expanded(
child: Column( child: Column(
children: [ children: [
Text( Text(
profile.nickname, profile.nickname,
semanticsLabel: profile.nickname, semanticsLabel: profile.nickname,
style: Provider style: Provider.of<FlwtchState>(context).biggerFont,
.of<FlwtchState>(context) softWrap: true,
.biggerFont, overflow: TextOverflow.ellipsis,
softWrap: true, ),
overflow: TextOverflow.ellipsis, ExcludeSemantics(
), child: Text(
ExcludeSemantics( profile.onion,
child: Text( softWrap: true,
profile.onion, overflow: TextOverflow.ellipsis,
softWrap: true, ))
overflow: TextOverflow.ellipsis, ],
)) )),
],
)),
IconButton( IconButton(
enableFeedback: true, enableFeedback: true,
tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname,
@ -83,7 +69,7 @@ class _ProfileRowState extends State<ProfileRow> {
appState.selectedProfile = profile.onion; appState.selectedProfile = profile.onion;
appState.selectedConversation = null; appState.selectedConversation = null;
_pushContactList(profile, appState.isLandscape(context));//orientation == Orientation.landscape); _pushContactList(profile, appState.isLandscape(context)); //orientation == Orientation.landscape);
}); });
}, },
)); ));
@ -94,19 +80,17 @@ class _ProfileRowState extends State<ProfileRow> {
MaterialPageRoute<void>( MaterialPageRoute<void>(
settings: RouteSettings(name: "conversations"), settings: RouteSettings(name: "conversations"),
builder: (BuildContext buildcontext) { builder: (BuildContext buildcontext) {
return OrientationBuilder( return OrientationBuilder(builder: (orientationBuilderContext, orientation) {
builder: (orientationBuilderContext, orientation) { return MultiProvider(
return MultiProvider( providers: [
providers: [ ChangeNotifierProvider<ProfileInfoState>.value(value: profile),
ChangeNotifierProvider<ProfileInfoState>.value(value: profile), ChangeNotifierProvider<ContactListState>.value(value: profile.contactList),
ChangeNotifierProvider<ContactListState>.value(value: profile.contactList), ],
], builder: (innercontext, widget) {
builder: (innercontext, widget) { var appState = Provider.of<AppState>(context);
var appState = Provider.of<AppState>(context); var settings = Provider.of<Settings>(context);
var settings = Provider.of<Settings>(context); return settings.uiColumns(appState.isLandscape(innercontext)).length > 1 ? DoubleColumnView() : ContactsView();
return settings.uiColumns(appState.isLandscape(innercontext)).length > 1 ? DoubleColumnView() : ContactsView(); });
}
);
}); });
}, },
), ),

View File

@ -42,7 +42,7 @@ packages:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.1" version: "1.2.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -70,7 +70,7 @@ packages:
name: dbus name: dbus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.5.1" version: "0.5.2"
desktop_notifications: desktop_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
@ -91,14 +91,14 @@ packages:
name: ffi name: ffi
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.1.2"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.1" version: "6.1.2"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -125,7 +125,7 @@ packages:
name: glob name: glob
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "2.0.1"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -189,20 +189,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -216,7 +202,7 @@ packages:
name: package_info_plus name: package_info_plus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.3"
package_info_plus_linux: package_info_plus_linux:
dependency: transitive dependency: transitive
description: description:
@ -244,14 +230,14 @@ packages:
name: package_info_plus_web name: package_info_plus_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.2"
package_info_plus_windows: package_info_plus_windows:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_windows name: package_info_plus_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.2"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -265,7 +251,7 @@ packages:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.1" version: "2.0.2"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@ -300,14 +286,14 @@ packages:
name: pedantic name: pedantic
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.11.0" version: "1.11.1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
name: petitparser name: petitparser
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "4.2.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -382,7 +368,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.1" version: "0.4.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -403,7 +389,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.1" version: "2.2.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

BIN
windows/nsis/brand_side.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,92 @@
; USAGE: Run in ui/deploy, requires the output be in 'windows' directory
!include "MUI2.nsh"
; General settings ----------------------------
Name "Cwtch"
; !define MUI_BRANDINGTEXT "SIG Beta Ver. 1.0"
Unicode True
# define the name of the installer
Outfile "cwtch-installer.exe"
# For removing Start Menu shortcut in Windows 7
#RequestExecutionLevel user
RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on)
# define the directory to install to, the desktop in this case as specified
# by the predefined $DESKTOP variable
InstallDir "$PROGRAMFILES\Cwtch"
;Get installation folder from registry if available
InstallDirRegKey HKCU "Software\Cwtch" "installLocation"
; MUI Interface -----------------------------
!define MUI_INSTALLCOLORS "DFB9DE 281831"
; 128x128, 32bit
!define MUI_ICON "../runner/resources/knot_128.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "cwtch_title.bmp"
!define MUI_TEXTCOLOR "350052"
!define MUI_WELCOMEFINISHPAGE_BITMAP "brand_side.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP_STRETCH NoStretchNoCrop
!define MUI_INSTFILESPAGE_COLORS "DFB9DE 281831"
!define MUI_INSTFILESPAGE_PROGRESSBAR "colored"
!define MUI_FINISHPAGE_NOAUTOCLOSE
ShowInstDetails show
; Pages --------
!define MUI_WELCOMEPAGE_TITLE "Welcome to the Cwtch installer"
!define MUI_WELCOMEPAGE_TEXT "Cwtch (pronounced: kutch) is a Welsh word roughly meaning 'a hug that creates a safe space'$\n$\n\
Cwtch is a platform for building consentful, decentralized, untrusted infrastructure using metadata resistant group communication applications. Currently there is a selfnamed instant messaging prototype app that is driving development and testing. Many Further apps are planned as the platform matures."
!define MUI_FINISHPAGE_TITLE "Enjoy Cwtch"
!define MUI_FINISHPAGE_RUN $INSTDIR/cwtch.exe
!define MUI_FINISHPAGE_TEXT "You can keep up-to-date on Cwtch and report any issues you have at https://cwtch.im"
!define MUI_FINISHPAGE_LINK "https://cwtch.im"
!define MUI_FINISHPAGE_LINK_LOCATION "https://cwtch.im"
!define MUI_FINISHPAGE_LINK_COLOR "D01972"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "../../LICENSE"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
; Languages --------------------------------
!insertmacro MUI_LANGUAGE "English"
# default section
Section
# define the output path for this file
SetOutPath $INSTDIR
# define what to install and place it in the output path
# Filler for .sh to populate with contents of deploy/windows
#FILESLISTSTART
FILE /r "..\..\build\windows\runner\Release\"
#FILESLISTEND
# create a shortcut in the start menu programs directory
CreateDirectory "$SMPROGRAMS\Cwtch"
CreateShortcut "$SMPROGRAMS\Cwtch\Cwtch.lnk" "$INSTDIR\cwtch.exe" "" "$INSTDIR\cwtch.ico"
;Store installation folder
WriteRegStr HKCU "Software\Cwtch" "installLocation" $INSTDIR
SectionEnd

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -9,7 +9,14 @@ RunLoop::RunLoop() {}
RunLoop::~RunLoop() {} RunLoop::~RunLoop() {}
void RunLoop::Run() { void RunLoop::Run() {
bool keep_running = true; // Fix/workaround for Windows high CPU usage
// https://github.com/flutter/flutter/issues/78517#issuecomment-814843107
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/*bool keep_running = true;
TimePoint next_flutter_event_time = TimePoint::clock::now(); TimePoint next_flutter_event_time = TimePoint::clock::now();
while (keep_running) { while (keep_running) {
std::chrono::nanoseconds wait_duration = std::chrono::nanoseconds wait_duration =
@ -40,7 +47,7 @@ void RunLoop::Run() {
next_flutter_event_time = next_flutter_event_time =
std::min(next_flutter_event_time, ProcessFlutterMessages()); std::min(next_flutter_event_time, ProcessFlutterMessages());
} }
} }*/
} }
void RunLoop::RegisterFlutterInstance( void RunLoop::RegisterFlutterInstance(