[ui] UI theme should match repertory blue #61
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
This commit is contained in:
@@ -8,6 +8,30 @@ import 'package:repertory/constants.dart' as constants;
|
|||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:sodium_libs/sodium_libs.dart' show SecureKey, StringX;
|
import 'package:sodium_libs/sodium_libs.dart' show SecureKey, StringX;
|
||||||
|
|
||||||
|
Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scheme = theme.colorScheme;
|
||||||
|
return Theme(
|
||||||
|
data: theme.copyWith(
|
||||||
|
dialogTheme: DialogThemeData(
|
||||||
|
backgroundColor: scheme.primary.withValues(alpha: 0.15),
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
side: BorderSide(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
typedef Validator = bool Function(String);
|
typedef Validator = bool Function(String);
|
||||||
|
|
||||||
class NullPasswordException implements Exception {
|
class NullPasswordException implements Exception {
|
||||||
@@ -347,98 +371,52 @@ Future<String?> editMountLocation(
|
|||||||
}) async {
|
}) async {
|
||||||
String? currentLocation = location;
|
String? currentLocation = location;
|
||||||
final controller = TextEditingController(text: currentLocation);
|
final controller = TextEditingController(text: currentLocation);
|
||||||
return await showDialog(
|
return await doShowDialog(
|
||||||
context: context,
|
context,
|
||||||
builder: (context) {
|
StatefulBuilder(
|
||||||
var theme = Theme.of(context);
|
builder: (context, setState) {
|
||||||
var scheme = theme.colorScheme;
|
return AlertDialog(
|
||||||
return Theme(
|
actions: [
|
||||||
data: theme.copyWith(
|
TextButton(
|
||||||
dialogTheme: DialogThemeData(
|
child: const Text('Cancel'),
|
||||||
backgroundColor: scheme.surface.withValues(alpha: 0.40),
|
onPressed: () => Navigator.of(context).pop(null),
|
||||||
surfaceTintColor: Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
|
||||||
side: BorderSide(
|
|
||||||
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
TextButton(
|
||||||
),
|
child: const Text('OK'),
|
||||||
child: StatefulBuilder(
|
onPressed: () {
|
||||||
builder: (context, setState) {
|
final result = getSettingValidators('Path').firstWhereOrNull(
|
||||||
return AlertDialog(
|
(validator) => !validator(currentLocation ?? ''),
|
||||||
actions: [
|
);
|
||||||
TextButton(
|
if (result != null) {
|
||||||
child: const Text('Cancel'),
|
return displayErrorMessage(
|
||||||
onPressed: () => Navigator.of(context).pop(null),
|
context,
|
||||||
|
"Mount location is not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop(currentLocation);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
content: available.isEmpty
|
||||||
|
? TextField(
|
||||||
|
autofocus: true,
|
||||||
|
controller: controller,
|
||||||
|
onChanged: (value) => setState(() => currentLocation = value),
|
||||||
|
)
|
||||||
|
: DropdownButton<String>(
|
||||||
|
hint: const Text("Select drive"),
|
||||||
|
value: currentLocation,
|
||||||
|
onChanged: (value) => setState(() => currentLocation = value),
|
||||||
|
items: available.map<DropdownMenuItem<String>>((item) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: item,
|
||||||
|
child: Text(item),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
TextButton(
|
title: const Text('Mount Location', textAlign: TextAlign.center),
|
||||||
child: const Text('OK'),
|
);
|
||||||
onPressed: () {
|
},
|
||||||
final result = getSettingValidators('Path')
|
),
|
||||||
.firstWhereOrNull(
|
|
||||||
(validator) => !validator(currentLocation ?? ''),
|
|
||||||
);
|
|
||||||
if (result != null) {
|
|
||||||
return displayErrorMessage(
|
|
||||||
context,
|
|
||||||
"Mount location is not valid",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop(currentLocation);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
content: available.isEmpty
|
|
||||||
? TextField(
|
|
||||||
autofocus: true,
|
|
||||||
controller: controller,
|
|
||||||
onChanged: (value) =>
|
|
||||||
setState(() => currentLocation = value),
|
|
||||||
)
|
|
||||||
: DropdownButton<String>(
|
|
||||||
hint: const Text("Select drive"),
|
|
||||||
value: currentLocation,
|
|
||||||
onChanged: (value) =>
|
|
||||||
setState(() => currentLocation = value),
|
|
||||||
items: available.map<DropdownMenuItem<String>>((item) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: item,
|
|
||||||
child: Text(item),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
title: const Text('Mount Location', textAlign: TextAlign.center),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final scheme = theme.colorScheme;
|
|
||||||
return Theme(
|
|
||||||
data: theme.copyWith(
|
|
||||||
dialogTheme: DialogThemeData(
|
|
||||||
backgroundColor: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
surfaceTintColor: Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
|
||||||
side: BorderSide(
|
|
||||||
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
@@ -8,6 +8,7 @@ import 'package:repertory/models/auth.dart';
|
|||||||
class Settings with ChangeNotifier {
|
class Settings with ChangeNotifier {
|
||||||
final Auth _auth;
|
final Auth _auth;
|
||||||
bool _autoStart = false;
|
bool _autoStart = false;
|
||||||
|
bool _enableAnimations = true;
|
||||||
|
|
||||||
Settings(this._auth) {
|
Settings(this._auth) {
|
||||||
_auth.addListener(() {
|
_auth.addListener(() {
|
||||||
@@ -18,6 +19,11 @@ class Settings with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get autoStart => _autoStart;
|
bool get autoStart => _autoStart;
|
||||||
|
bool get enableAnimations => _enableAnimations;
|
||||||
|
set enableAnimations(bool enable) {
|
||||||
|
_enableAnimations = enable;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void _reset() {
|
void _reset() {
|
||||||
_autoStart = false;
|
_autoStart = false;
|
||||||
|
@@ -9,6 +9,7 @@ import 'package:repertory/helpers.dart';
|
|||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/mount.dart';
|
import 'package:repertory/models/mount.dart';
|
||||||
import 'package:repertory/models/mount_list.dart';
|
import 'package:repertory/models/mount_list.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/types/mount_config.dart';
|
import 'package:repertory/types/mount_config.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
@@ -92,11 +93,10 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const AuroraSweep(
|
Consumer<Settings>(
|
||||||
enabled: true,
|
builder: (_, settings, _) {
|
||||||
duration: Duration(seconds: 28),
|
return AuroraSweep(enabled: settings.enableAnimations);
|
||||||
primaryAlphaA: 0.04,
|
},
|
||||||
primaryAlphaB: 0.03,
|
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
@@ -214,7 +214,7 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: constants.padding),
|
const SizedBox(width: constants.padding),
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
value: _mountType,
|
value: _mountType.isEmpty ? null : _mountType,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
underline: const SizedBox.shrink(),
|
underline: const SizedBox.shrink(),
|
||||||
onChanged: (mountType) {
|
onChanged: (mountType) {
|
||||||
@@ -298,99 +298,108 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
const SizedBox(height: constants.padding),
|
const SizedBox(height: constants.padding),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
IntrinsicWidth(
|
||||||
label: const Text('Test'),
|
child: ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.check),
|
label: const Text('Test'),
|
||||||
style: ElevatedButton.styleFrom(
|
icon: const Icon(Icons.check),
|
||||||
backgroundColor: scheme.primary.withValues(
|
style: ElevatedButton.styleFrom(
|
||||||
alpha: 0.18,
|
backgroundColor: scheme.primary.withValues(
|
||||||
),
|
alpha: 0.18,
|
||||||
foregroundColor: scheme.primary,
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
),
|
||||||
side: BorderSide(
|
foregroundColor: scheme.primary,
|
||||||
color: scheme.outlineVariant.withValues(
|
elevation: 0,
|
||||||
alpha: 0.15,
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
side: BorderSide(
|
||||||
|
color: scheme.outlineVariant.withValues(
|
||||||
|
alpha: 0.15,
|
||||||
|
),
|
||||||
|
width: 1,
|
||||||
),
|
),
|
||||||
width: 1,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onPressed: _handleProviderTest,
|
||||||
),
|
),
|
||||||
onPressed: _handleProviderTest,
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: constants.padding),
|
const SizedBox(width: constants.padding),
|
||||||
ElevatedButton.icon(
|
IntrinsicWidth(
|
||||||
label: const Text('Add'),
|
child: ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.add),
|
label: const Text('Add'),
|
||||||
style: ElevatedButton.styleFrom(
|
icon: const Icon(Icons.add),
|
||||||
backgroundColor: scheme.primary,
|
style: ElevatedButton.styleFrom(
|
||||||
foregroundColor: scheme.onPrimary,
|
backgroundColor: scheme.primary,
|
||||||
elevation: 8,
|
foregroundColor: scheme.onPrimary,
|
||||||
shadowColor: scheme.primary.withValues(alpha: 0.45),
|
elevation: 8,
|
||||||
shape: RoundedRectangleBorder(
|
shadowColor: scheme.primary.withValues(
|
||||||
borderRadius: BorderRadius.circular(
|
alpha: 0.45,
|
||||||
constants.borderRadius,
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
onPressed: () async {
|
||||||
onPressed: () async {
|
final mountList = Provider.of<MountList>(
|
||||||
final mountList = Provider.of<MountList>(
|
|
||||||
context,
|
|
||||||
listen: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
List<String> failed = [];
|
|
||||||
if (!validateSettings(
|
|
||||||
_settings[_mountType]!,
|
|
||||||
failed,
|
|
||||||
)) {
|
|
||||||
for (var key in failed) {
|
|
||||||
displayErrorMessage(
|
|
||||||
context,
|
|
||||||
"Setting '$key' is not valid",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mountList.hasConfigName(
|
|
||||||
_mountNameController.text,
|
|
||||||
)) {
|
|
||||||
return displayErrorMessage(
|
|
||||||
context,
|
context,
|
||||||
"Configuration name '${_mountNameController.text}' already exists",
|
listen: false,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (_mountType == "Sia" || _mountType == "S3") {
|
List<String> failed = [];
|
||||||
final bucket =
|
if (!validateSettings(
|
||||||
_settings[_mountType]!["${_mountType}Config"]["Bucket"]
|
_settings[_mountType]!,
|
||||||
as String;
|
failed,
|
||||||
if (mountList.hasBucketName(_mountType, bucket)) {
|
)) {
|
||||||
|
for (var key in failed) {
|
||||||
|
displayErrorMessage(
|
||||||
|
context,
|
||||||
|
"Setting '$key' is not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mountList.hasConfigName(
|
||||||
|
_mountNameController.text,
|
||||||
|
)) {
|
||||||
return displayErrorMessage(
|
return displayErrorMessage(
|
||||||
context,
|
context,
|
||||||
"Bucket '$bucket' already exists",
|
"Configuration name '${_mountNameController.text}' already exists",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final success = await mountList.add(
|
if (_mountType == "Sia" || _mountType == "S3") {
|
||||||
_mountType,
|
final bucket =
|
||||||
_mountType == 'Remote'
|
_settings[_mountType]!["${_mountType}Config"]["Bucket"]
|
||||||
? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}'
|
as String;
|
||||||
: _mountNameController.text,
|
if (mountList.hasBucketName(
|
||||||
_settings[_mountType]!,
|
_mountType,
|
||||||
);
|
bucket,
|
||||||
|
)) {
|
||||||
|
return displayErrorMessage(
|
||||||
|
context,
|
||||||
|
"Bucket '$bucket' already exists",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!success || !context.mounted) {
|
final success = await mountList.add(
|
||||||
return;
|
_mountType,
|
||||||
}
|
_mountType == 'Remote'
|
||||||
|
? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}'
|
||||||
|
: _mountNameController.text,
|
||||||
|
_settings[_mountType]!,
|
||||||
|
);
|
||||||
|
|
||||||
Navigator.pop(context);
|
if (!success || !context.mounted) {
|
||||||
},
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
|
|
||||||
class AuthScreen extends StatefulWidget {
|
class AuthScreen extends StatefulWidget {
|
||||||
@@ -97,7 +98,11 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const AuroraSweep(),
|
Consumer<Settings>(
|
||||||
|
builder: (_, settings, _) {
|
||||||
|
return AuroraSweep(enabled: settings.enableAnimations);
|
||||||
|
},
|
||||||
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||||
|
@@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/mount.dart';
|
import 'package:repertory/models/mount.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
@@ -43,11 +44,10 @@ class _EditMountScreenState extends State<EditMountScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const AuroraSweep(
|
Consumer<Settings>(
|
||||||
enabled: true,
|
builder: (_, settings, _) {
|
||||||
duration: Duration(seconds: 28),
|
return AuroraSweep(enabled: settings.enableAnimations);
|
||||||
primaryAlphaA: 0.04,
|
},
|
||||||
primaryAlphaB: 0.03,
|
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
|
@@ -9,6 +9,7 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/helpers.dart';
|
import 'package:repertory/helpers.dart';
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
import 'package:repertory/widgets/ui_settings.dart';
|
import 'package:repertory/widgets/ui_settings.dart';
|
||||||
|
|
||||||
@@ -41,11 +42,10 @@ class _EditSettingsScreenState extends State<EditSettingsScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const AuroraSweep(
|
Consumer<Settings>(
|
||||||
enabled: true,
|
builder: (_, settings, _) {
|
||||||
duration: Duration(seconds: 28),
|
return AuroraSweep(enabled: settings.enableAnimations);
|
||||||
primaryAlphaA: 0.04,
|
},
|
||||||
primaryAlphaB: 0.03,
|
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
|
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/mount_list_widget.dart';
|
import 'package:repertory/widgets/mount_list_widget.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
|
|
||||||
@@ -37,11 +38,10 @@ class _HomeScreeState extends State<HomeScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const AuroraSweep(
|
Consumer<Settings>(
|
||||||
enabled: true,
|
builder: (_, settings, _) {
|
||||||
duration: Duration(seconds: 28),
|
return AuroraSweep(enabled: settings.enableAnimations);
|
||||||
primaryAlphaA: 0.04,
|
},
|
||||||
primaryAlphaB: 0.03,
|
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
|
Reference in New Issue
Block a user