lemmur-app-android/lib/pages/settings.dart

305 lines
8.8 KiB
Dart
Raw Normal View History

import 'package:flutter/cupertino.dart';
2020-08-31 16:17:39 +02:00
import 'package:flutter/material.dart';
2020-09-08 00:34:09 +02:00
import 'package:flutter_hooks/flutter_hooks.dart';
2020-08-31 16:17:39 +02:00
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:provider/provider.dart';
import '../stores/accounts_store.dart';
2020-08-31 16:17:39 +02:00
import '../stores/config_store.dart';
import '../util/goto.dart';
2020-08-31 16:17:39 +02:00
2020-09-03 14:33:17 +02:00
class SettingsPage extends StatelessWidget {
2020-08-31 16:17:39 +02:00
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
backgroundColor: theme.scaffoldBackgroundColor,
shadowColor: Colors.transparent,
iconTheme: theme.iconTheme,
title: Text('Settings', style: theme.textTheme.headline6),
centerTitle: true,
),
body: Container(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.person),
title: Text('Accounts'),
onTap: () {
goTo(context, (_) => AccountsConfigPage());
},
2020-08-31 16:17:39 +02:00
),
ListTile(
leading: Icon(Icons.color_lens),
title: Text('Appearance'),
onTap: () {
goTo(context, (_) => AppearanceConfigPage());
2020-08-31 16:17:39 +02:00
},
)
],
),
),
);
}
}
class AppearanceConfigPage extends StatelessWidget {
2020-08-31 16:17:39 +02:00
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
backgroundColor: theme.scaffoldBackgroundColor,
shadowColor: Colors.transparent,
iconTheme: theme.iconTheme,
title: Text('Appearance', style: theme.textTheme.headline6),
centerTitle: true,
),
body: Observer(
builder: (ctx) => ListView(
2020-08-31 16:17:39 +02:00
children: [
2020-09-03 23:14:26 +02:00
_SectionHeading('Theme'),
2020-08-31 16:17:39 +02:00
for (final theme in ThemeMode.values)
RadioListTile<ThemeMode>(
value: theme,
title: Text(theme.toString().split('.')[1]),
groupValue: ctx.watch<ConfigStore>().theme,
onChanged: (selected) {
ctx.read<ConfigStore>().theme = selected;
},
),
2020-09-08 10:23:08 +02:00
SwitchListTile(
2020-09-08 10:24:47 +02:00
title: Text('AMOLED dark mode'),
2020-09-08 10:23:08 +02:00
value: ctx.watch<ConfigStore>().amoledDarkMode,
onChanged: (checked) {
ctx.read<ConfigStore>().amoledDarkMode = checked;
})
2020-08-31 16:17:39 +02:00
],
),
),
);
}
}
class AccountsConfigPage extends HookWidget {
2020-09-08 00:34:09 +02:00
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
return Scaffold(
2020-09-08 00:34:09 +02:00
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: theme.scaffoldBackgroundColor,
shadowColor: Colors.transparent,
iconTheme: theme.iconTheme,
title: Text('Accounts', style: theme.textTheme.headline6),
centerTitle: true,
),
2020-09-08 00:34:09 +02:00
floatingActionButton: FloatingActionButton(
2020-09-08 01:27:02 +02:00
onPressed: () {
showDialog(
2020-09-08 00:34:09 +02:00
context: context,
2020-09-08 01:27:02 +02:00
builder: (_) =>
_AccountsConfigAddInstanceDialog(scaffoldKey: _scaffoldKey),
2020-09-08 00:34:09 +02:00
);
},
child: Icon(Icons.add),
),
body: Observer(
builder: (ctx) {
var accountsStore = ctx.watch<AccountsStore>();
var theme = Theme.of(context);
return ListView(
children: [
for (var entry in accountsStore.users.entries) ...[
2020-09-03 23:14:26 +02:00
_SectionHeading(entry.key),
for (var username in entry.value.keys) ...[
ListTile(
trailing:
username == accountsStore.defaultUserFor(entry.key).name
2020-09-03 23:14:26 +02:00
? Icon(
Icons.check_circle_outline,
color: theme.accentColor,
)
: null,
title: Text(username),
onLongPress: () {
accountsStore.setDefaultAccountFor(entry.key, username);
},
2020-09-03 23:14:26 +02:00
onTap: () {}, // TODO: go to managing account
),
],
2020-09-08 01:27:02 +02:00
ListTile(
leading: Icon(Icons.add),
title: Text('Add account'),
onTap: () {
showDialog(
context: context,
builder: (_) => _AccountsConfigAddAccountDialog(
scaffoldKey: _scaffoldKey,
instanceUrl: entry.key,
),
);
},
),
]
2020-09-08 16:37:58 +02:00
],
);
},
),
);
}
}
2020-09-03 23:14:26 +02:00
2020-09-08 01:27:02 +02:00
class _AccountsConfigAddInstanceDialog extends HookWidget {
final GlobalKey<ScaffoldState> scaffoldKey;
const _AccountsConfigAddInstanceDialog({@required this.scaffoldKey})
: assert(scaffoldKey != null);
@override
Widget build(BuildContext context) {
var instanceController = useTextEditingController();
useValueListenable(instanceController);
var loading = useState(false);
2020-09-08 16:41:46 +02:00
handleOnAdd() async {
try {
loading.value = true;
await context
.read<AccountsStore>()
.addInstance(instanceController.text);
scaffoldKey.currentState.hideCurrentSnackBar();
} on Exception catch (err) {
scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(err.toString()),
));
}
loading.value = false;
Navigator.of(context).pop();
}
2020-09-08 01:27:02 +02:00
return AlertDialog(
title: Text('Add instance'),
content: TextField(
autofocus: true,
controller: instanceController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Instance url',
),
),
actions: <Widget>[
FlatButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
2020-09-08 01:27:02 +02:00
FlatButton(
child: !loading.value ? Text('Add') : CircularProgressIndicator(),
2020-09-08 16:41:46 +02:00
onPressed: instanceController.text.isEmpty ? null : handleOnAdd,
2020-09-08 01:27:02 +02:00
),
],
);
}
}
class _AccountsConfigAddAccountDialog extends HookWidget {
final GlobalKey<ScaffoldState> scaffoldKey;
final String instanceUrl;
const _AccountsConfigAddAccountDialog(
{@required this.scaffoldKey, @required this.instanceUrl})
: assert(scaffoldKey != null),
assert(instanceUrl != null);
@override
Widget build(BuildContext context) {
var usernameController = useTextEditingController();
var passwordController = useTextEditingController();
useValueListenable(usernameController);
useValueListenable(passwordController);
var loading = useState(false);
2020-09-08 16:41:46 +02:00
handleOnAdd() async {
try {
loading.value = true;
await context.read<AccountsStore>().addAccount(
instanceUrl,
usernameController.text,
passwordController.text,
);
} on Exception catch (err) {
scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(err.toString()),
));
}
loading.value = false;
Navigator.of(context).pop();
}
2020-09-08 01:27:02 +02:00
return AlertDialog(
title: Text('Add account'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
autofocus: true,
controller: usernameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Username or email',
),
),
const SizedBox(height: 5),
TextField(
controller: passwordController,
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
),
),
],
),
actions: <Widget>[
FlatButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
2020-09-08 01:27:02 +02:00
FlatButton(
child: !loading.value ? Text('Add') : CircularProgressIndicator(),
onPressed:
usernameController.text.isEmpty || passwordController.text.isEmpty
? null
2020-09-08 16:41:46 +02:00
: handleOnAdd,
2020-09-08 01:27:02 +02:00
),
],
);
}
}
2020-09-03 23:14:26 +02:00
class _SectionHeading extends StatelessWidget {
final String text;
const _SectionHeading(this.text);
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Padding(
child: Text(text.toUpperCase(),
style: theme.textTheme.subtitle2.copyWith(color: theme.accentColor)),
padding: EdgeInsets.only(left: 20, top: 40),
);
}
}