135 lines
4 KiB
Dart
135 lines
4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../models/tracker.dart';
|
|
import '../services/tracker_service.dart';
|
|
import '../widgets/theme.dart';
|
|
|
|
class CreateTrackerScreen extends ConsumerStatefulWidget {
|
|
const CreateTrackerScreen({super.key, this.existing});
|
|
|
|
final Tracker? existing;
|
|
|
|
@override
|
|
ConsumerState<CreateTrackerScreen> createState() =>
|
|
_CreateTrackerScreenState();
|
|
}
|
|
|
|
class _CreateTrackerScreenState extends ConsumerState<CreateTrackerScreen> {
|
|
late final TextEditingController _nameController;
|
|
late Color _color;
|
|
bool _saving = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_nameController = TextEditingController(text: widget.existing?.name ?? '');
|
|
_color = widget.existing != null
|
|
? Color(widget.existing!.colorValue)
|
|
: AppTokens.trackerPalette.first;
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_nameController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _save() async {
|
|
final String name = _nameController.text.trim();
|
|
if (name.isEmpty) return;
|
|
setState(() => _saving = true);
|
|
final TrackerService service = ref.read(trackerServiceProvider.notifier);
|
|
if (widget.existing == null) {
|
|
await service.create(name: name, color: _color);
|
|
} else {
|
|
await service.updateMeta(widget.existing!.id, name: name, color: _color);
|
|
}
|
|
if (!mounted) return;
|
|
Navigator.of(context).pop();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final bool isEditing = widget.existing != null;
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(isEditing ? 'Edit Tracker' : 'New Tracker')),
|
|
body: SingleChildScrollView(
|
|
padding: const EdgeInsets.all(AppTokens.spaceL),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: <Widget>[
|
|
TextField(
|
|
controller: _nameController,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Name',
|
|
hintText: 'e.g. My First Read-Through',
|
|
border: OutlineInputBorder(),
|
|
),
|
|
textInputAction: TextInputAction.done,
|
|
autofocus: !isEditing,
|
|
),
|
|
const SizedBox(height: AppTokens.spaceXL),
|
|
Text('Color', style: Theme.of(context).textTheme.titleMedium),
|
|
const SizedBox(height: AppTokens.spaceM),
|
|
Wrap(
|
|
spacing: AppTokens.spaceM,
|
|
runSpacing: AppTokens.spaceM,
|
|
children: <Widget>[
|
|
for (final Color option in AppTokens.trackerPalette)
|
|
_ColorSwatch(
|
|
color: option,
|
|
selected: option.toARGB32() == _color.toARGB32(),
|
|
onTap: () => setState(() => _color = option),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: AppTokens.spaceXXL),
|
|
FilledButton(
|
|
onPressed: _saving ? null : _save,
|
|
style: FilledButton.styleFrom(backgroundColor: _color),
|
|
child: Text(isEditing ? 'Save Changes' : 'Create Tracker'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _ColorSwatch extends StatelessWidget {
|
|
const _ColorSwatch({
|
|
required this.color,
|
|
required this.selected,
|
|
required this.onTap,
|
|
});
|
|
|
|
final Color color;
|
|
final bool selected;
|
|
final VoidCallback onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return InkResponse(
|
|
onTap: onTap,
|
|
radius: 32,
|
|
child: Container(
|
|
width: 44,
|
|
height: 44,
|
|
decoration: BoxDecoration(
|
|
color: color,
|
|
shape: BoxShape.circle,
|
|
border: Border.all(
|
|
color: selected
|
|
? Theme.of(context).colorScheme.onSurface
|
|
: Colors.transparent,
|
|
width: 3,
|
|
),
|
|
),
|
|
child: selected
|
|
? const Icon(Icons.check, color: Colors.white, size: 20)
|
|
: null,
|
|
),
|
|
);
|
|
}
|
|
}
|