Merge branch 'trunk' into tests
continuous-integration/drone/pr Build is failing
Details
continuous-integration/drone/pr Build is failing
Details
This commit is contained in:
commit
f101874ac2
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: fetch
|
||||
image: cirrusci/flutter:dev
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
commands:
|
||||
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor
|
||||
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/torrc
|
||||
- chmod a+x tor
|
||||
- git fetch --tags
|
||||
- echo `git describe --tags` > VERSION
|
||||
- echo `date +%G-%m-%d-%H-%M` > BUILDDATE
|
||||
- flutter pub get
|
||||
- mkdir deploy
|
||||
|
||||
#- name: quality
|
||||
# image: golang
|
||||
# volumes:
|
||||
# - name: deps
|
||||
# path: /go
|
||||
# commands:
|
||||
# - go list ./... | xargs go vet
|
||||
# - go list ./... | xargs golint
|
||||
# #Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting
|
||||
|
||||
- name: build-linux
|
||||
image: cirrusci/flutter:dev
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
commands:
|
||||
- flutter config --enable-linux-desktop
|
||||
- apt-get update
|
||||
- apt-get install -y --no-install-recommends cmake ninja-build clang build-essential pkg-config libgtk-3-dev liblzma-dev
|
||||
- flutter build linux
|
||||
- mkdir deploy/linux
|
||||
- cp -r build/linux/x64/release/bundle/* deploy/linux
|
||||
- cp /sdks/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat deploy/linux
|
||||
|
||||
- name: build-android
|
||||
image: cirrusci/flutter:dev
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /root/.pub-cache
|
||||
commands:
|
||||
- flutter build appbundle
|
||||
# or build apk --split-per-abi ?
|
||||
- mkdir deploy/android
|
||||
- cp build/app/outputs/bundle/release/app-release.aab deploy/android
|
||||
|
||||
# Todo: gonna need more work on container
|
||||
# https://flutter.dev/desktop
|
||||
# requirements: Visual Studio 2019 (not to be confused with Visual Studio Code) with the “Desktop development with C++” workload installed, including all of its default components
|
||||
#- name: build-windows
|
||||
# image: cirrusci/flutter:dev
|
||||
#- volumes:
|
||||
# - name: deps
|
||||
# path: /root/.pub-cache
|
||||
# commands:
|
||||
# - flutter config --enable-windows-desktop
|
||||
# - flutter build windows
|
||||
|
||||
- name: deploy-buildfiles
|
||||
image: kroniak/ssh-client
|
||||
environment:
|
||||
BUILDFILES_KEY:
|
||||
from_secret: buildfiles_key
|
||||
secrets: [gogs_account_token]
|
||||
when:
|
||||
event: push
|
||||
status: [ success ]
|
||||
commands:
|
||||
- echo $BUILDFILES_KEY > ~/id_rsab64
|
||||
- base64 -d ~/id_rsab64 > ~/id_rsa
|
||||
- chmod 400 ~/id_rsa
|
||||
- export DIR=flwtch-`cat VERSION`-`cat BUILDDATE`
|
||||
- mv deploy $DIR
|
||||
- cd $DIR
|
||||
- find . -type f -exec sha256sum {} \; > ./../sha256s.txt
|
||||
- mv ./../sha256s.txt .
|
||||
- cd ..
|
||||
# TODO: do deployment once files actaully compile
|
||||
- scp -r -o StrictHostKeyChecking=no -i ~/id_rsa $DIR buildfiles@openprivacy.ca:/home/buildfiles/buildfiles/
|
||||
|
||||
- name: notify-email
|
||||
image: drillster/drone-email
|
||||
host: build.openprivacy.ca
|
||||
port: 25
|
||||
skip_verify: true
|
||||
from: drone@openprivacy.ca
|
||||
when:
|
||||
status: [ failure ]
|
||||
|
||||
- name: notify-gogs
|
||||
image: openpriv/drone-gogs
|
||||
when:
|
||||
event: pull_request
|
||||
status: [ success, changed, failure ]
|
||||
environment:
|
||||
GOGS_ACCOUNT_TOKEN:
|
||||
from_secret: gogs_account_token
|
||||
gogs_url: https://git.openprivacy.ca
|
||||
|
||||
volumes:
|
||||
- name: deps
|
||||
temp: {}
|
||||
|
||||
trigger:
|
||||
repo: flutter/flutter_app
|
||||
branch: trunk
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import '../errorHandler.dart';
|
||||
import '../model.dart';
|
||||
import '../settings.dart';
|
||||
|
||||
|
@ -8,10 +9,12 @@ import '../settings.dart';
|
|||
class CwtchNotifier {
|
||||
ProfileListState profileCN;
|
||||
Settings settings;
|
||||
ErrorHandler error;
|
||||
|
||||
CwtchNotifier(ProfileListState pcn, Settings settingsCN) {
|
||||
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN) {
|
||||
profileCN = pcn;
|
||||
settings = settingsCN;
|
||||
error = errorCN;
|
||||
}
|
||||
|
||||
void handleMessage(String type, dynamic data) {
|
||||
|
@ -25,12 +28,13 @@ class CwtchNotifier {
|
|||
));
|
||||
break;
|
||||
case "PeerCreated":
|
||||
print("xx peercreated");
|
||||
print("xx peercreated $data");
|
||||
profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState(
|
||||
profileOnion: data["ProfileOnion"],
|
||||
onion: data["RemotePeer"],
|
||||
nickname: data["nick"],
|
||||
status: data["status"],
|
||||
imagePath: data["picture"],
|
||||
));
|
||||
break;
|
||||
case "PeerStateChange":
|
||||
|
@ -44,6 +48,10 @@ class CwtchNotifier {
|
|||
contact.status = data["ConnectionState"];
|
||||
}
|
||||
break;
|
||||
case "AppError":
|
||||
print("New App Error: $data");
|
||||
error.handleUpdate(data["Data"]);
|
||||
break;
|
||||
case "UpdateGlobalSettings":
|
||||
settings.handleUpdate(jsonDecode(data["Data"]));
|
||||
break;
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:path/path.dart' as path;
|
|||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter_app/cwtch/cwtch.dart';
|
||||
|
||||
|
||||
/////////////////////
|
||||
/// Cwtch API ///
|
||||
/////////////////////
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class ErrorHandler extends ChangeNotifier {
|
||||
// General Error Types
|
||||
static const String successErrorType = "success";
|
||||
|
||||
// Add Contact Specific Errors...
|
||||
static const String addContactErrorPrefix = "addcontact";
|
||||
static const String invalidImportStringErrorType = "invalid_import_string";
|
||||
static const String contactAlreadyExistsErrorType = "contact_already_exists";
|
||||
bool invalidImportStringError = false;
|
||||
bool contactAlreadyExistsError = false;
|
||||
bool explicitAddContactSuccess = false;
|
||||
|
||||
/// Called by the event bus.
|
||||
handleUpdate(String error) {
|
||||
var parts = error.split(".");
|
||||
String prefix = parts[0];
|
||||
String errorType = parts[1];
|
||||
|
||||
switch (prefix) {
|
||||
case addContactErrorPrefix:
|
||||
handleAddContactError(errorType);
|
||||
break;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
handleAddContactError(String errorType) {
|
||||
// Reset add contact errors
|
||||
invalidImportStringError = false;
|
||||
contactAlreadyExistsError = false;
|
||||
explicitAddContactSuccess = false;
|
||||
|
||||
switch (errorType) {
|
||||
case invalidImportStringErrorType:
|
||||
invalidImportStringError = true;
|
||||
break;
|
||||
case contactAlreadyExistsErrorType:
|
||||
contactAlreadyExistsError = true;
|
||||
break;
|
||||
case successErrorType:
|
||||
explicitAddContactSuccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "Aufgebaut auf: %2",
|
||||
"bulletinsBtn": "Meldungen",
|
||||
"chatBtn": "Chat",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "in die Zwischenablage kopiert",
|
||||
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "Adresse",
|
||||
"groupName": "Gruppenname",
|
||||
"groupNameLabel": "Gruppenname",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Einladung",
|
||||
"invitationLabel": "Einladung",
|
||||
"inviteBtn": "Einladen",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "Built on: %2",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"chatBtn": "Chat",
|
||||
"contactAlreadyExists": "Contact Already Exists",
|
||||
"conversationSettings": "Conversation Settings",
|
||||
"copiedClipboardNotification": "Copied to clipboard",
|
||||
"copiedToClipboardNotification": "Copied to Clipboard",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "Address",
|
||||
"groupName": "Group name",
|
||||
"groupNameLabel": "Group Name",
|
||||
"invalidImportString": "Invalid import string",
|
||||
"invitation": "Invitation",
|
||||
"invitationLabel": "Invitation",
|
||||
"inviteBtn": "Invite",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "Basado en: %2",
|
||||
"bulletinsBtn": "Boletines",
|
||||
"chatBtn": "Chat",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiado al portapapeles",
|
||||
"copiedToClipboardNotification": "Copiado al portapapeles",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "Dirección",
|
||||
"groupName": "Nombre del grupo",
|
||||
"groupNameLabel": "Nombre del grupo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Invitación",
|
||||
"invitationLabel": "Invitación",
|
||||
"inviteBtn": "Invitar",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "",
|
||||
"bulletinsBtn": "Bulletins",
|
||||
"chatBtn": "Discuter",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copié dans le presse-papier",
|
||||
"copiedToClipboardNotification": "Copié dans le presse-papier",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "",
|
||||
"groupName": "",
|
||||
"groupNameLabel": "Nom du groupe",
|
||||
"invalidImportString": "",
|
||||
"invitation": "",
|
||||
"invitationLabel": "Invitation",
|
||||
"inviteBtn": "Invitation",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "Costruito il: %2",
|
||||
"bulletinsBtn": "Bollettini",
|
||||
"chatBtn": "Chat",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiato negli Appunti",
|
||||
"copiedToClipboardNotification": "Copiato negli Appunti",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "Indirizzo",
|
||||
"groupName": "Nome del gruppo",
|
||||
"groupNameLabel": "Nome del gruppo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "Invito",
|
||||
"invitationLabel": "Invito",
|
||||
"inviteBtn": "Invitare",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"builddate": "",
|
||||
"bulletinsBtn": "Boletins",
|
||||
"chatBtn": "Chat",
|
||||
"contactAlreadyExists": "",
|
||||
"conversationSettings": "",
|
||||
"copiedClipboardNotification": "Copiado",
|
||||
"copiedToClipboardNotification": "Copiado",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"groupAddr": "",
|
||||
"groupName": "",
|
||||
"groupNameLabel": "Nome do Grupo",
|
||||
"invalidImportString": "",
|
||||
"invitation": "",
|
||||
"invitationLabel": "Convite",
|
||||
"inviteBtn": "Convidar",
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter_app/cwtch/ffi.dart';
|
||||
import 'package:flutter_app/cwtch/gomobile.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/errorHandler.dart';
|
||||
import 'package:flutter_app/settings.dart';
|
||||
import 'package:flutter_app/views/triplecolview.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -16,6 +17,7 @@ import 'opaque.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
var globalSettings = Settings(Locale("en", ''), Opaque.dark);
|
||||
var globalErrorHandler = ErrorHandler();
|
||||
|
||||
void main() {
|
||||
LicenseRegistry.addLicense(() => licenses());
|
||||
|
@ -46,7 +48,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
cwtchInit = false;
|
||||
|
||||
profs = ProfileListState();
|
||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings);
|
||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler);
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
cwtch = CwtchGomobile(cwtchNotifier);
|
||||
|
@ -63,6 +65,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
appStatus = AppModel(cwtch: cwtch);
|
||||
}
|
||||
|
||||
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
|
||||
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
|
||||
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
|
||||
ChangeNotifierProvider<ProfileListState> getProfileListProvider() => ChangeNotifierProvider(create: (context) => profs);
|
||||
|
@ -72,7 +75,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
//appStatus = AppModel(cwtch: cwtch);
|
||||
|
||||
return MultiProvider(
|
||||
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider()],
|
||||
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider(), getErrorHandlerProvider()],
|
||||
builder: (context, widget) {
|
||||
Provider.of<Settings>(context).initPackageInfo();
|
||||
return Consumer<Settings>(
|
||||
|
|
|
@ -192,7 +192,19 @@ class ContactInfoState extends ChangeNotifier {
|
|||
int _unreadMessages = 0;
|
||||
int _totalMessages = 0;
|
||||
|
||||
ContactInfoState({this.profileOnion, this.onion, nickname = "", isGroup = false, isInvitation = false, isBlocked = false, status = "", imagePath = "", savePeerHistory = "DeleteHistoryConfirmed", numMessages = 0, numUnread = 0,}) {
|
||||
ContactInfoState({
|
||||
this.profileOnion,
|
||||
this.onion,
|
||||
nickname = "",
|
||||
isGroup = false,
|
||||
isInvitation = false,
|
||||
isBlocked = false,
|
||||
status = "",
|
||||
imagePath = "",
|
||||
savePeerHistory = "DeleteHistoryConfirmed",
|
||||
numMessages = 0,
|
||||
numUnread = 0,
|
||||
}) {
|
||||
this._nickname = nickname;
|
||||
this._isGroup = isGroup;
|
||||
this._isInvitation = isInvitation;
|
||||
|
|
|
@ -7,6 +7,8 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||
|
||||
import 'opaque.dart';
|
||||
|
||||
const TapirGroupsExperiment = "tapir-groups-experiment";
|
||||
|
||||
/// Settings govern the *Globally* relevant settings like Locale, Theme and Experiments.
|
||||
/// We also provide access to the version information here as it is also accessed from the
|
||||
/// Settings Pane.
|
||||
|
|
|
@ -1,12 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/errorHandler.dart';
|
||||
import 'package:flutter_app/settings.dart';
|
||||
import 'package:flutter_app/widgets/buttontextfield.dart';
|
||||
import 'package:flutter_app/widgets/cwtchlabel.dart';
|
||||
import 'package:flutter_app/widgets/textfield.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../main.dart';
|
||||
import '../model.dart';
|
||||
|
||||
/// Add Contact View is the one-stop shop for adding public keys to a Profiles contact list.
|
||||
/// We support both Peers and Groups (experiment-pending).
|
||||
/// NOTE: This view makes use of the global Error Handler to receive events from the Cwtch Library (for validating
|
||||
/// error states caused by incorrect import string or duplicate requests to add a specific contact)
|
||||
class AddContactView extends StatefulWidget {
|
||||
@override
|
||||
_AddContactViewState createState() => _AddContactViewState();
|
||||
}
|
||||
|
||||
class _AddContactViewState extends State<AddContactView> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final ctrlrOnion = TextEditingController(text: "");
|
||||
final ctrlrContact = TextEditingController(text: "");
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -18,16 +39,119 @@ class _AddContactViewState extends State<AddContactView> {
|
|||
}
|
||||
|
||||
Widget _buildForm() {
|
||||
return Center(
|
||||
child: Wrap(
|
||||
direction: Axis.vertical,
|
||||
spacing: 20.0,
|
||||
runSpacing: 20.0,
|
||||
children: <Widget>[
|
||||
Text(AppLocalizations.of(context).profileName),
|
||||
Text("peer handle or group invite or server bundle"), //todo
|
||||
Text(AppLocalizations.of(context).createGroupBtn),
|
||||
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
|
||||
/// We display a different number of tabs dependening on the experiment setup
|
||||
bool groupsEnabled = Provider.of<Settings>(context).experimentsEnabled && Provider.of<Settings>(context).experiments[TapirGroupsExperiment];
|
||||
return Consumer<ErrorHandler>(builder: (context, globalErrorHandler, child) {
|
||||
return DefaultTabController(
|
||||
length: groupsEnabled ? 3 : 1,
|
||||
child: Column(children: [
|
||||
(groupsEnabled ? getTabBarWithGroups() : getTabBarWithAddPeerOnly()),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: (groupsEnabled ? [addPeerTab(), addGroupTab(), joinGroupTab()] : [addPeerTab()]),
|
||||
)),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
void _copyOnion() {
|
||||
Clipboard.setData(new ClipboardData(text: Provider.of<ProfileInfoState>(context, listen: false).onion));
|
||||
// TODO Toast
|
||||
}
|
||||
|
||||
/// A Tab Bar with only the Add Peer Tab
|
||||
TabBar getTabBarWithAddPeerOnly() {
|
||||
return TabBar(
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: Icon(Icons.person_add_rounded),
|
||||
text: AppLocalizations.of(context).addPeer,
|
||||
),
|
||||
],
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
/// The full tab bar with Join and Add Groups
|
||||
TabBar getTabBarWithGroups() {
|
||||
return TabBar(
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: Icon(Icons.person_add_rounded),
|
||||
text: AppLocalizations.of(context).addPeer,
|
||||
),
|
||||
Tab(icon: Icon(Icons.group), text: AppLocalizations.of(context).createGroup),
|
||||
Tab(icon: Icon(Icons.group_add), text: AppLocalizations.of(context).joinGroup),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// The Add Peer Tab allows a peer to add a specific non-group peer to their contact lists
|
||||
/// We also provide a convenient way to copy their onion.
|
||||
Widget addPeerTab() {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(30),
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Form(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
key: _formKey,
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
CwtchLabel(label: AppLocalizations.of(context).profileOnionLabel),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
CwtchButtonTextField(
|
||||
controller: ctrlrOnion,
|
||||
onPressed: _copyOnion,
|
||||
icon: Icon(Icons.copy),
|
||||
tooltip: AppLocalizations.of(context).copyBtn,
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
CwtchLabel(label: AppLocalizations.of(context).pasteAddressToAddContact),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
CwtchTextField(
|
||||
controller: ctrlrContact,
|
||||
validator: (value) {
|
||||
if (value == "") {
|
||||
return null;
|
||||
} if (globalErrorHandler.invalidImportStringError) {
|
||||
return AppLocalizations.of(context).invalidImportString;
|
||||
} else if (globalErrorHandler.contactAlreadyExistsError) {
|
||||
return AppLocalizations.of(context).contactAlreadyExists;
|
||||
} else if (globalErrorHandler.explicitAddContactSuccess) {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: (String peerAddr) async {
|
||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
final setPeerAttribute = {
|
||||
"EventType": "AddContact",
|
||||
"Data": {"ImportString": peerAddr},
|
||||
};
|
||||
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
if (globalErrorHandler.explicitAddContactSuccess) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
])));
|
||||
}
|
||||
|
||||
/// TODO Add Group Pane
|
||||
Widget addGroupTab() {
|
||||
return Icon(Icons.group_add);
|
||||
}
|
||||
|
||||
/// TODO Join Group Pane
|
||||
Widget joinGroupTab() {
|
||||
return Icon(Icons.group);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/widgets/contactrow.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../errorHandler.dart';
|
||||
import '../main.dart';
|
||||
import 'addcontactview.dart';
|
||||
import '../model.dart';
|
||||
|
@ -48,9 +49,11 @@ class _ContactsViewState extends State<ContactsView> {
|
|||
|
||||
void _pushAddContact() {
|
||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) {
|
||||
return Provider(
|
||||
create: (_) => Provider.of<FlwtchState>(context),
|
||||
builder: (BuildContext bcontext) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: Provider.of<ProfileInfoState>(context)),
|
||||
],
|
||||
child: AddContactView(),
|
||||
);
|
||||
},
|
||||
|
|
|
@ -94,12 +94,12 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
|
|||
children: [
|
||||
SwitchListTile(
|
||||
title: Text(AppLocalizations.of(context).enableGroups, style: TextStyle(color: settings.current().mainTextColor())),
|
||||
value: settings.experiments.containsKey("tapir-groups-experiment") && settings.experiments["tapir-groups-experiment"],
|
||||
value: settings.experiments.containsKey(TapirGroupsExperiment) && settings.experiments[TapirGroupsExperiment],
|
||||
onChanged: (bool value) {
|
||||
if (value) {
|
||||
settings.enableExperiment("tapir-groups-experiment");
|
||||
settings.enableExperiment(TapirGroupsExperiment);
|
||||
} else {
|
||||
settings.disableExperiment("tapir-groups-experiment");
|
||||
settings.disableExperiment(TapirGroupsExperiment);
|
||||
}
|
||||
// Save Settings...
|
||||
saveSettings(context);
|
||||
|
|
|
@ -81,8 +81,18 @@ class _MessageViewState extends State<MessageView> {
|
|||
onPressed: _sendMessage,
|
||||
),
|
||||
Row(children: <Widget>[
|
||||
SizedBox(width: 45, child: ElevatedButton(child: Icon(Icons.emoji_emotions_outlined, color: Opaque.current().mainTextColor()), onPressed: placeHolder,)),
|
||||
SizedBox(width: 45, child: ElevatedButton(child: Icon(Icons.attach_file, color: Opaque.current().mainTextColor()), onPressed: placeHolder,)),
|
||||
SizedBox(
|
||||
width: 45,
|
||||
child: ElevatedButton(
|
||||
child: Icon(Icons.emoji_emotions_outlined, color: Opaque.current().mainTextColor()),
|
||||
onPressed: placeHolder,
|
||||
)),
|
||||
SizedBox(
|
||||
width: 45,
|
||||
child: ElevatedButton(
|
||||
child: Icon(Icons.attach_file, color: Opaque.current().mainTextColor()),
|
||||
onPressed: placeHolder,
|
||||
)),
|
||||
])
|
||||
]),
|
||||
),
|
||||
|
|
|
@ -23,4 +23,4 @@ class _MessageListState extends State<MessageList> {
|
|||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@ import 'package:flutter/material.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import '../settings.dart';
|
||||
|
||||
doNothing(String x) {}
|
||||
|
||||
// Provides a styled Text Field for use in Form Widgets.
|
||||
// Callers must provide a text controller, label helper text and a validator.
|
||||
class CwtchTextField extends StatefulWidget {
|
||||
CwtchTextField({this.controller, this.labelText, this.validator});
|
||||
CwtchTextField({this.controller, this.labelText, this.validator, this.onChanged = doNothing});
|
||||
final TextEditingController controller;
|
||||
final String labelText;
|
||||
final FormFieldValidator validator;
|
||||
final Function(String) onChanged;
|
||||
|
||||
@override
|
||||
_CwtchTextFieldState createState() => _CwtchTextFieldState();
|
||||
|
@ -21,6 +24,7 @@ class _CwtchTextFieldState extends State<CwtchTextField> {
|
|||
return TextFormField(
|
||||
controller: widget.controller,
|
||||
validator: widget.validator,
|
||||
onChanged: widget.onChanged,
|
||||
decoration: InputDecoration(
|
||||
labelText: widget.labelText,
|
||||
labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()),
|
||||
|
|
Loading…
Reference in New Issue