diff --git a/lib/model/image_entry.dart b/lib/model/image_entry.dart index 76dbcff41..48b1cb965 100644 --- a/lib/model/image_entry.dart +++ b/lib/model/image_entry.dart @@ -10,16 +10,14 @@ import 'package:aves/utils/time_utils.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:geocoder/geocoder.dart'; -import 'package:path/path.dart'; +import 'package:path/path.dart' as ppath; import 'package:tuple/tuple.dart'; import 'mime_types.dart'; class ImageEntry { String uri; - String _path; - String _directory; - String _filename; + String _path, _directory, _filename, _extension; int contentId; final String sourceMimeType; int width; @@ -131,20 +129,26 @@ class ImageEntry { _path = path; _directory = null; _filename = null; + _extension = null; } String get path => _path; String get directory { - _directory ??= path != null ? dirname(path) : null; + _directory ??= path != null ? ppath.dirname(path) : null; return _directory; } String get filenameWithoutExtension { - _filename ??= path != null ? basenameWithoutExtension(path) : null; + _filename ??= path != null ? ppath.basenameWithoutExtension(path) : null; return _filename; } + String get extension { + _extension ??= path != null ? ppath.extension(path) : null; + return _extension; + } + // the MIME type reported by the Media Store is unreliable // so we use the one found during cataloguing if possible String get mimeType => catalogMetadata?.mimeType ?? sourceMimeType; @@ -318,7 +322,7 @@ class ImageEntry { Future rename(String newName) async { if (newName == filenameWithoutExtension) return true; - final newFields = await ImageFileService.rename(this, '$newName${extension(this.path)}'); + final newFields = await ImageFileService.rename(this, '$newName$extension'); if (newFields.isEmpty) return false; final uri = newFields['uri']; diff --git a/lib/widgets/common/action_delegates/create_album_dialog.dart b/lib/widgets/common/action_delegates/create_album_dialog.dart index d4a3ef0f5..87e943911 100644 --- a/lib/widgets/common/action_delegates/create_album_dialog.dart +++ b/lib/widgets/common/action_delegates/create_album_dialog.dart @@ -77,6 +77,7 @@ class _CreateAlbumDialogState extends State { helperText: exists ? 'Album already exists' : '', hintText: 'Album name', ), + autofocus: _allVolumes.length == 1, onChanged: (_) => _validate(), onSubmitted: (_) => _submit(context), ); @@ -96,7 +97,7 @@ class _CreateAlbumDialogState extends State { child: Text('Create'.toUpperCase()), ); }, - ) + ), ], ); } diff --git a/lib/widgets/common/action_delegates/rename_entry_dialog.dart b/lib/widgets/common/action_delegates/rename_entry_dialog.dart index 4e3106a47..766566caf 100644 --- a/lib/widgets/common/action_delegates/rename_entry_dialog.dart +++ b/lib/widgets/common/action_delegates/rename_entry_dialog.dart @@ -1,5 +1,8 @@ +import 'dart:io'; + import 'package:aves/model/image_entry.dart'; import 'package:flutter/material.dart'; +import 'package:path/path.dart'; import '../aves_dialog.dart'; @@ -14,11 +17,13 @@ class RenameEntryDialog extends StatefulWidget { class _RenameEntryDialogState extends State { final TextEditingController _nameController = TextEditingController(); + final ValueNotifier _isValidNotifier = ValueNotifier(false); + + ImageEntry get entry => widget.entry; @override void initState() { super.initState(); - final entry = widget.entry; _nameController.text = entry.filenameWithoutExtension ?? entry.sourceTitle; } @@ -34,17 +39,35 @@ class _RenameEntryDialogState extends State { content: TextField( controller: _nameController, autofocus: true, + onChanged: (_) => _validate(), + onSubmitted: (_) => _submit(context), ), actions: [ FlatButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'.toUpperCase()), ), - FlatButton( - onPressed: () => Navigator.pop(context, _nameController.text), - child: Text('Apply'.toUpperCase()), - ), + ValueListenableBuilder( + valueListenable: _isValidNotifier, + builder: (context, isValid, child) { + return FlatButton( + onPressed: isValid ? () => _submit(context) : null, + child: Text('Apply'.toUpperCase()), + ); + }, + ) ], ); } + + Future _validate() async { + var newName = _nameController.text ?? ''; + if (newName.isNotEmpty) { + newName += entry.extension; + } + final type = await FileSystemEntity.type(join(entry.directory, newName)); + _isValidNotifier.value = type == FileSystemEntityType.notFound; + } + + void _submit(BuildContext context) => Navigator.pop(context, _nameController.text); }