profile level server list and editor start
This commit is contained in:
parent
e31b593e79
commit
ae28cc5e5d
|
@ -118,6 +118,7 @@ class ProfileListState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactListState extends ChangeNotifier {
|
class ContactListState extends ChangeNotifier {
|
||||||
|
ProfileServerListState? servers;
|
||||||
List<ContactInfoState> _contacts = [];
|
List<ContactInfoState> _contacts = [];
|
||||||
String _filter = "";
|
String _filter = "";
|
||||||
int get num => _contacts.length;
|
int get num => _contacts.length;
|
||||||
|
@ -129,18 +130,36 @@ class ContactListState extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void connectServers(ProfileServerListState servers) {
|
||||||
|
this.servers = servers;
|
||||||
|
}
|
||||||
|
|
||||||
List<ContactInfoState> filteredList() {
|
List<ContactInfoState> filteredList() {
|
||||||
if (!isFiltered) return contacts;
|
if (!isFiltered) return contacts;
|
||||||
return _contacts.where((ContactInfoState c) => c.onion.toLowerCase().startsWith(_filter) || (c.nickname.toLowerCase().contains(_filter))).toList();
|
return _contacts.where((ContactInfoState c) => c.onion.toLowerCase().startsWith(_filter) || (c.nickname.toLowerCase().contains(_filter))).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAll(Iterable<ContactInfoState> newContacts) {
|
void addAll(Iterable<ContactInfoState> newContacts) {
|
||||||
|
print("****** contactListState.addAll()... *********");
|
||||||
_contacts.addAll(newContacts);
|
_contacts.addAll(newContacts);
|
||||||
|
servers?.clearGroups();
|
||||||
|
print("contact len: ${_contacts.length}");
|
||||||
|
_contacts.forEach((contact) {
|
||||||
|
//print("looking at contact ${contact.onion} (${contact.isGroup})...");
|
||||||
|
if (contact.isGroup) {
|
||||||
|
print("contactList adding group ${contact.onion} to ${contact.server}");
|
||||||
|
servers?.addGroup(contact);
|
||||||
|
}
|
||||||
|
});
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(ContactInfoState newContact) {
|
void add(ContactInfoState newContact) {
|
||||||
_contacts.add(newContact);
|
_contacts.add(newContact);
|
||||||
|
if (newContact.isGroup) {
|
||||||
|
print("contactList adding group ${newContact.onion} to ${newContact.server}");
|
||||||
|
servers?.addGroup(newContact);
|
||||||
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,8 +225,8 @@ class ContactListState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProfileInfoState extends ChangeNotifier {
|
class ProfileInfoState extends ChangeNotifier {
|
||||||
ContactListState _contacts = ContactListState();
|
|
||||||
ProfileServerListState _servers = ProfileServerListState();
|
ProfileServerListState _servers = ProfileServerListState();
|
||||||
|
ContactListState _contacts = ContactListState();
|
||||||
final String onion;
|
final String onion;
|
||||||
String _nickname = "";
|
String _nickname = "";
|
||||||
String _imagePath = "";
|
String _imagePath = "";
|
||||||
|
@ -235,7 +254,11 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
this._online = online;
|
this._online = online;
|
||||||
this._encrypted = encrypted;
|
this._encrypted = encrypted;
|
||||||
|
|
||||||
|
_contacts.connectServers(this._servers);
|
||||||
|
|
||||||
if (contactsJson != null && contactsJson != "" && contactsJson != "null") {
|
if (contactsJson != null && contactsJson != "" && contactsJson != "null") {
|
||||||
|
this.replaceServers(serversJson);
|
||||||
|
|
||||||
List<dynamic> contacts = jsonDecode(contactsJson);
|
List<dynamic> contacts = jsonDecode(contactsJson);
|
||||||
this._contacts.addAll(contacts.map((contact) {
|
this._contacts.addAll(contacts.map((contact) {
|
||||||
return ContactInfoState(this.onion, contact["onion"],
|
return ContactInfoState(this.onion, contact["onion"],
|
||||||
|
@ -258,7 +281,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.replaceServers(serversJson);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse out the server list json into our server info state struct...
|
// Parse out the server list json into our server info state struct...
|
||||||
|
@ -267,7 +290,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
List<dynamic> servers = jsonDecode(serversJson);
|
List<dynamic> servers = jsonDecode(serversJson);
|
||||||
this._servers.replace(servers.map((server) {
|
this._servers.replace(servers.map((server) {
|
||||||
// TODO Keys...
|
// TODO Keys...
|
||||||
return RemoteServerInfoState(onion: server["onion"], status: server["status"]);
|
return RemoteServerInfoState(onion: server["onion"], description: server["description"], status: server["status"]);
|
||||||
}));
|
}));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
@ -275,7 +298,7 @@ class ProfileInfoState extends ChangeNotifier {
|
||||||
|
|
||||||
//
|
//
|
||||||
void updateServerStatusCache(String server, String status) {
|
void updateServerStatusCache(String server, String status) {
|
||||||
this._servers.updateServerCache(server, status);
|
this._servers.updateServerState(server, status);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cwtch/model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ProfileServerListState extends ChangeNotifier {
|
class ProfileServerListState extends ChangeNotifier {
|
||||||
|
@ -6,6 +7,7 @@ class ProfileServerListState extends ChangeNotifier {
|
||||||
void replace(Iterable<RemoteServerInfoState> newServers) {
|
void replace(Iterable<RemoteServerInfoState> newServers) {
|
||||||
_servers.clear();
|
_servers.clear();
|
||||||
_servers.addAll(newServers);
|
_servers.addAll(newServers);
|
||||||
|
resort();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,16 +16,43 @@ class ProfileServerListState extends ChangeNotifier {
|
||||||
return idx >= 0 ? _servers[idx] : null;
|
return idx >= 0 ? _servers[idx] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateServerCache(String onion, String description, String status) {
|
void updateServerState(String onion, String status) {
|
||||||
int idx = _servers.indexWhere((element) => element.onion == onion);
|
int idx = _servers.indexWhere((element) => element.onion == onion);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
_servers[idx] = RemoteServerInfoState(onion: onion, description: description, status: status);
|
_servers[idx] = RemoteServerInfoState(onion: onion, description: _servers[idx].description, status: status);
|
||||||
} else {
|
} else {
|
||||||
print("Tried to update server cache without a starting state...this is probably an error");
|
print("Tried to update server cache without a starting state...this is probably an error");
|
||||||
}
|
}
|
||||||
|
resort();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resort() {
|
||||||
|
_servers.sort((RemoteServerInfoState a, RemoteServerInfoState b) {
|
||||||
|
// return -1 = a first in list
|
||||||
|
// return 1 = b first in list
|
||||||
|
if (a.status == "Synced" && b.status != "Synced") {
|
||||||
|
return -1;
|
||||||
|
} else if (a.status != "Synced" && b.status == "Synced") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearGroups() {
|
||||||
|
_servers.map((server) => server.clearGroups());
|
||||||
|
}
|
||||||
|
|
||||||
|
void addGroup(ContactInfoState group) {
|
||||||
|
print("serverList adding group ${group.onion} to ${group.server}");
|
||||||
|
|
||||||
|
int idx = _servers.indexWhere((element) => element.onion == group.server);
|
||||||
|
if (idx >= 0) {
|
||||||
|
_servers[idx].addGroup(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<RemoteServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
List<RemoteServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +60,32 @@ class ProfileServerListState extends ChangeNotifier {
|
||||||
class RemoteServerInfoState extends ChangeNotifier {
|
class RemoteServerInfoState extends ChangeNotifier {
|
||||||
final String onion;
|
final String onion;
|
||||||
final String status;
|
final String status;
|
||||||
final String description;
|
String description;
|
||||||
|
List<ContactInfoState> _groups = [];
|
||||||
|
|
||||||
RemoteServerInfoState({required this.onion, required this.description, required this.status});
|
RemoteServerInfoState({required this.onion, required this.description, required this.status});
|
||||||
|
|
||||||
|
void updateDescription(String newDescription) {
|
||||||
|
this.description = newDescription;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearGroups() {
|
||||||
|
print("Server CLEARING group");
|
||||||
|
description = "cleared groups";
|
||||||
|
_groups = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
void addGroup(ContactInfoState group) {
|
||||||
|
print("server $onion adding group ${group.onion}");
|
||||||
|
_groups.add(group);
|
||||||
|
print("now has ${_groups.length}");
|
||||||
|
description = "i have ${_groups.length} groups";
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
int get groupsLen => _groups.length;
|
||||||
|
|
||||||
|
List<ContactInfoState> get groups => _groups.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ class _AddEditServerViewState extends State<AddEditServerView> {
|
||||||
),
|
),
|
||||||
CwtchTextField(
|
CwtchTextField(
|
||||||
controller: ctrlrDesc,
|
controller: ctrlrDesc,
|
||||||
labelText: "Description",
|
labelText: "Description", // TODO localize
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cwtch/cwtch_icons_icons.dart';
|
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||||
|
import 'package:cwtch/views/profileserversview.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cwtch/views/torstatusview.dart';
|
import 'package:cwtch/views/torstatusview.dart';
|
||||||
import 'package:cwtch/widgets/contactrow.dart';
|
import 'package:cwtch/widgets/contactrow.dart';
|
||||||
|
@ -171,10 +172,11 @@ class _ContactsViewState extends State<ContactsView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pushServers() {
|
void _pushServers() {
|
||||||
|
var profile = Provider.of<ProfileInfoState>(context);
|
||||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [Provider.value(value: Provider.of<FlwtchState>(context))],
|
providers: [ChangeNotifierProvider(create: (context) => profile.serverList), Provider.value(value: Provider.of<FlwtchState>(context))],
|
||||||
child: ProfileServersView(),
|
child: ProfileServersView(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileServersView extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_ProfileServersView createState() => _ProfileServersView();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProfileServersView extends State<ProfileServersView> {
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text( MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.serversManagerTitleLong : AppLocalizations.of(context)!.serversManagerTitleShort),
|
|
||||||
//actions: getActions(),
|
|
||||||
),
|
|
||||||
body: Consumer<ServerListState>(
|
|
||||||
builder: (context, svrs, child) {
|
|
||||||
final tiles = svrs.servers.map((ServerInfoState server) {
|
|
||||||
return ChangeNotifierProvider<ServerInfoState>.value(
|
|
||||||
value: server,
|
|
||||||
builder: (context, child) => RepaintBoundary(child: ServerRow()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
final divided = ListTile.divideTiles(
|
|
||||||
context: context,
|
|
||||||
tiles: tiles,
|
|
||||||
).toList();
|
|
||||||
|
|
||||||
if (tiles.isEmpty) {
|
|
||||||
return Center(
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.unlockServerTip,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListView(children: divided);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:cwtch/models/profileservers.dart';
|
||||||
|
import 'package:cwtch/models/servers.dart';
|
||||||
|
import 'package:cwtch/widgets/remoteserverrow.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../model.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class ProfileServersView extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_ProfileServersView createState() => _ProfileServersView();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProfileServersView extends State<ProfileServersView> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.size
|
||||||
|
.width > 600 ? AppLocalizations.of(context)!.serversManagerTitleLong : AppLocalizations.of(context)!.serversManagerTitleShort),
|
||||||
|
//actions: getActions(),
|
||||||
|
),
|
||||||
|
body: Consumer<ProfileServerListState>(
|
||||||
|
builder: (context, servers, child) {
|
||||||
|
final tiles = servers.servers.map((RemoteServerInfoState server) {
|
||||||
|
return ChangeNotifierProvider<RemoteServerInfoState>.value(
|
||||||
|
value: server,
|
||||||
|
builder: (context, child) => RepaintBoundary(child: RemoteServerRow()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final divided = ListTile.divideTiles(
|
||||||
|
context: context,
|
||||||
|
tiles: tiles,
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
// TODO: add import row from global servers
|
||||||
|
divided.insert(0, Row( children: [Text("Import server from global list if any")]));
|
||||||
|
|
||||||
|
return ListView(children: divided);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:cwtch/cwtch/cwtch.dart';
|
||||||
|
import 'package:cwtch/cwtch_icons_icons.dart';
|
||||||
|
import 'package:cwtch/models/profileservers.dart';
|
||||||
|
import 'package:cwtch/models/servers.dart';
|
||||||
|
import 'package:cwtch/widgets/buttontextfield.dart';
|
||||||
|
import 'package:cwtch/widgets/contactrow.dart';
|
||||||
|
import 'package:cwtch/widgets/cwtchlabel.dart';
|
||||||
|
import 'package:cwtch/widgets/passwordfield.dart';
|
||||||
|
import 'package:cwtch/widgets/textfield.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cwtch/settings.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import '../errorHandler.dart';
|
||||||
|
import '../main.dart';
|
||||||
|
import '../config.dart';
|
||||||
|
import '../model.dart';
|
||||||
|
|
||||||
|
/// Pane to add or edit a server
|
||||||
|
class RemoteServerView extends StatefulWidget {
|
||||||
|
const RemoteServerView();
|
||||||
|
|
||||||
|
@override
|
||||||
|
_RemoteServerViewState createState() => _RemoteServerViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RemoteServerViewState extends State<RemoteServerView> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final ctrlrDesc = TextEditingController(text: "");
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
var serverInfoState = Provider.of<RemoteServerInfoState>(context, listen: false);
|
||||||
|
if (serverInfoState.description.isNotEmpty) {
|
||||||
|
ctrlrDesc.text = serverInfoState.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer2<RemoteServerInfoState, Settings>(builder: (context, serverInfoState, settings, child) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion)
|
||||||
|
),
|
||||||
|
body: LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
|
||||||
|
return Scrollbar(
|
||||||
|
isAlwaysShown: true,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: viewportConstraints.maxHeight,
|
||||||
|
),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.fromLTRB(30, 0, 30, 10),
|
||||||
|
padding: EdgeInsets.fromLTRB(20, 0, 20, 10),
|
||||||
|
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
|
||||||
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
CwtchLabel(label: AppLocalizations.of(context)!.serverAddress),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
SelectableText(
|
||||||
|
serverInfoState.onion
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
|
||||||
|
// Description
|
||||||
|
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel),
|
||||||
|
Text(AppLocalizations.of(context)!.serverDescriptionDescription),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
CwtchButtonTextField(
|
||||||
|
controller: ctrlrDesc,
|
||||||
|
readonly: false,
|
||||||
|
tooltip: "Save", //TODO localize
|
||||||
|
labelText: "Description", // TODO localize
|
||||||
|
icon: Icon(Icons.save),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO save
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
|
||||||
|
Text("Groups on this server"),
|
||||||
|
_buildGroupsList(serverInfoState),
|
||||||
|
|
||||||
|
]))))));
|
||||||
|
}),);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildGroupsList(RemoteServerInfoState serverInfoState) {
|
||||||
|
print("groups: ${serverInfoState.groups} lenMethod: ${serverInfoState.groupsLen} len: ${serverInfoState.groups.length}");
|
||||||
|
final tiles = serverInfoState.groups.map((ContactInfoState group) {
|
||||||
|
print("building group tile for ${group.onion}");
|
||||||
|
return ChangeNotifierProvider<ContactInfoState>.value(key: ValueKey(group.profileOnion + "" + group.onion), value: group, builder: (_, __) => RepaintBoundary(child: _buildGroupRow(group)));
|
||||||
|
});
|
||||||
|
final divided = ListTile.divideTiles(
|
||||||
|
context: context,
|
||||||
|
tiles: tiles,
|
||||||
|
).toList();
|
||||||
|
return RepaintBoundary(child: ListView(children: divided));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _savePressed() {
|
||||||
|
|
||||||
|
var server = Provider.of<ServerInfoState>(context, listen: false);
|
||||||
|
|
||||||
|
Provider.of<FlwtchState>(context, listen: false)
|
||||||
|
.cwtch.SetServerAttribute(server.onion, "description", ctrlrDesc.text);
|
||||||
|
server.setDescription(ctrlrDesc.text);
|
||||||
|
|
||||||
|
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
// TODO support change password
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildGroupRow(ContactInfoState group) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
group.nickname,
|
||||||
|
style: Provider.of<FlwtchState>(context).biggerFont.apply(color: Provider.of<Settings>(context).theme.portraitOnlineBorderColor()),
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: !Provider.of<Settings>(context).streamerMode,
|
||||||
|
child: ExcludeSemantics(
|
||||||
|
child: Text(
|
||||||
|
group.onion,
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(color: Provider.of<Settings>(context).theme.portraitOnlineBorderColor()),
|
||||||
|
)))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -5,12 +5,13 @@ import 'package:provider/provider.dart';
|
||||||
// Provides a styled Text Field for use in Form Widgets.
|
// Provides a styled Text Field for use in Form Widgets.
|
||||||
// Callers must provide a text controller, label helper text and a validator.
|
// Callers must provide a text controller, label helper text and a validator.
|
||||||
class CwtchButtonTextField extends StatefulWidget {
|
class CwtchButtonTextField extends StatefulWidget {
|
||||||
CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true});
|
CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true, this.labelText});
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final Function()? onPressed;
|
final Function()? onPressed;
|
||||||
final Icon icon;
|
final Icon icon;
|
||||||
final String tooltip;
|
final String tooltip;
|
||||||
final bool readonly;
|
final bool readonly;
|
||||||
|
String? labelText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CwtchButtonTextFieldState createState() => _CwtchButtonTextFieldState();
|
_CwtchButtonTextFieldState createState() => _CwtchButtonTextFieldState();
|
||||||
|
@ -39,6 +40,8 @@ class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
enableIMEPersonalizedLearning: false,
|
enableIMEPersonalizedLearning: false,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
labelText: widget.labelText,
|
||||||
|
labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
onPressed: widget.onPressed,
|
onPressed: widget.onPressed,
|
||||||
icon: widget.icon,
|
icon: widget.icon,
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import 'package:cwtch/main.dart';
|
||||||
|
import 'package:cwtch/models/profileservers.dart';
|
||||||
|
import 'package:cwtch/models/servers.dart';
|
||||||
|
import 'package:cwtch/views/addeditservers.dart';
|
||||||
|
import 'package:cwtch/views/remoteserverview.dart';
|
||||||
|
import 'package:cwtch/widgets/profileimage.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import '../cwtch_icons_icons.dart';
|
||||||
|
import '../errorHandler.dart';
|
||||||
|
import '../model.dart';
|
||||||
|
import '../settings.dart';
|
||||||
|
|
||||||
|
class RemoteServerRow extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_RemoteServerRowState createState() => _RemoteServerRowState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RemoteServerRowState extends State<RemoteServerRow> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var server = Provider.of<RemoteServerInfoState>(context);
|
||||||
|
var description = server.description.isNotEmpty ? server.description : server.onion;
|
||||||
|
var running = server.status == "Synced";
|
||||||
|
return Card(clipBehavior: Clip.antiAlias,
|
||||||
|
margin: EdgeInsets.all(0.0),
|
||||||
|
child: InkWell(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(6.0), //border size
|
||||||
|
child: Icon(CwtchIcons.dns_24px,
|
||||||
|
color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor(),
|
||||||
|
size: 64)
|
||||||
|
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
description,
|
||||||
|
semanticsLabel: description,
|
||||||
|
style: Provider.of<FlwtchState>(context).biggerFont.apply(color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: !Provider.of<Settings>(context).streamerMode,
|
||||||
|
child: ExcludeSemantics(
|
||||||
|
child: Text(
|
||||||
|
server.onion,
|
||||||
|
softWrap: true,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(color: running ? Provider.of<Settings>(context).theme.portraitOnlineBorderColor() : Provider.of<Settings>(context).theme.portraitOfflineBorderColor()),
|
||||||
|
)))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
|
||||||
|
]),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||||
|
settings: RouteSettings(name: "remoteserverview"),
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return MultiProvider(
|
||||||
|
providers: [ChangeNotifierProvider(create: (context) => server), Provider.value(value: Provider.of<FlwtchState>(context))],
|
||||||
|
child: RemoteServerView(),
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -77,7 +77,11 @@ class _ServerRowState extends State<ServerRow> {
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
])));
|
]),
|
||||||
|
onTap: () {
|
||||||
|
_pushEditServer(server);
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pushEditServer(ServerInfoState server ) {
|
void _pushEditServer(ServerInfoState server ) {
|
||||||
|
|
Loading…
Reference in New Issue