mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-04 20:30:35 +00:00
Added select server screen and add server screen
This commit is contained in:
parent
e1ff7a151d
commit
a97ae20631
22 changed files with 623 additions and 27 deletions
|
@ -1,8 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/app_screen.dart';
|
||||
import 'package:adguard_home_manager/config/app_screens.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
class Base extends StatefulWidget {
|
||||
const Base({Key? key}) : super(key: key);
|
||||
|
@ -16,6 +20,16 @@ class _BaseState extends State<Base> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
|
||||
List<AppScreen> screens = serversProvider.selectedServer != null
|
||||
? screensServerConnected
|
||||
: screensSelectServer;
|
||||
|
||||
if (selectedScreen > screens.length-1) {
|
||||
setState(() => selectedScreen = 0);
|
||||
}
|
||||
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
|
@ -31,20 +45,14 @@ class _BaseState extends State<Base> {
|
|||
: Brightness.light,
|
||||
),
|
||||
child: Scaffold(
|
||||
body: PageTransitionSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
transitionBuilder: (
|
||||
(child, primaryAnimation, secondaryAnimation) => FadeThroughTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
child: child,
|
||||
)
|
||||
),
|
||||
),
|
||||
appBar: screens[selectedScreen].appBar,
|
||||
body: screens[selectedScreen].body,
|
||||
bottomNavigationBar: BottomNavBar(
|
||||
screens: screens,
|
||||
selectedScreen: selectedScreen,
|
||||
onSelect: (value) => setState(() => selectedScreen = value),
|
||||
),
|
||||
floatingActionButton: screens[selectedScreen].fab,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,42 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/home.dart';
|
||||
import 'package:adguard_home_manager/screens/settings.dart';
|
||||
import 'package:adguard_home_manager/screens/connect/fab.dart';
|
||||
import 'package:adguard_home_manager/screens/home/appbar.dart';
|
||||
import 'package:adguard_home_manager/screens/connect/appbar.dart';
|
||||
import 'package:adguard_home_manager/screens/connect/connect.dart';
|
||||
import 'package:adguard_home_manager/screens/home/home.dart';
|
||||
import 'package:adguard_home_manager/screens/settings/appbar.dart';
|
||||
import 'package:adguard_home_manager/screens/settings/settings.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/app_screen.dart';
|
||||
|
||||
const List<AppScreen> screens = [
|
||||
AppScreen(
|
||||
name: "home",
|
||||
icon: Icons.home_rounded,
|
||||
widget: Home()
|
||||
List<AppScreen> screensSelectServer = [
|
||||
const AppScreen(
|
||||
name: "connect",
|
||||
icon: Icons.link_rounded,
|
||||
appBar: ConnectAppBar(),
|
||||
body: Connect(),
|
||||
fab: FabConnect()
|
||||
),
|
||||
AppScreen(
|
||||
const AppScreen(
|
||||
name: "settings",
|
||||
icon: Icons.settings_rounded,
|
||||
widget: Settings()
|
||||
appBar: SettingsAppBar(),
|
||||
body: Settings()
|
||||
)
|
||||
];
|
||||
|
||||
List<AppScreen> screensServerConnected = [
|
||||
const AppScreen(
|
||||
name: "home",
|
||||
icon: Icons.home_rounded,
|
||||
appBar: HomeAppBar(),
|
||||
body: Home()
|
||||
),
|
||||
const AppScreen(
|
||||
name: "settings",
|
||||
icon: Icons.settings_rounded,
|
||||
appBar: SettingsAppBar(),
|
||||
body: Settings()
|
||||
)
|
||||
];
|
16
lib/config/system_overlay_style.dart
Normal file
16
lib/config/system_overlay_style.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
SystemUiOverlayStyle systemUiOverlayStyleConfig(BuildContext context) => SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarBrightness: Theme.of(context).brightness == Brightness.light
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
statusBarIconBrightness: Theme.of(context).brightness == Brightness.light
|
||||
? Brightness.dark
|
||||
: Brightness.light,
|
||||
systemNavigationBarColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
systemNavigationBarIconBrightness: Theme.of(context).brightness == Brightness.light
|
||||
? Brightness.dark
|
||||
: Brightness.light,
|
||||
);
|
45
lib/functions/conversions.dart
Normal file
45
lib/functions/conversions.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
import 'package:intl/intl.dart';
|
||||
|
||||
bool? convertFromIntToBool(int value) {
|
||||
if (value == 1) {
|
||||
return true;
|
||||
}
|
||||
else if (value == 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int? convertFromBoolToInt(bool value) {
|
||||
if (value == true) {
|
||||
return 1;
|
||||
}
|
||||
else if (value == false) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
double formatPercentage(double value) {
|
||||
return (value * 100).truncateToDouble() / 100;
|
||||
}
|
||||
|
||||
String intFormat(int value, String locale) {
|
||||
final f = NumberFormat("#,###", locale);
|
||||
return f.format(value);
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> convertFromMapToList(Map<String, int> values) {
|
||||
List<Map<String, dynamic>> items = [];
|
||||
values.forEach((key, value) {
|
||||
items.add({
|
||||
"label": key,
|
||||
"value": value
|
||||
});
|
||||
});
|
||||
return items;
|
||||
}
|
|
@ -1,4 +1,18 @@
|
|||
{
|
||||
"home": "Home",
|
||||
"settings": "Settings"
|
||||
"settings": "Settings",
|
||||
"connect": "Connect",
|
||||
"servers": "Servers",
|
||||
"createConnection": "Create connection",
|
||||
"name": "Name",
|
||||
"ipDomain": "IP address or domain",
|
||||
"path": "Path",
|
||||
"port": "Port",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"defaultServer": "Default server",
|
||||
"general": "General",
|
||||
"connection": "Connection",
|
||||
"authentication": "Authentication",
|
||||
"other": "Other"
|
||||
}
|
|
@ -1,4 +1,18 @@
|
|||
{
|
||||
"home": "Inicio",
|
||||
"settings": "Ajustes"
|
||||
"settings": "Ajustes",
|
||||
"connect": "Conectar",
|
||||
"servers": "Servidores",
|
||||
"createConnection": "Crear conexión",
|
||||
"name": "Nombre",
|
||||
"ipDomain": "Dirección IP o dominio",
|
||||
"path": "Ruta",
|
||||
"port": "Puerto",
|
||||
"username": "Nombre de usuario",
|
||||
"password": "Contraseña",
|
||||
"defaultServer": "Servidor por defecto",
|
||||
"general": "General",
|
||||
"connection": "Conexión",
|
||||
"authentication": "Autenticación",
|
||||
"other": "Otros"
|
||||
}
|
|
@ -11,7 +11,9 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|||
|
||||
import 'package:adguard_home_manager/base.dart';
|
||||
|
||||
import 'package:adguard_home_manager/services/database.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
import 'package:adguard_home_manager/config/theme.dart';
|
||||
|
||||
|
||||
|
@ -22,6 +24,12 @@ void main() async {
|
|||
);
|
||||
|
||||
AppConfigProvider appConfigProvider = AppConfigProvider();
|
||||
ServersProvider serversProvider = ServersProvider();
|
||||
|
||||
final dbData = await loadDb();
|
||||
serversProvider.setDbInstance(dbData['dbInstance']);
|
||||
appConfigProvider.setDbInstance(dbData['dbInstance']);
|
||||
serversProvider.saveFromDb(dbData['servers']);
|
||||
|
||||
PackageInfo appInfo = await PackageInfo.fromPlatform();
|
||||
appConfigProvider.setAppInfo(appInfo);
|
||||
|
@ -39,9 +47,12 @@ void main() async {
|
|||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(
|
||||
create: ((context) => serversProvider)
|
||||
),
|
||||
ChangeNotifierProvider(
|
||||
create: ((context) => appConfigProvider)
|
||||
)
|
||||
),
|
||||
],
|
||||
child: const Main(),
|
||||
)
|
||||
|
|
|
@ -3,11 +3,15 @@ import 'package:flutter/material.dart';
|
|||
class AppScreen {
|
||||
final String name;
|
||||
final IconData icon;
|
||||
final Widget widget;
|
||||
final PreferredSizeWidget appBar;
|
||||
final Widget body;
|
||||
final Widget? fab;
|
||||
|
||||
const AppScreen({
|
||||
required this.name,
|
||||
required this.icon,
|
||||
required this.widget
|
||||
required this.appBar,
|
||||
required this.body,
|
||||
this.fab
|
||||
});
|
||||
}
|
21
lib/models/server.dart
Normal file
21
lib/models/server.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
class Server {
|
||||
final String name;
|
||||
final String connectionMethod;
|
||||
final String domain;
|
||||
final String? path;
|
||||
final int? port;
|
||||
final String user;
|
||||
final String password;
|
||||
final bool defaultServer;
|
||||
|
||||
const Server({
|
||||
required this.name,
|
||||
required this.connectionMethod,
|
||||
required this.domain,
|
||||
this.path,
|
||||
this.port,
|
||||
required this.user,
|
||||
required this.password,
|
||||
required this.defaultServer
|
||||
});
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:sqflite/sqlite_api.dart';
|
||||
|
||||
class AppConfigProvider with ChangeNotifier {
|
||||
Database? _dbInstance;
|
||||
|
||||
PackageInfo? _appInfo;
|
||||
AndroidDeviceInfo? _androidDeviceInfo;
|
||||
IosDeviceInfo? _iosDeviceInfo;
|
||||
|
@ -19,6 +22,10 @@ class AppConfigProvider with ChangeNotifier {
|
|||
return _iosDeviceInfo;
|
||||
}
|
||||
|
||||
void setDbInstance(Database db) {
|
||||
_dbInstance = db;
|
||||
}
|
||||
|
||||
void setAppInfo(PackageInfo appInfo) {
|
||||
_appInfo = appInfo;
|
||||
}
|
||||
|
|
51
lib/providers/servers_provider.dart
Normal file
51
lib/providers/servers_provider.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import 'package:adguard_home_manager/functions/conversions.dart';
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
|
||||
class ServersProvider with ChangeNotifier {
|
||||
Database? _dbInstance;
|
||||
|
||||
List<Server> _serversList = [];
|
||||
Server? _selectedServer;
|
||||
|
||||
List<Server> get serversList {
|
||||
return _serversList;
|
||||
}
|
||||
|
||||
Server? get selectedServer {
|
||||
return _selectedServer;
|
||||
}
|
||||
|
||||
void setDbInstance(Database db) {
|
||||
_dbInstance = db;
|
||||
}
|
||||
|
||||
void addServer(Server server) {
|
||||
_serversList.add(server);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void saveFromDb(List<Map<String, dynamic>>? data) async {
|
||||
if (data != null) {
|
||||
for (var server in data) {
|
||||
final Server serverObj = Server(
|
||||
name: server['name'],
|
||||
connectionMethod: server['connectionMethod'],
|
||||
domain: server['domain'],
|
||||
path: server['path'],
|
||||
port: server['port'],
|
||||
user: server['user'],
|
||||
password: server['password'],
|
||||
defaultServer: convertFromIntToBool(server['isDefaultServer'])!,
|
||||
);
|
||||
_serversList.add(serverObj);
|
||||
if (convertFromIntToBool(server['isDefaultServer']) == true) {
|
||||
_selectedServer = serverObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
17
lib/screens/connect/appbar.dart
Normal file
17
lib/screens/connect/appbar.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class ConnectAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||
const ConnectAppBar({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.connect),
|
||||
centerTitle: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
10
lib/screens/connect/connect.dart
Normal file
10
lib/screens/connect/connect.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class Connect extends StatelessWidget {
|
||||
const Connect({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
23
lib/screens/connect/fab.dart
Normal file
23
lib/screens/connect/fab.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FabConnect extends StatelessWidget {
|
||||
const FabConnect({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
void openAddServerModal() async {
|
||||
await Future.delayed(const Duration(seconds: 0), (() => {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) => const AddServerModal()
|
||||
))
|
||||
}));
|
||||
}
|
||||
|
||||
return FloatingActionButton(
|
||||
onPressed: openAddServerModal,
|
||||
child: const Icon(Icons.add_rounded),
|
||||
);
|
||||
}
|
||||
}
|
16
lib/screens/home/appbar.dart
Normal file
16
lib/screens/home/appbar.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class HomeAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||
const HomeAppBar({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
PreferredSizeWidget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.home),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
16
lib/screens/settings/appbar.dart
Normal file
16
lib/screens/settings/appbar.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class SettingsAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||
const SettingsAppBar({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.settings),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
35
lib/services/database.dart
Normal file
35
lib/services/database.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
Future<Map<String, dynamic>> loadDb() async {
|
||||
List<Map<String, Object?>>? servers;
|
||||
// List<Map<String, Object?>>? appConfig;
|
||||
|
||||
Database db = await openDatabase(
|
||||
'adguard_home_manager.db',
|
||||
version: 1,
|
||||
onCreate: (Database db, int version) async {
|
||||
await db.execute("CREATE TABLE servers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER)");
|
||||
},
|
||||
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||
|
||||
},
|
||||
onOpen: (Database db) async {
|
||||
await db.transaction((txn) async{
|
||||
servers = await txn.rawQuery(
|
||||
'SELECT * FROM servers',
|
||||
);
|
||||
});
|
||||
// await db.transaction((txn) async{
|
||||
// appConfig = await txn.rawQuery(
|
||||
// 'SELECT * FROM appConfig',
|
||||
// );
|
||||
// });
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
"servers": servers,
|
||||
// "appConfig": appConfig![0],
|
||||
"dbInstance": db,
|
||||
};
|
||||
}
|
194
lib/widgets/add_server_modal.dart
Normal file
194
lib/widgets/add_server_modal.dart
Normal file
|
@ -0,0 +1,194 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/custom_radio_toggle.dart';
|
||||
|
||||
import 'package:adguard_home_manager/config/system_overlay_style.dart';
|
||||
|
||||
class AddServerModal extends StatefulWidget {
|
||||
const AddServerModal({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddServerModal> createState() => _AddServerModalState();
|
||||
}
|
||||
|
||||
class _AddServerModalState extends State<AddServerModal> {
|
||||
final TextEditingController nameController = TextEditingController();
|
||||
|
||||
String connectionType = "http";
|
||||
|
||||
final TextEditingController ipDomainController = TextEditingController();
|
||||
String? ipDomainError;
|
||||
|
||||
final TextEditingController pathController = TextEditingController();
|
||||
String? pathError;
|
||||
|
||||
final TextEditingController portController = TextEditingController();
|
||||
String? portError;
|
||||
|
||||
final TextEditingController userController = TextEditingController();
|
||||
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
bool defaultServer = false;
|
||||
|
||||
Widget sectionLabel(String label) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 30
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget textField({
|
||||
required String label,
|
||||
required TextEditingController controller,
|
||||
String? error,
|
||||
required IconData icon,
|
||||
TextInputType? keyboardType
|
||||
}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(icon),
|
||||
errorText: error,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10)
|
||||
)
|
||||
),
|
||||
labelText: label,
|
||||
),
|
||||
keyboardType: keyboardType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Scaffold(
|
||||
backgroundColor: Theme.of(context).dialogBackgroundColor,
|
||||
appBar: AppBar(
|
||||
systemOverlayStyle: systemUiOverlayStyleConfig(context),
|
||||
title: Text(AppLocalizations.of(context)!.createConnection),
|
||||
elevation: 5,
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: IconButton(
|
||||
tooltip: AppLocalizations.of(context)!.connect,
|
||||
onPressed: () => {},
|
||||
icon: const Icon(Icons.login_rounded)
|
||||
),
|
||||
),
|
||||
],
|
||||
toolbarHeight: 70,
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
sectionLabel(AppLocalizations.of(context)!.general),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.name,
|
||||
controller: nameController,
|
||||
icon: Icons.badge_rounded
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.connection),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
CustomRadioToggle(
|
||||
groupSelected: connectionType,
|
||||
value: 'http',
|
||||
label: 'HTTP',
|
||||
onTap: (value) => setState(() => connectionType = value)
|
||||
),
|
||||
CustomRadioToggle(
|
||||
groupSelected: connectionType,
|
||||
value: 'https',
|
||||
label: 'HTTPS',
|
||||
onTap: (value) => setState(() => connectionType = value)
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.ipDomain,
|
||||
controller: ipDomainController,
|
||||
icon: Icons.link_rounded,
|
||||
error: ipDomainError,
|
||||
keyboardType: TextInputType.url
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.path,
|
||||
controller: pathController,
|
||||
icon: Icons.route_rounded,
|
||||
error: pathError
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.port,
|
||||
controller: portController,
|
||||
icon: Icons.numbers_rounded,
|
||||
error: portError,
|
||||
keyboardType: TextInputType.number
|
||||
),
|
||||
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
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.other),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => setState(() => defaultServer = !defaultServer),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.defaultServer,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: defaultServer,
|
||||
onChanged: (value) => setState(() => defaultServer = value),
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/app_screen.dart';
|
||||
import 'package:adguard_home_manager/config/app_screens.dart';
|
||||
|
||||
class BottomNavBar extends StatelessWidget {
|
||||
final List<AppScreen> screens;
|
||||
final int selectedScreen;
|
||||
final void Function(int) onSelect;
|
||||
|
||||
const BottomNavBar({
|
||||
Key? key,
|
||||
Key? key,
|
||||
required this.screens,
|
||||
required this.selectedScreen,
|
||||
required this.onSelect,
|
||||
}) : super(key: key);
|
||||
|
@ -23,6 +26,9 @@ class BottomNavBar extends StatelessWidget {
|
|||
case 'settings':
|
||||
return AppLocalizations.of(context)!.settings;
|
||||
|
||||
case 'connect':
|
||||
return AppLocalizations.of(context)!.connect;
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
|
65
lib/widgets/custom_radio_toggle.dart
Normal file
65
lib/widgets/custom_radio_toggle.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomRadioToggle extends StatelessWidget {
|
||||
final String groupSelected;
|
||||
final String value;
|
||||
final String label;
|
||||
final void Function(String) onTap;
|
||||
|
||||
const CustomRadioToggle({
|
||||
Key? key,
|
||||
required this.groupSelected,
|
||||
required this.value,
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => onTap(value),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15,
|
||||
vertical: 5
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: groupSelected == value
|
||||
? Theme.of(context).primaryColor
|
||||
: Theme.of(context).primaryColor.withOpacity(0.05),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).primaryColor
|
||||
),
|
||||
borderRadius: BorderRadius.circular(30)
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (groupSelected == value) ...[
|
||||
const Icon(
|
||||
Icons.check,
|
||||
color: Colors.white,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: groupSelected == value
|
||||
? Colors.white
|
||||
: null
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue