Adapted servers list and connection screen

This commit is contained in:
Juan Gilsanz Polo 2023-04-30 20:18:29 +02:00
parent f631780e18
commit 33125e543c
8 changed files with 743 additions and 225 deletions

View file

@ -66,6 +66,7 @@ class _ConnectState extends State<Connect> {
controllers: expandableControllerList,
onChange: expandOrContract,
scrollController: scrollController,
breakingWidth: 700,
),
AnimatedPositioned(
duration: const Duration(milliseconds: 100),

View file

@ -6,12 +6,27 @@ class FabConnect extends StatelessWidget {
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
void openAddServerModal() async {
await Future.delayed(const Duration(seconds: 0), (() => {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => const AddServerModal()
))
if (width > 700) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const AddServerModal(
window: true,
),
)
}
else {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => const AddServerModal(
window: false,
)
))
}
}));
}

View file

@ -13,7 +13,12 @@ import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class Servers extends StatefulWidget {
const Servers({Key? key}) : super(key: key);
final double? breakingWidth;
const Servers({
Key? key,
this.breakingWidth
}) : super(key: key);
@override
State<Servers> createState() => _ServersState();
@ -55,16 +60,31 @@ class _ServersState extends State<Servers> {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
for (var i = 0; i < serversProvider.serversList.length; i++) {
expandableControllerList.add(ExpandableController());
}
void openAddServerModal() async {
await Future.delayed(const Duration(seconds: 0), (() => {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => const AddServerModal()
))
if (width > 700) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const AddServerModal(
window: true,
),
)
}
else {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => const AddServerModal(
window: false,
)
))
}
}));
}
@ -79,7 +99,8 @@ class _ServersState extends State<Servers> {
context: context,
controllers: expandableControllerList,
onChange: expandOrContract,
scrollController: scrollController
scrollController: scrollController,
breakingWidth: widget.breakingWidth ?? 700,
),
AnimatedPositioned(
duration: const Duration(milliseconds: 100),

View file

@ -16,10 +16,12 @@ enum ConnectionType { http, https}
class AddServerModal extends StatefulWidget {
final Server? server;
final bool window;
const AddServerModal({
Key? key,
this.server,
required this.window
}) : super(key: key);
@override
@ -429,15 +431,227 @@ class _AddServerModalState extends State<AddServerModal> {
}
}
return Stack(
children: [
Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.createConnection),
actions: [
List<Widget> form() {
return [
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
margin: const EdgeInsets.only(
top: 24,
left: 24,
right: 24
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary.withOpacity(0.05),
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Theme.of(context).colorScheme.primary
)
),
child: Text(
"${connectionType.name}://${ipDomainController.text}${portController.text != '' ? ':${portController.text}' : ""}${pathController.text}",
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500
),
),
),
sectionLabel(AppLocalizations.of(context)!.general),
textField(
label: AppLocalizations.of(context)!.name,
controller: nameController,
icon: Icons.badge_rounded,
error: nameError,
onChanged: (value) {
if (value != '') {
setState(() => nameError = null);
}
else {
setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty);
}
checkDataValid();
}
),
sectionLabel(AppLocalizations.of(context)!.connection),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: SegmentedButton<ConnectionType>(
segments: const [
ButtonSegment(
value: ConnectionType.http,
label: Text("HTTP")
),
ButtonSegment(
value: ConnectionType.https,
label: Text("HTTPS")
),
],
selected: <ConnectionType>{connectionType},
onSelectionChanged: (value) => setState(() => connectionType = value.first),
),
),
const SizedBox(height: 30),
textField(
label: AppLocalizations.of(context)!.ipDomain,
controller: ipDomainController,
icon: Icons.link_rounded,
error: ipDomainError,
keyboardType: TextInputType.url,
onChanged: validateAddress
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.path,
controller: pathController,
icon: Icons.route_rounded,
error: pathError,
onChanged: validateSubroute,
hintText: AppLocalizations.of(context)!.examplePath,
helperText: AppLocalizations.of(context)!.helperPath,
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.port,
controller: portController,
icon: Icons.numbers_rounded,
error: portError,
keyboardType: TextInputType.number,
onChanged: validatePort
),
sectionLabel(AppLocalizations.of(context)!.authentication),
textField(
label: AppLocalizations.of(context)!.username,
controller: userController,
icon: Icons.person_rounded,
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.password,
controller: passwordController,
icon: Icons.lock_rounded,
keyboardType: TextInputType.visiblePassword,
obscureText: true
),
sectionLabel(AppLocalizations.of(context)!.other),
Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.server == null
? () => setState(() => defaultServer = !defaultServer)
: null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.defaultServer,
style: const TextStyle(
fontSize: 15,
),
),
Switch(
value: defaultServer,
onChanged: widget.server == null
? (value) => setState(() => defaultServer = value)
: null,
)
],
),
),
),
),
const SizedBox(height: 20),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () => setState(() => homeAssistant = !homeAssistant),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.runningHomeAssistant,
style: const TextStyle(
fontSize: 15,
),
),
Switch(
value: homeAssistant,
onChanged: (value) => setState(() => homeAssistant = value),
)
],
),
),
),
),
const SizedBox(height: 20),
];
}
if (widget.window == true) {
return Dialog(
child: SizedBox(
width: 400,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(right: 10),
child: IconButton(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
IconButton(
onPressed: () => Navigator.pop(context),
icon: const Icon(Icons.clear_rounded)
),
const SizedBox(width: 8),
Text(
AppLocalizations.of(context)!.createConnection,
style: const TextStyle(
fontSize: 20
),
),
],
),
IconButton(
tooltip: widget.server == null
? AppLocalizations.of(context)!.connect
: AppLocalizations.of(context)!.save,
onPressed: allDataValid == true
? widget.server == null
? () => connect()
: () => edit()
: null,
icon: Icon(
widget.server == null
? Icons.login_rounded
: Icons.save_rounded
)
),
],
),
),
Expanded(
child: ListView(
children: form()
),
)
],
),
),
);
}
else {
return Stack(
children: [
Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.createConnection),
actions: [
IconButton(
tooltip: widget.server == null
? AppLocalizations.of(context)!.connect
: AppLocalizations.of(context)!.save,
@ -452,203 +666,49 @@ class _AddServerModalState extends State<AddServerModal> {
: Icons.save_rounded
)
),
),
],
toolbarHeight: 70,
const SizedBox(width: 10)
],
toolbarHeight: 70,
),
body: ListView(
children: form(),
)
),
body: ListView(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
margin: const EdgeInsets.only(
top: 24,
left: 24,
right: 24
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary.withOpacity(0.05),
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Theme.of(context).colorScheme.primary
)
),
child: Text(
"${connectionType.name}://${ipDomainController.text}${portController.text != '' ? ':${portController.text}' : ""}${pathController.text}",
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500
),
),
),
sectionLabel(AppLocalizations.of(context)!.general),
textField(
label: AppLocalizations.of(context)!.name,
controller: nameController,
icon: Icons.badge_rounded,
error: nameError,
onChanged: (value) {
if (value != '') {
setState(() => nameError = null);
}
else {
setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty);
}
checkDataValid();
}
),
sectionLabel(AppLocalizations.of(context)!.connection),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: SegmentedButton<ConnectionType>(
segments: const [
ButtonSegment(
value: ConnectionType.http,
label: Text("HTTP")
),
ButtonSegment(
value: ConnectionType.https,
label: Text("HTTPS")
),
],
selected: <ConnectionType>{connectionType},
onSelectionChanged: (value) => setState(() => connectionType = value.first),
),
),
const SizedBox(height: 30),
textField(
label: AppLocalizations.of(context)!.ipDomain,
controller: ipDomainController,
icon: Icons.link_rounded,
error: ipDomainError,
keyboardType: TextInputType.url,
onChanged: validateAddress
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.path,
controller: pathController,
icon: Icons.route_rounded,
error: pathError,
onChanged: validateSubroute,
hintText: AppLocalizations.of(context)!.examplePath,
helperText: AppLocalizations.of(context)!.helperPath,
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.port,
controller: portController,
icon: Icons.numbers_rounded,
error: portError,
keyboardType: TextInputType.number,
onChanged: validatePort
),
sectionLabel(AppLocalizations.of(context)!.authentication),
textField(
label: AppLocalizations.of(context)!.username,
controller: userController,
icon: Icons.person_rounded,
),
const SizedBox(height: 20),
textField(
label: AppLocalizations.of(context)!.password,
controller: passwordController,
icon: Icons.lock_rounded,
keyboardType: TextInputType.visiblePassword,
obscureText: true
),
sectionLabel(AppLocalizations.of(context)!.other),
Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.server == null
? () => setState(() => defaultServer = !defaultServer)
: null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.defaultServer,
style: const TextStyle(
fontSize: 15,
),
),
Switch(
value: defaultServer,
onChanged: widget.server == null
? (value) => setState(() => defaultServer = value)
: null,
)
],
),
),
),
),
const SizedBox(height: 20),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () => setState(() => homeAssistant = !homeAssistant),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLocalizations.of(context)!.runningHomeAssistant,
style: const TextStyle(
fontSize: 15,
),
),
Switch(
value: homeAssistant,
onChanged: (value) => setState(() => homeAssistant = value),
)
],
),
),
),
),
const SizedBox(height: 20),
],
),
),
AnimatedOpacity(
opacity: isConnecting == true ? 1 : 0,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: IgnorePointer(
ignoring: isConnecting == true ? false : true,
child: Scaffold(
backgroundColor: Colors.transparent,
body: Container(
width: mediaQuery.size.width,
height: mediaQuery.size.height,
color: const Color.fromRGBO(0, 0, 0, 0.7),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircularProgressIndicator(
color: Colors.white,
),
const SizedBox(height: 30),
Text(
AppLocalizations.of(context)!.connecting,
style: const TextStyle(
AnimatedOpacity(
opacity: isConnecting == true ? 1 : 0,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: IgnorePointer(
ignoring: isConnecting == true ? false : true,
child: Scaffold(
backgroundColor: Colors.transparent,
body: Container(
width: mediaQuery.size.width,
height: mediaQuery.size.height,
color: const Color.fromRGBO(0, 0, 0, 0.7),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircularProgressIndicator(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 26
),
)
],
const SizedBox(height: 30),
Text(
AppLocalizations.of(context)!.connecting,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 26
),
)
],
),
),
),
),
),
)
],
);
)
],
);
}
}
}

View file

@ -20,6 +20,7 @@ class ProcessDialog extends StatelessWidget {
horizontal: 30
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(width: 40),

View file

@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/servers_list/servers_list_item.dart';
import 'package:adguard_home_manager/widgets/servers_list/servers_tile_item.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -13,6 +14,7 @@ class ServersList extends StatelessWidget {
final List<ExpandableController> controllers;
final Function(int) onChange;
final ScrollController scrollController;
final double breakingWidth;
const ServersList({
Key? key,
@ -20,23 +22,44 @@ class ServersList extends StatelessWidget {
required this.controllers,
required this.onChange,
required this.scrollController,
required this.breakingWidth
}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final width = MediaQuery.of(context).size.width;
if (serversProvider.serversList.isNotEmpty) {
return ListView.builder(
controller: scrollController,
itemCount: serversProvider.serversList.length,
itemBuilder: (context, index) => ServersListItem(
expandableController: controllers[index],
server: serversProvider.serversList[index],
index: index,
onChange: onChange
)
);
if (width > breakingWidth) {
return ListView(
children: [
Wrap(
children: serversProvider.serversList.asMap().entries.map(
(s) => ServersTileItem(
server: serversProvider.serversList[s.key],
index: s.key,
onChange: onChange
)
).toList(),
),
const SizedBox(height: 8)
],
);
}
else {
return ListView.builder(
controller: scrollController,
itemCount: serversProvider.serversList.length,
itemBuilder: (context, index) => ServersListItem(
expandableController: controllers[index],
server: serversProvider.serversList[index],
index: index,
onChange: onChange
)
);
}
}
else {
return SizedBox(

View file

@ -71,6 +71,8 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
void showDeleteModal(Server server) async {
await Future.delayed(const Duration(seconds: 0), () => {
showDialog(
@ -85,10 +87,25 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
void openAddServerBottomSheet({Server? server}) async {
await Future.delayed(const Duration(seconds: 0), (() => {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => AddServerModal(server: server)
))
if (width > 700) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AddServerModal(
server: server,
window: true,
),
)
}
else {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => AddServerModal(
server: server,
window: false,
)
))
}
}));
}
@ -356,7 +373,6 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
);
}
return Container(
decoration: BoxDecoration(
border: Border(

View file

@ -0,0 +1,381 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/app_log.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ServersTileItem extends StatefulWidget {
final Server server;
final int index;
final void Function(int) onChange;
const ServersTileItem({
Key? key,
required this.server,
required this.index,
required this.onChange
}) : super(key: key);
@override
State<ServersTileItem> createState() => _ServersTileItemState();
}
class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
void showDeleteModal(Server server) async {
await Future.delayed(const Duration(seconds: 0), () => {
showDialog(
context: context,
builder: (context) => DeleteModal(
serverToDelete: server,
),
barrierDismissible: false
)
});
}
void openAddServerBottomSheet({Server? server}) async {
await Future.delayed(const Duration(seconds: 0), (() => {
if (width > 700) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AddServerModal(
server: server,
window: true,
),
)
}
else {
Navigator.push(context, MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) => AddServerModal(
server: server,
window: false,
)
))
}
}));
}
void connectToServer(Server server) async {
final ProcessModal process = ProcessModal(context: context);
process.open(AppLocalizations.of(context)!.connecting);
final result = server.runningOnHa == true
? await loginHA(server)
: await login(server);
if (result['result'] == 'success') {
serversProvider.setSelectedServer(server);
serversProvider.setServerStatusLoad(0);
final serverStatus = await getServerStatus(server);
if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']);
serversProvider.checkServerUpdatesAvailable(server);
serversProvider.setServerStatusLoad(1);
}
else {
appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2);
}
process.close();
}
else {
process.close();
appConfigProvider.addLog(result['log']);
showSnacbkar(
context: context,
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.cannotConnect,
color: Colors.red
);
}
}
void setDefaultServer(Server server) async {
final result = await serversProvider.setDefaultServer(server);
if (result == null) {
showSnacbkar(
context: context,
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionDefaultSuccessfully,
color: Colors.green
);
}
else {
appConfigProvider.addLog(
AppLog(
type: 'set_default_server',
dateTime: DateTime.now(),
message: result.toString()
)
);
showSnacbkar(
context: context,
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionDefaultFailed,
color: Colors.red
);
}
}
Widget leadingIcon(Server server) {
if (server.defaultServer == true) {
return Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? Colors.green
: Colors.orange
: null,
),
SizedBox(
width: 25,
height: 25,
child: Stack(
alignment: Alignment.bottomRight,
children: [
Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(20)
),
child: Icon(
Icons.star,
color: Theme.of(context).colorScheme.onPrimaryContainer,
size: 10,
),
),
],
),
)
],
);
}
else {
return Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? Colors.green
: Colors.orange
: null,
);
}
}
Widget topRow(Server server, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Container(
margin: const EdgeInsets.only(right: 16),
child: leadingIcon(server),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurface
),
),
Column(
children: [
const SizedBox(height: 3),
Text(
server.name,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurfaceVariant
),
)
],
)
],
),
),
],
),
),
],
);
}
Widget bottomRow(Server server, int index) {
return Column(
children: [
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
PopupMenuButton(
// color: Theme.of(context).dialogBackgroundColor,
itemBuilder: (context) => [
PopupMenuItem(
enabled: server.defaultServer == false
? true
: false,
onTap: server.defaultServer == false
? (() => setDefaultServer(server))
: null,
child: SizedBox(
child: Row(
children: [
const Icon(Icons.star),
const SizedBox(width: 15),
Text(
server.defaultServer == true
? AppLocalizations.of(context)!.defaultConnection
: AppLocalizations.of(context)!.setDefault,
)
],
),
)
),
PopupMenuItem(
onTap: (() => openAddServerBottomSheet(server: server)),
child: Row(
children: [
const Icon(Icons.edit),
const SizedBox(width: 15),
Text(AppLocalizations.of(context)!.edit)
],
)
),
PopupMenuItem(
onTap: (() => showDeleteModal(server)),
child: Row(
children: [
const Icon(Icons.delete),
const SizedBox(width: 15),
Text(AppLocalizations.of(context)!.delete)
],
)
),
]
),
SizedBox(
child: serversProvider.selectedServer != null &&
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null &&
serversProvider.selectedServer?.id == server.id
? Container(
margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
decoration: BoxDecoration(
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null
? Colors.green
: Colors.orange,
borderRadius: BorderRadius.circular(30)
),
child: Row(
children: [
Icon(
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null
? Icons.check
: Icons.warning,
color: Colors.white,
),
const SizedBox(width: 10),
Text(
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null
? AppLocalizations.of(context)!.connected
: AppLocalizations.of(context)!.selectedDisconnected,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500
),
)
],
),
)
: Container(
margin: const EdgeInsets.only(right: 10),
child: TextButton(
onPressed: () => connectToServer(server),
child: Text(AppLocalizations.of(context)!.connect),
),
),
)
],
)
],
);
}
EdgeInsets generateMargins(int index) {
if (index == 0) {
return const EdgeInsets.only(top: 16, left: 16, right: 8, bottom: 8);
}
if (index == 1) {
return const EdgeInsets.only(top: 16, left: 8, right: 16, bottom: 8);
}
else if (index == serversProvider.serversList.length-1 && (index+1)%2 == 0) {
return const EdgeInsets.only(top: 8, left: 8, right: 16, bottom: 16);
}
else if (index == serversProvider.serversList.length-1 && (index+1)%2 == 1) {
return const EdgeInsets.only(top: 8, left: 16, right: 8, bottom: 16);
}
else {
if ((index+1)%2 == 0) {
return const EdgeInsets.only(top: 8, left: 8, right: 16, bottom: 8);
}
else {
return const EdgeInsets.only(top: 8, left: 16, right: 8, bottom: 8);
}
}
}
return FractionallySizedBox(
widthFactor: 0.5,
child: Card(
margin: generateMargins(widget.index),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
topRow(widget.server, widget.index),
bottomRow(widget.server, widget.index)
],
),
),
),
);
}
}