Merge branch 'trunk' of git.openprivacy.ca:flutter/flutter_app into integtests
continuous-integration/drone/pr Build is passing
Details
28
.drone.yml
|
@ -144,17 +144,37 @@ steps:
|
||||||
image: openpriv/flutter-desktop:windows-dev
|
image: openpriv/flutter-desktop:windows-dev
|
||||||
commands:
|
commands:
|
||||||
- git fetch --tags
|
- git fetch --tags
|
||||||
- git describe --tags > VERSION
|
- powershell -command "git describe --tags > VERSION"
|
||||||
- date +%G-%m-%d-%H-%M > BUILDDATE
|
- powershell -command "Get-Date -Format 'yyyy-MM-dd-HH-mm' >.\BUILDDATE"
|
||||||
- name: build-windows
|
- name: build-windows
|
||||||
image: openpriv/flutter-desktop:windows-dev
|
image: openpriv/flutter-desktop:windows-dev
|
||||||
commands:
|
commands:
|
||||||
- flutter pub get
|
- flutter pub get
|
||||||
- mkdir deploy
|
|
||||||
- flutter build windows
|
- flutter build windows
|
||||||
|
# flwtch-`cat VERSION`-`cat BUILDDATE`
|
||||||
|
- $Env:builddir = 'deploy\flwtch-win-'
|
||||||
|
- $Env:builddir += type .\VERSION
|
||||||
|
- $Env:builddir += '-'
|
||||||
|
- $Env:builddir += type .\BUILDDATE
|
||||||
|
- mkdir deploy
|
||||||
|
- move windows/runner/Release/ $Env:builddir
|
||||||
|
- name: deploy-windows
|
||||||
|
image: appleboy/drone-scp:v1.4.0-windows
|
||||||
|
when:
|
||||||
|
event: push
|
||||||
|
status: [ success ]
|
||||||
|
settings:
|
||||||
|
host: openprivacy.ca
|
||||||
|
username: buildfiles
|
||||||
|
key:
|
||||||
|
from_secret: buildfiles_key
|
||||||
|
port: 22
|
||||||
|
target: /home/buildfiles/buildfiles/
|
||||||
|
#/var/www/deploy/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}
|
||||||
|
source: deploy/*
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
repo: flutter/flutter_app
|
repo: flutter/flutter_app
|
||||||
branch: trunk
|
branch: trunk
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
|
|
@ -44,3 +44,4 @@ libCwtch.so
|
||||||
android/cwtch/cwtch.aar
|
android/cwtch/cwtch.aar
|
||||||
coverage
|
coverage
|
||||||
test/failures
|
test/failures
|
||||||
|
.gradle
|
|
@ -157,6 +157,9 @@ class MainActivity: FlutterActivity() {
|
||||||
val jsonEvent = (call.argument("jsonEvent") as? String) ?: "";
|
val jsonEvent = (call.argument("jsonEvent") as? String) ?: "";
|
||||||
Cwtch.sendAppEvent(jsonEvent);
|
Cwtch.sendAppEvent(jsonEvent);
|
||||||
}
|
}
|
||||||
|
"ResetTor" -> {
|
||||||
|
Cwtch.resetTor();
|
||||||
|
}
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 622 B |
After Width: | Height: | Size: 7.0 KiB |
|
@ -1,13 +1,70 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
<svg
|
||||||
<style type="text/css">
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
.st0{fill:none;}
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
</style>
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
<path class="st0" d="M0,0h24v24H0V0z"/>
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
<path id="Subtraction_1" d="M18.5,16L18.5,16L5.3,4.4C6.3,3.5,7.6,3,9,3c1.7,0,3.3,0.7,4.4,2c1.1-1.3,2.7-2,4.4-2
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
C20.6,3,23,5.3,23,8.2c0,0,0,0.1,0,0.1c0,0.6-0.1,1.3-0.3,1.9c-0.2,0.7-0.5,1.3-0.9,1.9C21.1,13.2,20.1,14.4,18.5,16L18.5,16z"/>
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
<path d="M20.2,18.6L2.3,3.1L1,4.6l2.6,2.2C3.2,7.5,3,8.4,3,9.2c0,3.7,3.3,6.6,8.3,11.2l1.4,1.3l1.4-1.3c0.9-0.8,1.7-1.6,2.5-2.3
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
l2.3,2L20.2,18.6z"/>
|
version="1.1"
|
||||||
</svg>
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
style="enable-background:new 0 0 24 24;"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="negative_heart_24px.svg"
|
||||||
|
inkscape:export-filename="/home/sarah/AndroidStudioProjects/flutter_app/assets/core/negative_heart_512px.png"
|
||||||
|
inkscape:export-xdpi="4096"
|
||||||
|
inkscape:export-ydpi="4096"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
|
||||||
|
id="metadata14"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs12" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1015"
|
||||||
|
id="namedview10"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.8333333"
|
||||||
|
inkscape:cx="12"
|
||||||
|
inkscape:cy="14.687942"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Layer_1" />
|
||||||
|
<style
|
||||||
|
type="text/css"
|
||||||
|
id="style2">
|
||||||
|
.st0{fill:none;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<g
|
||||||
|
id="g824"
|
||||||
|
transform="translate(4.0677965,4.0677965)"><path
|
||||||
|
style="fill:none;stroke-width:0.66101694"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4"
|
||||||
|
d="M 0,0 H 15.864407 V 15.864407 H 0 Z"
|
||||||
|
class="st0" /><path
|
||||||
|
style="stroke-width:0.66101694"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 12.228814,10.576271 v 0 L 3.5033898,2.9084746 c 0.661017,-0.5949153 1.520339,-0.9254238 2.4457627,-0.9254238 1.1237289,0 2.181356,0.4627119 2.9084746,1.3220339 0.7271187,-0.859322 1.7847459,-1.3220339 2.9084749,-1.3220339 1.850847,0 3.437288,1.520339 3.437288,3.4372882 0,0 0,0.066102 0,0.066102 0,0.3966101 -0.0661,0.859322 -0.198305,1.2559322 -0.132204,0.4627118 -0.330509,0.859322 -0.594916,1.2559322 -0.462711,0.7271186 -1.123728,1.520339 -2.181355,2.5779656 z"
|
||||||
|
id="Subtraction_1" /><path
|
||||||
|
style="stroke-width:0.66101694"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7"
|
||||||
|
d="M 13.352542,12.294915 1.520339,2.0491525 0.66101695,3.040678 2.379661,4.4949153 C 2.1152542,4.9576271 1.9830508,5.5525424 1.9830508,6.0813559 c 0,2.4457627 2.181356,4.3627121 5.4864407,7.4033901 l 0.9254238,0.859322 0.9254237,-0.859322 c 0.5949152,-0.528814 1.123729,-1.057627 1.652542,-1.520339 l 1.520339,1.322034 z" /></g>
|
||||||
|
</svg>
|
Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 22 KiB |
|
@ -9,6 +9,9 @@ abstract class Cwtch {
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void LoadProfiles(String pass);
|
void LoadProfiles(String pass);
|
||||||
|
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
void ResetTor();
|
||||||
|
|
||||||
// todo: remove these
|
// todo: remove these
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
void SendProfileEvent(String onion, String jsonEvent);
|
void SendProfileEvent(String onion, String jsonEvent);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter_app/torstatus.dart';
|
||||||
|
|
||||||
import '../errorHandler.dart';
|
import '../errorHandler.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
@ -11,17 +13,20 @@ class CwtchNotifier {
|
||||||
ProfileListState profileCN;
|
ProfileListState profileCN;
|
||||||
Settings settings;
|
Settings settings;
|
||||||
ErrorHandler error;
|
ErrorHandler error;
|
||||||
|
TorStatus torStatus;
|
||||||
|
|
||||||
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN) {
|
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) {
|
||||||
profileCN = pcn;
|
profileCN = pcn;
|
||||||
settings = settingsCN;
|
settings = settingsCN;
|
||||||
error = errorCN;
|
error = errorCN;
|
||||||
|
torStatus = torStatusCN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleMessage(String type, dynamic data) {
|
void handleMessage(String type, dynamic data) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "NewPeer":
|
case "NewPeer":
|
||||||
profileCN.add(ProfileInfoState(onion: data["Identity"], nickname: data["name"], imagePath: data["picture"], contactsJson: data["ContactsJson"], online: data["Online"] == "true"));
|
profileCN.add(ProfileInfoState(
|
||||||
|
onion: data["Identity"], nickname: data["name"], imagePath: data["picture"], contactsJson: data["ContactsJson"], serversJson: data["ServerList"], online: data["Online"] == "true"));
|
||||||
break;
|
break;
|
||||||
case "PeerCreated":
|
case "PeerCreated":
|
||||||
profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState(
|
profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState(
|
||||||
|
@ -35,7 +40,8 @@ class CwtchNotifier {
|
||||||
savePeerHistory: data["saveConversationHistory"],
|
savePeerHistory: data["saveConversationHistory"],
|
||||||
numMessages: int.parse(data["numMessages"]),
|
numMessages: int.parse(data["numMessages"]),
|
||||||
numUnread: int.parse(data["unread"]),
|
numUnread: int.parse(data["unread"]),
|
||||||
lastMessageTime: DateTime.now(),//show at the top of the contact list even if no messages yet
|
isGroup: data["isGroup"],
|
||||||
|
lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
case "PeerStateChange":
|
case "PeerStateChange":
|
||||||
|
@ -75,6 +81,10 @@ class CwtchNotifier {
|
||||||
break;
|
break;
|
||||||
case "ACNStatus":
|
case "ACNStatus":
|
||||||
print("acn status: $data");
|
print("acn status: $data");
|
||||||
|
torStatus.handleUpdate(int.parse(data["Progress"]), data["Status"]);
|
||||||
|
break;
|
||||||
|
case "UpdateServerInfo":
|
||||||
|
profileCN.getProfile(data["ProfileOnion"]).replaceServers(data["ServerList"]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print("unhandled event: $type");
|
print("unhandled event: $type");
|
||||||
|
|
|
@ -297,4 +297,11 @@ class CwtchFfi implements Cwtch {
|
||||||
final u3 = message.toNativeUtf8();
|
final u3 = message.toNativeUtf8();
|
||||||
SendMessage(u1, u1.length, u2, u2.length, u3, u3.length);
|
SendMessage(u1, u1.length, u2, u2.length, u3, u3.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void ResetTor() {
|
||||||
|
var resetTor = library.lookup<NativeFunction<Void Function()>>("c_ResetTor");
|
||||||
|
final ResetTor = resetTor.asFunction<void Function()>();
|
||||||
|
ResetTor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,4 +142,10 @@ class CwtchGomobile implements Cwtch {
|
||||||
void SendMessage(String profileOnion, String contactHandle, String message) {
|
void SendMessage(String profileOnion, String contactHandle, String message) {
|
||||||
cwtchPlatform.invokeMethod("SendMessage", {"ProfileOnion": profileOnion, "handle": contactHandle, "message": message});
|
cwtchPlatform.invokeMethod("SendMessage", {"ProfileOnion": profileOnion, "handle": contactHandle, "message": message});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
void ResetTor() {
|
||||||
|
cwtchPlatform.invokeMethod("ResetTor", {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "",
|
"cycleColoursDesktop": "",
|
||||||
"cycleMorphsAndroid": "",
|
"cycleMorphsAndroid": "",
|
||||||
"cycleMorphsDesktop": "",
|
"cycleMorphsDesktop": "",
|
||||||
|
"dateDaysAgo": "",
|
||||||
|
"dateHoursAgo": "",
|
||||||
|
"dateLastMonth": "",
|
||||||
|
"dateLastYear": "",
|
||||||
|
"dateMinutesAgo": "",
|
||||||
|
"dateMonthsAgo": "",
|
||||||
|
"dateNever": "",
|
||||||
|
"dateRightNow": "",
|
||||||
|
"dateWeeksAgo": "",
|
||||||
|
"dateYearsAgo": "",
|
||||||
|
"dateYesterday": "",
|
||||||
"defaultGroupName": "Tolle Gruppe",
|
"defaultGroupName": "Tolle Gruppe",
|
||||||
"defaultProfileName": "Alice",
|
"defaultProfileName": "Alice",
|
||||||
"defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:",
|
"defaultScalingText": "defaultmäßige Textgröße (Skalierungsfaktor:",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "Sprache",
|
"settingLanguage": "Sprache",
|
||||||
"settingTheme": "Thema",
|
"settingTheme": "Thema",
|
||||||
"smallTextLabel": "Klein",
|
"smallTextLabel": "Klein",
|
||||||
|
"successfullAddedContact": "",
|
||||||
"themeDark": "Dunkel",
|
"themeDark": "Dunkel",
|
||||||
"themeLight": "Licht",
|
"themeLight": "Licht",
|
||||||
"titleManageContacts": "",
|
"titleManageContacts": "",
|
||||||
"titleManageProfiles": "",
|
"titleManageProfiles": "",
|
||||||
|
"titleManageServers": "",
|
||||||
"titlePlaceholder": "Titel...",
|
"titlePlaceholder": "Titel...",
|
||||||
"todoPlaceholder": "noch zu erledigen",
|
"todoPlaceholder": "noch zu erledigen",
|
||||||
"tooltipAddContact": "",
|
"tooltipAddContact": "",
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "Click to cycle colours.\\nRight-click to reset.",
|
"cycleColoursDesktop": "Click to cycle colours.\\nRight-click to reset.",
|
||||||
"cycleMorphsAndroid": "Click to cycle morphs.\\nLong-press to reset.",
|
"cycleMorphsAndroid": "Click to cycle morphs.\\nLong-press to reset.",
|
||||||
"cycleMorphsDesktop": "Click to cycle morphs.\\nRight-click to reset.",
|
"cycleMorphsDesktop": "Click to cycle morphs.\\nRight-click to reset.",
|
||||||
|
"dateDaysAgo": "Days Ago",
|
||||||
|
"dateHoursAgo": "Hours Ago",
|
||||||
|
"dateLastMonth": "Last Month",
|
||||||
|
"dateLastYear": "Last Year",
|
||||||
|
"dateMinutesAgo": "Minutes Ago",
|
||||||
|
"dateMonthsAgo": "Months Ago",
|
||||||
|
"dateNever": "Never",
|
||||||
|
"dateRightNow": "Right Now",
|
||||||
|
"dateWeeksAgo": "Weeks Ago",
|
||||||
|
"dateYearsAgo": "X Years Ago (displayed next to a contact row to indicate time of last action)",
|
||||||
|
"dateYesterday": "Yesterday",
|
||||||
"defaultGroupName": "Awesome Group",
|
"defaultGroupName": "Awesome Group",
|
||||||
"defaultProfileName": "Alice",
|
"defaultProfileName": "Alice",
|
||||||
"defaultScalingText": "Default size text (scale factor:",
|
"defaultScalingText": "Default size text (scale factor:",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "Language",
|
"settingLanguage": "Language",
|
||||||
"settingTheme": "Theme",
|
"settingTheme": "Theme",
|
||||||
"smallTextLabel": "Small",
|
"smallTextLabel": "Small",
|
||||||
|
"successfullAddedContact": "Successfully added ",
|
||||||
"themeDark": "Dark",
|
"themeDark": "Dark",
|
||||||
"themeLight": "Light",
|
"themeLight": "Light",
|
||||||
"titleManageContacts": "Manage Contacts",
|
"titleManageContacts": "Manage Contacts",
|
||||||
"titleManageProfiles": "Manage Cwtch Profiles",
|
"titleManageProfiles": "Manage Cwtch Profiles",
|
||||||
|
"titleManageServers": "Manage Servers",
|
||||||
"titlePlaceholder": "title...",
|
"titlePlaceholder": "title...",
|
||||||
"todoPlaceholder": "Todo...",
|
"todoPlaceholder": "Todo...",
|
||||||
"tooltipAddContact": "Add a new contact",
|
"tooltipAddContact": "Add a new contact",
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.",
|
"cycleColoursDesktop": "Click para cambiar colores. Click derecho para reiniciar.",
|
||||||
"cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.",
|
"cycleMorphsAndroid": "Click para cambiar transformaciones. Mantenga pulsado para reiniciar.",
|
||||||
"cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.",
|
"cycleMorphsDesktop": "Click para cambiar transformaciones. Click derecho para reiniciar.",
|
||||||
|
"dateDaysAgo": "",
|
||||||
|
"dateHoursAgo": "",
|
||||||
|
"dateLastMonth": "",
|
||||||
|
"dateLastYear": "",
|
||||||
|
"dateMinutesAgo": "",
|
||||||
|
"dateMonthsAgo": "",
|
||||||
|
"dateNever": "",
|
||||||
|
"dateRightNow": "",
|
||||||
|
"dateWeeksAgo": "",
|
||||||
|
"dateYearsAgo": "",
|
||||||
|
"dateYesterday": "",
|
||||||
"defaultGroupName": "El Grupo Asombroso",
|
"defaultGroupName": "El Grupo Asombroso",
|
||||||
"defaultProfileName": "Alicia",
|
"defaultProfileName": "Alicia",
|
||||||
"defaultScalingText": "Tamaño predeterminado de texto (factor de escala:",
|
"defaultScalingText": "Tamaño predeterminado de texto (factor de escala:",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "Idioma",
|
"settingLanguage": "Idioma",
|
||||||
"settingTheme": "Tema",
|
"settingTheme": "Tema",
|
||||||
"smallTextLabel": "Pequeño",
|
"smallTextLabel": "Pequeño",
|
||||||
|
"successfullAddedContact": "",
|
||||||
"themeDark": "Oscuro",
|
"themeDark": "Oscuro",
|
||||||
"themeLight": "Claro",
|
"themeLight": "Claro",
|
||||||
"titleManageContacts": "",
|
"titleManageContacts": "",
|
||||||
"titleManageProfiles": "",
|
"titleManageProfiles": "",
|
||||||
|
"titleManageServers": "",
|
||||||
"titlePlaceholder": "título...",
|
"titlePlaceholder": "título...",
|
||||||
"todoPlaceholder": "Por hacer...",
|
"todoPlaceholder": "Por hacer...",
|
||||||
"tooltipAddContact": "",
|
"tooltipAddContact": "",
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "",
|
"cycleColoursDesktop": "",
|
||||||
"cycleMorphsAndroid": "",
|
"cycleMorphsAndroid": "",
|
||||||
"cycleMorphsDesktop": "",
|
"cycleMorphsDesktop": "",
|
||||||
|
"dateDaysAgo": "",
|
||||||
|
"dateHoursAgo": "",
|
||||||
|
"dateLastMonth": "",
|
||||||
|
"dateLastYear": "",
|
||||||
|
"dateMinutesAgo": "",
|
||||||
|
"dateMonthsAgo": "",
|
||||||
|
"dateNever": "",
|
||||||
|
"dateRightNow": "",
|
||||||
|
"dateWeeksAgo": "",
|
||||||
|
"dateYearsAgo": "",
|
||||||
|
"dateYesterday": "",
|
||||||
"defaultGroupName": "Un super groupe",
|
"defaultGroupName": "Un super groupe",
|
||||||
"defaultProfileName": "",
|
"defaultProfileName": "",
|
||||||
"defaultScalingText": "Taille par défaut du texte (échelle:",
|
"defaultScalingText": "Taille par défaut du texte (échelle:",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "",
|
"settingLanguage": "",
|
||||||
"settingTheme": "",
|
"settingTheme": "",
|
||||||
"smallTextLabel": "Petit",
|
"smallTextLabel": "Petit",
|
||||||
|
"successfullAddedContact": "",
|
||||||
"themeDark": "",
|
"themeDark": "",
|
||||||
"themeLight": "",
|
"themeLight": "",
|
||||||
"titleManageContacts": "",
|
"titleManageContacts": "",
|
||||||
"titleManageProfiles": "",
|
"titleManageProfiles": "",
|
||||||
|
"titleManageServers": "",
|
||||||
"titlePlaceholder": "titre...",
|
"titlePlaceholder": "titre...",
|
||||||
"todoPlaceholder": "A faire...",
|
"todoPlaceholder": "A faire...",
|
||||||
"tooltipAddContact": "",
|
"tooltipAddContact": "",
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "Fare clic per scorrere i colori.\\nCliccare con il tasto destro per resettare.",
|
"cycleColoursDesktop": "Fare clic per scorrere i colori.\\nCliccare con il tasto destro per resettare.",
|
||||||
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\\nPressione lunga per resettare.",
|
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\\nPressione lunga per resettare.",
|
||||||
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\\nCliccare con il tasto destro per resettare.",
|
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\\nCliccare con il tasto destro per resettare.",
|
||||||
|
"dateDaysAgo": "",
|
||||||
|
"dateHoursAgo": "",
|
||||||
|
"dateLastMonth": "",
|
||||||
|
"dateLastYear": "",
|
||||||
|
"dateMinutesAgo": "",
|
||||||
|
"dateMonthsAgo": "",
|
||||||
|
"dateNever": "",
|
||||||
|
"dateRightNow": "",
|
||||||
|
"dateWeeksAgo": "",
|
||||||
|
"dateYearsAgo": "",
|
||||||
|
"dateYesterday": "",
|
||||||
"defaultGroupName": "Gruppo fantastico",
|
"defaultGroupName": "Gruppo fantastico",
|
||||||
"defaultProfileName": "Alice",
|
"defaultProfileName": "Alice",
|
||||||
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",
|
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "Lingua",
|
"settingLanguage": "Lingua",
|
||||||
"settingTheme": "Tema",
|
"settingTheme": "Tema",
|
||||||
"smallTextLabel": "Piccolo",
|
"smallTextLabel": "Piccolo",
|
||||||
|
"successfullAddedContact": "",
|
||||||
"themeDark": "Scuro",
|
"themeDark": "Scuro",
|
||||||
"themeLight": "Chiaro",
|
"themeLight": "Chiaro",
|
||||||
"titleManageContacts": "",
|
"titleManageContacts": "",
|
||||||
"titleManageProfiles": "",
|
"titleManageProfiles": "",
|
||||||
|
"titleManageServers": "",
|
||||||
"titlePlaceholder": "titolo...",
|
"titlePlaceholder": "titolo...",
|
||||||
"todoPlaceholder": "Da fare...",
|
"todoPlaceholder": "Da fare...",
|
||||||
"tooltipAddContact": "",
|
"tooltipAddContact": "",
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
"cycleColoursDesktop": "",
|
"cycleColoursDesktop": "",
|
||||||
"cycleMorphsAndroid": "",
|
"cycleMorphsAndroid": "",
|
||||||
"cycleMorphsDesktop": "",
|
"cycleMorphsDesktop": "",
|
||||||
|
"dateDaysAgo": "",
|
||||||
|
"dateHoursAgo": "",
|
||||||
|
"dateLastMonth": "",
|
||||||
|
"dateLastYear": "",
|
||||||
|
"dateMinutesAgo": "",
|
||||||
|
"dateMonthsAgo": "",
|
||||||
|
"dateNever": "",
|
||||||
|
"dateRightNow": "",
|
||||||
|
"dateWeeksAgo": "",
|
||||||
|
"dateYearsAgo": "",
|
||||||
|
"dateYesterday": "",
|
||||||
"defaultGroupName": "Grupo incrível",
|
"defaultGroupName": "Grupo incrível",
|
||||||
"defaultProfileName": "",
|
"defaultProfileName": "",
|
||||||
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
|
"defaultScalingText": "Texto tamanho padrão (fator de escala: ",
|
||||||
|
@ -123,10 +134,12 @@
|
||||||
"settingLanguage": "",
|
"settingLanguage": "",
|
||||||
"settingTheme": "",
|
"settingTheme": "",
|
||||||
"smallTextLabel": "Pequeno",
|
"smallTextLabel": "Pequeno",
|
||||||
|
"successfullAddedContact": "",
|
||||||
"themeDark": "",
|
"themeDark": "",
|
||||||
"themeLight": "",
|
"themeLight": "",
|
||||||
"titleManageContacts": "",
|
"titleManageContacts": "",
|
||||||
"titleManageProfiles": "",
|
"titleManageProfiles": "",
|
||||||
|
"titleManageServers": "",
|
||||||
"titlePlaceholder": "título…",
|
"titlePlaceholder": "título…",
|
||||||
"todoPlaceholder": "Afazer…",
|
"todoPlaceholder": "Afazer…",
|
||||||
"tooltipAddContact": "",
|
"tooltipAddContact": "",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter_app/cwtch/gomobile.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_app/errorHandler.dart';
|
import 'package:flutter_app/errorHandler.dart';
|
||||||
import 'package:flutter_app/settings.dart';
|
import 'package:flutter_app/settings.dart';
|
||||||
|
import 'package:flutter_app/torstatus.dart';
|
||||||
import 'package:flutter_app/views/triplecolview.dart';
|
import 'package:flutter_app/views/triplecolview.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'cwtch/cwtch.dart';
|
import 'cwtch/cwtch.dart';
|
||||||
|
@ -18,6 +19,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
var globalSettings = Settings(Locale("en", ''), Opaque.dark);
|
var globalSettings = Settings(Locale("en", ''), Opaque.dark);
|
||||||
var globalErrorHandler = ErrorHandler();
|
var globalErrorHandler = ErrorHandler();
|
||||||
|
var globalTorStatus = TorStatus();
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
LicenseRegistry.addLicense(() => licenses());
|
LicenseRegistry.addLicense(() => licenses());
|
||||||
|
@ -48,7 +50,7 @@ class FlwtchState extends State<Flwtch> {
|
||||||
cwtchInit = false;
|
cwtchInit = false;
|
||||||
|
|
||||||
profs = ProfileListState();
|
profs = ProfileListState();
|
||||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler);
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus);
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
cwtch = CwtchGomobile(cwtchNotifier);
|
cwtch = CwtchGomobile(cwtchNotifier);
|
||||||
|
@ -65,6 +67,7 @@ class FlwtchState extends State<Flwtch> {
|
||||||
appStatus = AppModel(cwtch: cwtch);
|
appStatus = AppModel(cwtch: cwtch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
|
||||||
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
|
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
|
||||||
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
|
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
|
||||||
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
|
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
|
||||||
|
@ -75,7 +78,7 @@ class FlwtchState extends State<Flwtch> {
|
||||||
//appStatus = AppModel(cwtch: cwtch);
|
//appStatus = AppModel(cwtch: cwtch);
|
||||||
|
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider(), getErrorHandlerProvider()],
|
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider(), getErrorHandlerProvider(), getTorStatusProvider()],
|
||||||
builder: (context, widget) {
|
builder: (context, widget) {
|
||||||
Provider.of<Settings>(context).initPackageInfo();
|
Provider.of<Settings>(context).initPackageInfo();
|
||||||
return Consumer<Settings>(
|
return Consumer<Settings>(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_app/models/servers.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
@ -34,16 +35,6 @@ class ContactModel {
|
||||||
ContactModel({this.onion, this.nickname, this.status, this.isInvitation, this.isBlocked, this.imagePath});
|
ContactModel({this.onion, this.nickname, this.status, this.isInvitation, this.isBlocked, this.imagePath});
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: delete
|
|
||||||
class DanMessageModel {
|
|
||||||
// ignore: non_constant_identifier_names
|
|
||||||
String Timestamp;
|
|
||||||
// ignore: non_constant_identifier_names
|
|
||||||
bool Acknowledged;
|
|
||||||
// ignore: non_constant_identifier_names
|
|
||||||
String Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatMessage {
|
class ChatMessage {
|
||||||
final int o;
|
final int o;
|
||||||
final String d;
|
final String d;
|
||||||
|
@ -123,6 +114,7 @@ class ContactListState extends ChangeNotifier {
|
||||||
|
|
||||||
class ProfileInfoState extends ChangeNotifier {
|
class ProfileInfoState extends ChangeNotifier {
|
||||||
ContactListState _contacts = ContactListState();
|
ContactListState _contacts = ContactListState();
|
||||||
|
ServerListState _servers = ServerListState();
|
||||||
final String onion;
|
final String onion;
|
||||||
String _nickname = "";
|
String _nickname = "";
|
||||||
String _imagePath = "";
|
String _imagePath = "";
|
||||||
|
@ -135,6 +127,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
imagePath = "",
|
imagePath = "",
|
||||||
unreadMessages = 0,
|
unreadMessages = 0,
|
||||||
contactsJson = "",
|
contactsJson = "",
|
||||||
|
serversJson = "",
|
||||||
online = false,
|
online = false,
|
||||||
}) {
|
}) {
|
||||||
this._nickname = nickname;
|
this._nickname = nickname;
|
||||||
|
@ -164,6 +157,20 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
this._contacts.updateLastMessageTime(this._contacts._contacts.first.onion, this._contacts._contacts.first.lastMessageTime);
|
this._contacts.updateLastMessageTime(this._contacts._contacts.first.onion, this._contacts._contacts.first.lastMessageTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.replaceServers(serversJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse out the server list json into our server info state struct...
|
||||||
|
void replaceServers(String serversJson) {
|
||||||
|
if (serversJson != null && serversJson != "" && serversJson != "null") {
|
||||||
|
print("got servers $serversJson");
|
||||||
|
List<dynamic> servers = jsonDecode(serversJson);
|
||||||
|
this._servers.replace(servers.map((server) {
|
||||||
|
// TODO Keys...
|
||||||
|
return ServerInfoState(onion: server["onion"], status: server["status"]);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters for Online Status
|
// Getters and Setters for Online Status
|
||||||
|
@ -192,6 +199,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactListState get contactList => this._contacts;
|
ContactListState get contactList => this._contacts;
|
||||||
|
ServerListState get serverList => this._servers;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ServerListState extends ChangeNotifier {
|
||||||
|
List<ServerInfoState> _servers = [];
|
||||||
|
|
||||||
|
void replace(Iterable<ServerInfoState> newServers) {
|
||||||
|
_servers.clear();
|
||||||
|
_servers.addAll(newServers);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfoState getServer(String onion) {
|
||||||
|
int idx = _servers.indexWhere((element) => element.onion == onion);
|
||||||
|
return idx >= 0 ? _servers[idx] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerInfoState extends ChangeNotifier {
|
||||||
|
final String onion;
|
||||||
|
final String status;
|
||||||
|
|
||||||
|
ServerInfoState({this.onion, this.status});
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TorStatus extends ChangeNotifier {
|
||||||
|
int progress;
|
||||||
|
String status;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
/// Called by the event bus.
|
||||||
|
handleUpdate(int new_progress, String new_status) {
|
||||||
|
if (progress == 100) {
|
||||||
|
connected = true;
|
||||||
|
} else {
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress = new_progress;
|
||||||
|
status = new_status;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_app/errorHandler.dart';
|
import 'package:flutter_app/errorHandler.dart';
|
||||||
|
import 'package:flutter_app/models/servers.dart';
|
||||||
import 'package:flutter_app/settings.dart';
|
import 'package:flutter_app/settings.dart';
|
||||||
import 'package:flutter_app/widgets/buttontextfield.dart';
|
import 'package:flutter_app/widgets/buttontextfield.dart';
|
||||||
import 'package:flutter_app/widgets/cwtchlabel.dart';
|
import 'package:flutter_app/widgets/cwtchlabel.dart';
|
||||||
|
@ -24,8 +25,11 @@ class AddContactView extends StatefulWidget {
|
||||||
|
|
||||||
class _AddContactViewState extends State<AddContactView> {
|
class _AddContactViewState extends State<AddContactView> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final _createGroupFormKey = GlobalKey<FormState>();
|
||||||
final ctrlrOnion = TextEditingController(text: "");
|
final ctrlrOnion = TextEditingController(text: "");
|
||||||
final ctrlrContact = TextEditingController(text: "");
|
final ctrlrContact = TextEditingController(text: "");
|
||||||
|
final ctrlrGroupName = TextEditingController(text: "");
|
||||||
|
String server = "";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -49,7 +53,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
(groupsEnabled ? getTabBarWithGroups() : getTabBarWithAddPeerOnly()),
|
(groupsEnabled ? getTabBarWithGroups() : getTabBarWithAddPeerOnly()),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
children: (groupsEnabled ? [addPeerTab(), addGroupTab(), joinGroupTab()] : [addPeerTab()]),
|
children: (groupsEnabled ? [addPeerTab(), manageServersTab(), addGroupTab(), joinGroupTab()] : [addPeerTab()]),
|
||||||
)),
|
)),
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
@ -57,7 +61,8 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
void _copyOnion() {
|
void _copyOnion() {
|
||||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||||
// TODO Toast
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Tab Bar with only the Add Peer Tab
|
/// A Tab Bar with only the Add Peer Tab
|
||||||
|
@ -80,6 +85,7 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
icon: Icon(Icons.person_add_rounded),
|
icon: Icon(Icons.person_add_rounded),
|
||||||
text: AppLocalizations.of(context).addPeer,
|
text: AppLocalizations.of(context).addPeer,
|
||||||
),
|
),
|
||||||
|
Tab(icon: Icon(Icons.backup), text: AppLocalizations.of(context).titleManageServers),
|
||||||
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context).createGroup),
|
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context).createGroup),
|
||||||
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup),
|
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup),
|
||||||
],
|
],
|
||||||
|
@ -137,6 +143,8 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
Future.delayed(const Duration(milliseconds: 500), () {
|
Future.delayed(const Duration(milliseconds: 500), () {
|
||||||
if (globalErrorHandler.explicitAddContactSuccess) {
|
if (globalErrorHandler.explicitAddContactSuccess) {
|
||||||
|
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).successfullAddedContact + peerAddr));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -147,11 +155,78 @@ class _AddContactViewState extends State<AddContactView> {
|
||||||
|
|
||||||
/// TODO Add Group Pane
|
/// TODO Add Group Pane
|
||||||
Widget addGroupTab() {
|
Widget addGroupTab() {
|
||||||
return Icon(Icons.group_add);
|
// TODO We should replace with with a "Paste in Server Key Bundle"
|
||||||
|
if (Provider.of<ProfileInfoState>(context).serverList.servers.isEmpty) {
|
||||||
|
return Text("You need to add a server before you can create a group.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we haven't picked a server yet, pick the first one in the list...
|
||||||
|
if (server.isEmpty) {
|
||||||
|
server = Provider.of<ProfileInfoState>(context).serverList.servers.first.onion;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.all(30),
|
||||||
|
padding: EdgeInsets.all(20),
|
||||||
|
child: Form(
|
||||||
|
autovalidateMode: AutovalidateMode.always,
|
||||||
|
key: _createGroupFormKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
CwtchLabel(label: AppLocalizations.of(context).server),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
DropdownButton(
|
||||||
|
onChanged: (newServer) {
|
||||||
|
server = newServer;
|
||||||
|
},
|
||||||
|
value: server,
|
||||||
|
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: serverInfo.onion,
|
||||||
|
child: Text(serverInfo.onion),
|
||||||
|
);
|
||||||
|
}).toList()),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
CwtchLabel(label: AppLocalizations.of(context).groupName),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
CwtchTextField(controller: ctrlrGroupName, labelText: AppLocalizations.of(context).groupNameLabel, onChanged: (newValue) {}),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: Text(AppLocalizations.of(context).createGroupBtn),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO Join Group Pane
|
/// TODO Join Group Pane
|
||||||
Widget joinGroupTab() {
|
Widget joinGroupTab() {
|
||||||
return Icon(Icons.group);
|
return Icon(Icons.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO Manage Servers Tab
|
||||||
|
Widget manageServersTab() {
|
||||||
|
final tiles = Provider.of<ProfileInfoState>(context).serverList.servers.map((ServerInfoState server) {
|
||||||
|
return ChangeNotifierProvider<ServerInfoState>.value(
|
||||||
|
value: server,
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(server.onion),
|
||||||
|
));
|
||||||
|
});
|
||||||
|
final divided = ListTile.divideTiles(
|
||||||
|
context: context,
|
||||||
|
tiles: tiles,
|
||||||
|
).toList();
|
||||||
|
return ListView(children: divided);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
|
||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../opaque.dart';
|
import '../opaque.dart';
|
||||||
|
import '../settings.dart';
|
||||||
import '../widgets/messagelist.dart';
|
import '../widgets/messagelist.dart';
|
||||||
|
|
||||||
class MessageView extends StatefulWidget {
|
class MessageView extends StatefulWidget {
|
||||||
|
@ -87,7 +88,7 @@ class _MessageViewState extends State<MessageView> {
|
||||||
|
|
||||||
Widget _buildComposeBox() {
|
Widget _buildComposeBox() {
|
||||||
return Container(
|
return Container(
|
||||||
color: Opaque.current().backgroundMainColor(),
|
color: Provider.of<Settings>(context).theme.backgroundMainColor(),
|
||||||
height: 100,
|
height: 100,
|
||||||
padding: EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -107,10 +108,10 @@ class _MessageViewState extends State<MessageView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.fromLTRB(2, 2, 2, 2),
|
padding: EdgeInsets.fromLTRB(2, 2, 2, 2),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
child: Icon(Icons.send, color: Opaque.current().mainTextColor()),
|
child: Icon(Icons.send, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
fixedSize: MaterialStateProperty.all(Size(86, 40)),
|
fixedSize: MaterialStateProperty.all(Size(86, 40)),
|
||||||
backgroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonColor()),
|
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
|
||||||
),
|
),
|
||||||
onPressed: _sendMessage,
|
onPressed: _sendMessage,
|
||||||
)),
|
)),
|
||||||
|
@ -120,10 +121,10 @@ class _MessageViewState extends State<MessageView> {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 41,
|
width: 41,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
child: Icon(Icons.emoji_emotions_outlined, color: Opaque.current().mainTextColor()),
|
child: Icon(Icons.emoji_emotions_outlined, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
fixedSize: MaterialStateProperty.all(Size(41, 40)),
|
fixedSize: MaterialStateProperty.all(Size(41, 40)),
|
||||||
backgroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonColor()),
|
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
|
||||||
),
|
),
|
||||||
onPressed: placeHolder,
|
onPressed: placeHolder,
|
||||||
))),
|
))),
|
||||||
|
@ -132,10 +133,10 @@ class _MessageViewState extends State<MessageView> {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 41,
|
width: 41,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
child: Icon(Icons.attach_file, color: Opaque.current().mainTextColor()),
|
child: Icon(Icons.attach_file, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
fixedSize: MaterialStateProperty.all(Size(41, 40)),
|
fixedSize: MaterialStateProperty.all(Size(41, 40)),
|
||||||
backgroundColor: MaterialStateProperty.all(Opaque.current().defaultButtonColor()),
|
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
|
||||||
),
|
),
|
||||||
onPressed: placeHolder,
|
onPressed: placeHolder,
|
||||||
))),
|
))),
|
||||||
|
|
|
@ -2,6 +2,8 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_app/settings.dart';
|
import 'package:flutter_app/settings.dart';
|
||||||
|
import 'package:flutter_app/torstatus.dart';
|
||||||
|
import 'package:flutter_app/views/torstatusview.dart';
|
||||||
import 'package:flutter_app/widgets/passwordfield.dart';
|
import 'package:flutter_app/widgets/passwordfield.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_app/widgets/profilerow.dart';
|
import 'package:flutter_app/widgets/profilerow.dart';
|
||||||
|
@ -34,6 +36,15 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context).titleManageProfiles),
|
title: Text(AppLocalizations.of(context).titleManageProfiles),
|
||||||
actions: [
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: Image(
|
||||||
|
image: AssetImage(Provider.of<TorStatus>(context).progress == 100 ? "assets/core/Tor_icon.png" : "assets/core/Tor_icon_error.png"),
|
||||||
|
filterQuality: FilterQuality.low,
|
||||||
|
isAntiAlias: false,
|
||||||
|
color: Provider.of<Settings>(context).theme.mainTextColor(),
|
||||||
|
colorBlendMode: BlendMode.srcIn,
|
||||||
|
),
|
||||||
|
onPressed: _pushTorStatus),
|
||||||
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
|
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.lock_open),
|
icon: Icon(Icons.lock_open),
|
||||||
|
@ -75,6 +86,17 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _pushTorStatus() {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return MultiProvider(
|
||||||
|
providers: [Provider.value(value: Provider.of<FlwtchState>(context))],
|
||||||
|
child: TorStatusView(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
void _pushAddEditProfile({onion: ""}) {
|
void _pushAddEditProfile({onion: ""}) {
|
||||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app/settings.dart';
|
||||||
|
import 'package:flutter_app/torstatus.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import '../main.dart';
|
||||||
|
|
||||||
|
/// Tor Status View provides all info on Tor network state and the (future) ability to configure the network in a variety
|
||||||
|
/// of ways (restart, enable bridges, enable pluggable transports etc)
|
||||||
|
class TorStatusView extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_TorStatusView createState() => _TorStatusView();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TorStatusView extends State<TorStatusView> {
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("Tor Network Status"),
|
||||||
|
),
|
||||||
|
body: _buildSettingsList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSettingsList() {
|
||||||
|
return Consumer<TorStatus>(builder: (context, torStatus, child) {
|
||||||
|
return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
|
||||||
|
return Scrollbar(
|
||||||
|
isAlwaysShown: true,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: viewportConstraints.maxHeight,
|
||||||
|
),
|
||||||
|
child: Column(children: [
|
||||||
|
ListTile(
|
||||||
|
leading: Image(
|
||||||
|
image: AssetImage(torStatus.progress == 100 ? "assets/core/Tor_icon.png" : "assets/core/Tor_icon_error.png"),
|
||||||
|
filterQuality: FilterQuality.low,
|
||||||
|
isAntiAlias: false,
|
||||||
|
// Color the onion per the text color...
|
||||||
|
color: Provider.of<Settings>(context).theme.mainTextColor(),
|
||||||
|
colorBlendMode: BlendMode.srcIn,
|
||||||
|
),
|
||||||
|
title: Text("Tor Status"),
|
||||||
|
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context).networkStatusOnline : torStatus.status),
|
||||||
|
trailing: ElevatedButton(
|
||||||
|
child: Text("Reset"),
|
||||||
|
onPressed: () {
|
||||||
|
Provider.of<FlwtchState>(context, listen: false).cwtch.ResetTor();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]))));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/painting.dart';
|
||||||
import 'package:flutter_app/views/messageview.dart';
|
import 'package:flutter_app/views/messageview.dart';
|
||||||
import 'package:flutter_app/widgets/profileimage.dart';
|
import 'package:flutter_app/widgets/profileimage.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../opaque.dart';
|
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class ContactRow extends StatefulWidget {
|
class ContactRow extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
|
@ -29,21 +30,24 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
badgeTextColor: Provider.of<Settings>(context).theme.portraitContactBadgeTextColor(),
|
badgeTextColor: Provider.of<Settings>(context).theme.portraitContactBadgeTextColor(),
|
||||||
diameter: 64.0,
|
diameter: 64.0,
|
||||||
imagePath: contact.imagePath,
|
imagePath: contact.imagePath,
|
||||||
maskOut: contact.status != "Authenticated",
|
maskOut: contact.isGroup ? false : contact.status != "Authenticated",
|
||||||
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
|
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Padding(
|
||||||
children: [
|
padding: EdgeInsets.all(10.0),
|
||||||
Text(
|
child: Column(
|
||||||
contact.nickname, //(contact.isInvitation ? "invite " : "non-invite ") + (contact.isBlocked ? "blokt" : "nonblokt"),//
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: Provider.of<FlwtchState>(context).biggerFont,
|
children: [
|
||||||
softWrap: true,
|
Text(
|
||||||
overflow: TextOverflow.visible,
|
contact.nickname, //(contact.isInvitation ? "invite " : "non-invite ") + (contact.isBlocked ? "blokt" : "nonblokt"),//
|
||||||
),
|
style: Provider.of<FlwtchState>(context).biggerFont,
|
||||||
Text(contact.status),
|
softWrap: true,
|
||||||
],
|
overflow: TextOverflow.visible,
|
||||||
)),
|
),
|
||||||
|
Text(contact.onion),
|
||||||
|
],
|
||||||
|
))),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: contact.isInvitation != null && contact.isInvitation
|
child: contact.isInvitation != null && contact.isInvitation
|
||||||
|
@ -51,13 +55,13 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
icon: Icon(Icons.favorite, color: Opaque.current().mainTextColor()),
|
icon: Icon(Icons.favorite, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
onPressed: _btnApprove,
|
onPressed: _btnApprove,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
icon: Icon(Icons.delete, color: Opaque.current().mainTextColor()),
|
icon: Icon(Icons.delete, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
onPressed: _btnReject,
|
onPressed: _btnReject,
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
@ -65,10 +69,10 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
? IconButton(
|
? IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
icon: Icon(Icons.block, color: Opaque.current().mainTextColor()),
|
icon: Icon(Icons.block, color: Provider.of<Settings>(context).theme.mainTextColor()),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
)
|
)
|
||||||
: Text(contact.unreadMessages.toString())),
|
: Text(dateToNiceString(contact.lastMessageTime))),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -109,4 +113,11 @@ class _ContactRowState extends State<ContactRow> {
|
||||||
.cwtch
|
.cwtch
|
||||||
.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion);
|
.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String dateToNiceString(DateTime date) {
|
||||||
|
if (date.millisecondsSinceEpoch == 0) {
|
||||||
|
return AppLocalizations.of(context).dateNever;
|
||||||
|
}
|
||||||
|
return DateFormat.yMd().add_jm().format(date.toLocal());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../opaque.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../settings.dart';
|
||||||
|
|
||||||
class MessageBubble extends StatefulWidget {
|
class MessageBubble extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
_MessageBubbleState createState() => _MessageBubbleState();
|
_MessageBubbleState createState() => _MessageBubbleState();
|
||||||
|
@ -21,28 +22,40 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||||
prettyDate = DateFormat.yMd().add_jm().format(Provider.of<MessageState>(context).timestamp);
|
prettyDate = DateFormat.yMd().add_jm().format(Provider.of<MessageState>(context).timestamp);
|
||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: fromMe ? Opaque.current().messageFromMeBackgroundColor() : Opaque.current().messageFromOtherBackgroundColor(),
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(),
|
||||||
border: Border.all(color: fromMe ? Opaque.current().messageFromMeBackgroundColor() : Opaque.current().messageFromOtherBackgroundColor(), width: 1),
|
border: Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(), width: 1),
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(borderRadiousEh),
|
topLeft: Radius.circular(borderRadiousEh),
|
||||||
topRight: Radius.circular(borderRadiousEh),
|
topRight: Radius.circular(borderRadiousEh),
|
||||||
bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
|
bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero,
|
||||||
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
|
bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
child: Padding(padding: EdgeInsets.all(9.0), child:Column(crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [SelectableText(
|
),
|
||||||
Provider.of<MessageState>(context).message,
|
child: Padding(
|
||||||
textAlign: TextAlign.left,
|
padding: EdgeInsets.all(9.0),
|
||||||
),
|
child: Column(crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [
|
||||||
Row(
|
SelectableText(
|
||||||
children: [
|
Provider.of<MessageState>(context).message,
|
||||||
Text(prettyDate, style: TextStyle(fontSize: 9.0), textAlign: fromMe ? TextAlign.right : TextAlign.left),
|
style: TextStyle(
|
||||||
Provider.of<MessageState>(context).ackd
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
|
||||||
? Icon(Icons.check_circle_outline, color: Opaque.current().mainTextColor(), size: 12)
|
),
|
||||||
: Icon(Icons.hourglass_bottom_outlined, color: Opaque.current().mainTextColor(), size: 12)
|
textAlign: TextAlign.left,
|
||||||
],
|
),
|
||||||
)])),
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(prettyDate,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 9.0,
|
||||||
|
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
|
||||||
|
),
|
||||||
|
textAlign: fromMe ? TextAlign.right : TextAlign.left),
|
||||||
|
Provider.of<MessageState>(context).ackd
|
||||||
|
? Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
||||||
|
: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
])),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import 'messagebubble.dart';
|
import '../settings.dart';
|
||||||
import 'messagerow.dart';
|
import 'messagerow.dart';
|
||||||
|
|
||||||
class MessageList extends StatefulWidget {
|
class MessageList extends StatefulWidget {
|
||||||
|
@ -43,22 +43,31 @@ class _MessageListState extends State<MessageList> {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom(false));
|
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom(false));
|
||||||
return Card(
|
return Card(
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
isAlwaysShown: true,
|
isAlwaysShown: true,
|
||||||
controller: ctrlr1,
|
controller: ctrlr1,
|
||||||
child: ListView.builder(
|
child: Container(
|
||||||
controller: ctrlr1,
|
// Only show broken heart is the contact is offline...
|
||||||
itemCount: Provider.of<ContactInfoState>(context).totalMessages,
|
decoration: Provider.of<ContactInfoState>(outerContext).status == "Authenticated"
|
||||||
itemBuilder: (context, index) {
|
? null
|
||||||
return ChangeNotifierProvider(
|
: BoxDecoration(
|
||||||
create: (_) => MessageState(
|
image: DecorationImage(
|
||||||
context: context,
|
fit: BoxFit.contain,
|
||||||
profileOnion: Provider.of<ProfileInfoState>(outerContext).onion,
|
image: AssetImage("assets/core/negative_heart_512px.png"),
|
||||||
contactHandle: Provider.of<ContactInfoState>(outerContext).onion,
|
colorFilter: ColorFilter.mode(Provider.of<Settings>(context).theme.mainTextColor(), BlendMode.srcIn))),
|
||||||
messageIndex: index,
|
child: ListView.builder(
|
||||||
),
|
controller: ctrlr1,
|
||||||
child: MessageRow());
|
itemCount: Provider.of<ContactInfoState>(context).totalMessages,
|
||||||
},
|
itemBuilder: (context, index) {
|
||||||
),
|
return ChangeNotifierProvider(
|
||||||
));
|
create: (_) => MessageState(
|
||||||
|
context: context,
|
||||||
|
profileOnion: Provider.of<ProfileInfoState>(outerContext).onion,
|
||||||
|
contactHandle: Provider.of<ContactInfoState>(outerContext).onion,
|
||||||
|
messageIndex: index,
|
||||||
|
),
|
||||||
|
child: MessageRow());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
import '../model.dart';
|
import '../model.dart';
|
||||||
import '../opaque.dart';
|
|
||||||
import '../settings.dart';
|
import '../settings.dart';
|
||||||
import 'messagebubble.dart';
|
import 'messagebubble.dart';
|
||||||
|
|
||||||
|
@ -20,8 +19,8 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
|
||||||
|
|
||||||
Widget wdgBubble = MessageBubble();
|
Widget wdgBubble = MessageBubble();
|
||||||
Widget wdgIcons = Icon(Icons.delete_forever_outlined, color: Opaque.current().dropShadowColor());
|
Widget wdgIcons = Icon(Icons.delete_forever_outlined, color: Provider.of<Settings>(context).theme.dropShadowColor());
|
||||||
Widget wdgSpacer = Expanded(child:SizedBox(width: 60, height: 10));
|
Widget wdgSpacer = Expanded(child: SizedBox(width: 60, height: 10));
|
||||||
var widgetRow = <Widget>[];
|
var widgetRow = <Widget>[];
|
||||||
|
|
||||||
if (fromMe) {
|
if (fromMe) {
|
||||||
|
@ -36,8 +35,7 @@ class _MessageRowState extends State<MessageRow> {
|
||||||
diameter: 48.0,
|
diameter: 48.0,
|
||||||
imagePath: contact.imagePath,
|
imagePath: contact.imagePath,
|
||||||
maskOut: contact.status != "Authenticated",
|
maskOut: contact.status != "Authenticated",
|
||||||
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()
|
border: contact.status == "Authenticated" ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor());
|
||||||
);
|
|
||||||
|
|
||||||
widgetRow = <Widget>[
|
widgetRow = <Widget>[
|
||||||
wdgPortrait,
|
wdgPortrait,
|
||||||
|
|
|
@ -142,7 +142,7 @@ packages:
|
||||||
name: integration_test
|
name: integration_test
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2+2"
|
version: "1.0.2+3"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -84,7 +84,9 @@ flutter:
|
||||||
|
|
||||||
assets:
|
assets:
|
||||||
- assets/
|
- assets/
|
||||||
|
- assets/core/
|
||||||
- assets/profiles/
|
- assets/profiles/
|
||||||
|
- assets/servers/
|
||||||
|
|
||||||
# To add custom fonts to your application, add a fonts section here,
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
# in this "flutter" section. Each entry in this list should have a
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
|
After Width: | Height: | Size: 6.5 KiB |
|
@ -0,0 +1,72 @@
|
||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility that Flutter provides. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app/opaque.dart';
|
||||||
|
import 'package:flutter_app/settings.dart';
|
||||||
|
import 'package:flutter_app/widgets/cwtchlabel.dart';
|
||||||
|
import 'package:flutter_app/widgets/profileimage.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
var settingsEnglishDark = Settings(Locale("en", ''), Opaque.dark);
|
||||||
|
var settingsEnglishLight = Settings(Locale("en", ''), Opaque.light);
|
||||||
|
ChangeNotifierProvider<Settings> getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark);
|
||||||
|
|
||||||
|
String file(String slug) {
|
||||||
|
return "profileimage_" + slug + ".png";
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
testWidgets('ProfileImage widget test', (WidgetTester tester) async {
|
||||||
|
tester.binding.window.physicalSizeTestValue = Size(200, 200);
|
||||||
|
// await tester.pumpWidget(MultiProvider(
|
||||||
|
// providers:[getSettingsEnglishDark()],
|
||||||
|
// child: Directionality(textDirection: TextDirection.ltr, child: CwtchLabel(label: testingStr))
|
||||||
|
// ));
|
||||||
|
|
||||||
|
Widget testWidget = ProfileImage(
|
||||||
|
imagePath: "profiles/001-centaur.png",
|
||||||
|
badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor(),
|
||||||
|
badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor(),
|
||||||
|
maskOut: false,
|
||||||
|
border: settingsEnglishDark.theme.portraitOfflineBorderColor(),
|
||||||
|
diameter: 64.0,
|
||||||
|
badgeCount: 10,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget testHarness = MultiProvider(
|
||||||
|
providers:[getSettingsEnglishDark()],
|
||||||
|
builder: (context, child) { return MaterialApp(
|
||||||
|
locale: Provider.of<Settings>(context).locale,
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
title: 'Test',
|
||||||
|
theme: mkThemeData(Provider.of<Settings>(context)),
|
||||||
|
home: Card(child: testWidget),
|
||||||
|
);}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
//expect(find.text(testingStr), findsOneWidget);
|
||||||
|
//expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
await tester.pumpWidget(testHarness);
|
||||||
|
await expectLater(find.byWidget(testHarness), matchesGoldenFile(file('init')));
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
// await tester.tap(find.byIcon(Icons.add));
|
||||||
|
// await tester.pump();
|
||||||
|
//
|
||||||
|
// // Verify that our counter has incremented.
|
||||||
|
// expect(find.text('0'), findsNothing);
|
||||||
|
// expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|