Browse Source

Merge pull request #120 from provokateurin/fix/notes-editing

Fix note editing problems
pull/122/head
Kate 2 years ago committed by GitHub
parent
commit
60165edccf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/neon/lib/src/apps/notes/app.dart
  2. 83
      packages/neon/lib/src/apps/notes/blocs/note.dart
  3. 70
      packages/neon/lib/src/apps/notes/blocs/note.rxb.g.dart
  4. 49
      packages/neon/lib/src/apps/notes/pages/note.dart

1
packages/neon/lib/src/apps/notes/app.dart

@ -1,6 +1,5 @@
library notes;
import 'dart:async';
import 'dart:convert';
import 'package:crypto/crypto.dart';

83
packages/neon/lib/src/apps/notes/blocs/note.dart

@ -4,20 +4,18 @@ import 'package:neon/src/apps/notes/app.dart';
import 'package:neon/src/apps/notes/blocs/notes.dart';
import 'package:neon/src/neon.dart';
import 'package:nextcloud/nextcloud.dart';
import 'package:queue/queue.dart';
import 'package:rx_bloc/rx_bloc.dart';
import 'package:rxdart/rxdart.dart';
part 'note.rxb.g.dart';
abstract class NotesNoteBlocEvents {
void updateNote(
final int id,
final String etag, {
final String? title,
final String? category,
final String? content,
final bool? favorite,
});
void updateContent(final String content);
void updateTitle(final String title);
void updateCategory(final String category);
}
abstract class NotesNoteBlocStates {
@ -27,8 +25,6 @@ abstract class NotesNoteBlocStates {
BehaviorSubject<String> get category;
BehaviorSubject<String> get etag;
Stream<Exception> get errors;
}
@ -41,52 +37,69 @@ class NotesNoteBloc extends $NotesNoteBloc {
this._notesBloc,
final NotesNote note,
) {
_$updateNoteEvent.listen((final event) {
_$updateContentEvent.debounceTime(const Duration(seconds: 1)).listen((final content) {
_wrapAction(
(final etag) async => _client.notes.updateNote(
id: id,
content: content,
ifMatch: '"$etag"',
),
);
});
_$updateTitleEvent.debounceTime(const Duration(seconds: 1)).listen((final title) {
_wrapAction(
(final etag) async => _client.notes.updateNote(
id: id,
title: title,
ifMatch: '"$etag"',
),
);
});
_$updateCategoryEvent.listen((final category) {
_wrapAction(
() async {
_emitNote(
await _client.notes.updateNote(
id: event.id,
title: event.title,
category: event.category,
content: event.content,
favorite: event.favorite ?? false ? 1 : 0,
ifMatch: '"${event.etag}"',
),
);
},
(final etag) async => _client.notes.updateNote(
id: id,
category: category,
ifMatch: '"$etag"',
),
);
});
_contentSubject.add(note.content);
_titleSubject.add(note.title);
_emitNote(note);
id = note.id;
}
void _emitNote(final NotesNote note) {
_contentSubject.add(note.content);
_titleSubject.add(note.title);
_categorySubject.add(note.category);
_etagSubject.add(note.etag);
_etag = note.etag;
}
void _wrapAction(final Future Function() call) {
final stream = _requestManager.wrapWithoutCache(call).asBroadcastStream();
stream.whereError().listen(_errorsStreamController.add);
stream.whereSuccess().listen((final _) async {
_notesBloc.refresh();
});
void _wrapAction(final Future<NotesNote> Function(String etag) call) {
unawaited(
_updateQueue.add(() async {
final stream = _requestManager.wrapWithoutCache(() async => _emitNote(await call(_etag))).asBroadcastStream();
stream.whereError().listen(_errorsStreamController.add);
stream.whereSuccess().listen((final _) => _notesBloc.refresh());
await stream.last;
}),
);
}
final NotesAppSpecificOptions options;
final RequestManager _requestManager;
final NextcloudClient _client;
final NotesBloc _notesBloc;
final _updateQueue = Queue();
late final int id;
late String _etag;
final _contentSubject = BehaviorSubject<String>();
final _titleSubject = BehaviorSubject<String>();
final _categorySubject = BehaviorSubject<String>();
final _etagSubject = BehaviorSubject<String>();
final _errorsStreamController = StreamController<Exception>();
@override
@ -94,7 +107,6 @@ class NotesNoteBloc extends $NotesNoteBloc {
unawaited(_contentSubject.close());
unawaited(_titleSubject.close());
unawaited(_categorySubject.close());
unawaited(_etagSubject.close());
unawaited(_errorsStreamController.close());
super.dispose();
}
@ -110,7 +122,4 @@ class NotesNoteBloc extends $NotesNoteBloc {
@override
BehaviorSubject<String> _mapToCategoryState() => _categorySubject;
@override
BehaviorSubject<String> _mapToEtagState() => _etagSubject;
}

70
packages/neon/lib/src/apps/notes/blocs/note.rxb.g.dart

@ -19,8 +19,14 @@ abstract class $NotesNoteBloc extends RxBlocBase
implements NotesNoteBlocEvents, NotesNoteBlocStates, NotesNoteBlocType {
final _compositeSubscription = CompositeSubscription();
/// Тhe [Subject] where events sink to by calling [updateNote]
final _$updateNoteEvent = PublishSubject<_UpdateNoteEventArgs>();
/// Тhe [Subject] where events sink to by calling [updateContent]
final _$updateContentEvent = PublishSubject<String>();
/// Тhe [Subject] where events sink to by calling [updateTitle]
final _$updateTitleEvent = PublishSubject<String>();
/// Тhe [Subject] where events sink to by calling [updateCategory]
final _$updateCategoryEvent = PublishSubject<String>();
/// The state of [content] implemented in [_mapToContentState]
late final BehaviorSubject<String> _contentState = _mapToContentState();
@ -31,29 +37,17 @@ abstract class $NotesNoteBloc extends RxBlocBase
/// The state of [category] implemented in [_mapToCategoryState]
late final BehaviorSubject<String> _categoryState = _mapToCategoryState();
/// The state of [etag] implemented in [_mapToEtagState]
late final BehaviorSubject<String> _etagState = _mapToEtagState();
/// The state of [errors] implemented in [_mapToErrorsState]
late final Stream<Exception> _errorsState = _mapToErrorsState();
@override
void updateNote(
int id,
String etag, {
String? title,
String? category,
String? content,
bool? favorite,
}) =>
_$updateNoteEvent.add(_UpdateNoteEventArgs(
id,
etag,
title: title,
category: category,
content: content,
favorite: favorite,
));
void updateContent(String content) => _$updateContentEvent.add(content);
@override
void updateTitle(String title) => _$updateTitleEvent.add(title);
@override
void updateCategory(String category) => _$updateCategoryEvent.add(category);
@override
BehaviorSubject<String> get content => _contentState;
@ -64,9 +58,6 @@ abstract class $NotesNoteBloc extends RxBlocBase
@override
BehaviorSubject<String> get category => _categoryState;
@override
BehaviorSubject<String> get etag => _etagState;
@override
Stream<Exception> get errors => _errorsState;
@ -76,8 +67,6 @@ abstract class $NotesNoteBloc extends RxBlocBase
BehaviorSubject<String> _mapToCategoryState();
BehaviorSubject<String> _mapToEtagState();
Stream<Exception> _mapToErrorsState();
@override
@ -88,33 +77,10 @@ abstract class $NotesNoteBloc extends RxBlocBase
@override
void dispose() {
_$updateNoteEvent.close();
_$updateContentEvent.close();
_$updateTitleEvent.close();
_$updateCategoryEvent.close();
_compositeSubscription.dispose();
super.dispose();
}
}
/// Helps providing the arguments in the [Subject.add] for
/// [NotesNoteBlocEvents.updateNote] event
class _UpdateNoteEventArgs {
const _UpdateNoteEventArgs(
this.id,
this.etag, {
this.title,
this.category,
this.content,
this.favorite,
});
final int id;
final String etag;
final String? title;
final String? category;
final String? content;
final bool? favorite;
}

49
packages/neon/lib/src/apps/notes/pages/note.dart

@ -19,7 +19,6 @@ class _NotesNotePageState extends State<NotesNotePage> {
late final _titleController = TextEditingController();
final _contentFocusNode = FocusNode();
final _titleFocusNode = FocusNode();
final _updateController = StreamController();
bool _showEditor = false;
void _focusEditor() {
@ -27,24 +26,6 @@ class _NotesNotePageState extends State<NotesNotePage> {
_contentController.selection = TextSelection.collapsed(offset: _contentController.text.length);
}
Future _update({
final String? category,
}) async {
final updatedTitle = await widget.bloc.title.first != _titleController.text ? _titleController.text : null;
final updatedCategory = category != null && await widget.bloc.category.first != category ? category : null;
final updatedContent = await widget.bloc.content.first != _contentController.text ? _contentController.text : null;
if (updatedTitle != null || updatedCategory != null || updatedContent != null) {
widget.bloc.updateNote(
widget.bloc.id,
await widget.bloc.etag.first,
title: updatedTitle,
category: updatedCategory,
content: updatedContent,
);
}
}
@override
void initState() {
super.initState();
@ -71,9 +52,16 @@ class _NotesNotePageState extends State<NotesNotePage> {
}
});
_contentController.addListener(() => _updateController.add(null));
_titleController.addListener(() => _updateController.add(null));
_updateController.stream.debounceTime(const Duration(seconds: 1)).listen((final _) async => _update());
_contentController.addListener(() async {
if (await widget.bloc.content.first != _contentController.text) {
widget.bloc.updateContent(_contentController.text);
}
});
_titleController.addListener(() async {
if (await widget.bloc.title.first != _titleController.text) {
widget.bloc.updateTitle(_titleController.text);
}
});
WidgetsBinding.instance.addPostFrameCallback((final _) async {
if (Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
@ -89,27 +77,16 @@ class _NotesNotePageState extends State<NotesNotePage> {
});
}
@override
void dispose() {
unawaited(_updateController.close());
super.dispose();
}
@override
Widget build(final BuildContext context) => WillPopScope(
onWillPop: () async {
await _update();
if (!mounted) {
return true;
}
if (Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
await Wakelock.disable();
}
return true;
},
child: Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomInset: true,
appBar: AppBar(
titleSpacing: 0,
title: TextField(
@ -159,9 +136,7 @@ class _NotesNotePageState extends State<NotesNotePage> {
),
);
if (result != null) {
await _update(
category: result,
);
widget.bloc.updateCategory(result);
}
},
icon: Icon(

Loading…
Cancel
Save