mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[flutter]: close stream before docpage dispose
This commit is contained in:
parent
7730539278
commit
c4a6342c96
@ -28,12 +28,7 @@ class DocBloc extends Bloc<DocEvent, DocState> {
|
||||
final docOrFail = await iDocImpl.readDoc();
|
||||
yield docOrFail.fold(
|
||||
(doc) {
|
||||
final flowyDoc = FlowyDoc(
|
||||
doc: doc,
|
||||
data: _decodeJsonToDocument(
|
||||
doc.data,
|
||||
),
|
||||
iDocImpl: iDocImpl);
|
||||
final flowyDoc = FlowyDoc(doc: doc, iDocImpl: iDocImpl);
|
||||
return DocState.loadDoc(flowyDoc);
|
||||
},
|
||||
(error) {
|
||||
|
@ -12,24 +12,17 @@ class DocEditBloc extends Bloc<DocEditEvent, DocEditState> {
|
||||
@override
|
||||
Stream<DocEditState> mapEventToState(DocEditEvent event) async* {
|
||||
yield* event.map(
|
||||
initial: (e) async* {},
|
||||
close: (Close value) async* {
|
||||
iDocImpl.closeDoc();
|
||||
},
|
||||
changeset: (Changeset changeset) async* {
|
||||
iDocImpl.applyChangeset(json: changeset.data);
|
||||
},
|
||||
save: (Save save) async* {
|
||||
// no need to save
|
||||
});
|
||||
initial: (e) async* {},
|
||||
close: (Close value) async* {
|
||||
iDocImpl.closeDoc();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class DocEditEvent with _$DocEditEvent {
|
||||
const factory DocEditEvent.initial() = Initial;
|
||||
const factory DocEditEvent.changeset(String data) = Changeset;
|
||||
const factory DocEditEvent.save(String data) = Save;
|
||||
const factory DocEditEvent.close() = Close;
|
||||
}
|
||||
|
||||
|
@ -20,18 +20,6 @@ class _$DocEditEventTearOff {
|
||||
return const Initial();
|
||||
}
|
||||
|
||||
Changeset changeset(String data) {
|
||||
return Changeset(
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
Save save(String data) {
|
||||
return Save(
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
Close close() {
|
||||
return const Close();
|
||||
}
|
||||
@ -45,16 +33,12 @@ mixin _$DocEditEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String data) changeset,
|
||||
required TResult Function(String data) save,
|
||||
required TResult Function() close,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String data)? changeset,
|
||||
TResult Function(String data)? save,
|
||||
TResult Function()? close,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
@ -62,16 +46,12 @@ mixin _$DocEditEvent {
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(Changeset value) changeset,
|
||||
required TResult Function(Save value) save,
|
||||
required TResult Function(Close value) close,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(Changeset value)? changeset,
|
||||
TResult Function(Save value)? save,
|
||||
TResult Function(Close value)? close,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
@ -132,8 +112,6 @@ class _$Initial implements Initial {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String data) changeset,
|
||||
required TResult Function(String data) save,
|
||||
required TResult Function() close,
|
||||
}) {
|
||||
return initial();
|
||||
@ -143,8 +121,6 @@ class _$Initial implements Initial {
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String data)? changeset,
|
||||
TResult Function(String data)? save,
|
||||
TResult Function()? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@ -158,8 +134,6 @@ class _$Initial implements Initial {
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(Changeset value) changeset,
|
||||
required TResult Function(Save value) save,
|
||||
required TResult Function(Close value) close,
|
||||
}) {
|
||||
return initial(this);
|
||||
@ -169,8 +143,6 @@ class _$Initial implements Initial {
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(Changeset value)? changeset,
|
||||
TResult Function(Save value)? save,
|
||||
TResult Function(Close value)? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@ -185,247 +157,6 @@ abstract class Initial implements DocEditEvent {
|
||||
const factory Initial() = _$Initial;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ChangesetCopyWith<$Res> {
|
||||
factory $ChangesetCopyWith(Changeset value, $Res Function(Changeset) then) =
|
||||
_$ChangesetCopyWithImpl<$Res>;
|
||||
$Res call({String data});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ChangesetCopyWithImpl<$Res> extends _$DocEditEventCopyWithImpl<$Res>
|
||||
implements $ChangesetCopyWith<$Res> {
|
||||
_$ChangesetCopyWithImpl(Changeset _value, $Res Function(Changeset) _then)
|
||||
: super(_value, (v) => _then(v as Changeset));
|
||||
|
||||
@override
|
||||
Changeset get _value => super._value as Changeset;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? data = freezed,
|
||||
}) {
|
||||
return _then(Changeset(
|
||||
data == freezed
|
||||
? _value.data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$Changeset implements Changeset {
|
||||
const _$Changeset(this.data);
|
||||
|
||||
@override
|
||||
final String data;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DocEditEvent.changeset(data: $data)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other is Changeset &&
|
||||
(identical(other.data, data) ||
|
||||
const DeepCollectionEquality().equals(other.data, data)));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
runtimeType.hashCode ^ const DeepCollectionEquality().hash(data);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
$ChangesetCopyWith<Changeset> get copyWith =>
|
||||
_$ChangesetCopyWithImpl<Changeset>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String data) changeset,
|
||||
required TResult Function(String data) save,
|
||||
required TResult Function() close,
|
||||
}) {
|
||||
return changeset(data);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String data)? changeset,
|
||||
TResult Function(String data)? save,
|
||||
TResult Function()? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (changeset != null) {
|
||||
return changeset(data);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(Changeset value) changeset,
|
||||
required TResult Function(Save value) save,
|
||||
required TResult Function(Close value) close,
|
||||
}) {
|
||||
return changeset(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(Changeset value)? changeset,
|
||||
TResult Function(Save value)? save,
|
||||
TResult Function(Close value)? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (changeset != null) {
|
||||
return changeset(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Changeset implements DocEditEvent {
|
||||
const factory Changeset(String data) = _$Changeset;
|
||||
|
||||
String get data => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$ChangesetCopyWith<Changeset> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $SaveCopyWith<$Res> {
|
||||
factory $SaveCopyWith(Save value, $Res Function(Save) then) =
|
||||
_$SaveCopyWithImpl<$Res>;
|
||||
$Res call({String data});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SaveCopyWithImpl<$Res> extends _$DocEditEventCopyWithImpl<$Res>
|
||||
implements $SaveCopyWith<$Res> {
|
||||
_$SaveCopyWithImpl(Save _value, $Res Function(Save) _then)
|
||||
: super(_value, (v) => _then(v as Save));
|
||||
|
||||
@override
|
||||
Save get _value => super._value as Save;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? data = freezed,
|
||||
}) {
|
||||
return _then(Save(
|
||||
data == freezed
|
||||
? _value.data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$Save implements Save {
|
||||
const _$Save(this.data);
|
||||
|
||||
@override
|
||||
final String data;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DocEditEvent.save(data: $data)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other is Save &&
|
||||
(identical(other.data, data) ||
|
||||
const DeepCollectionEquality().equals(other.data, data)));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
runtimeType.hashCode ^ const DeepCollectionEquality().hash(data);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
$SaveCopyWith<Save> get copyWith =>
|
||||
_$SaveCopyWithImpl<Save>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String data) changeset,
|
||||
required TResult Function(String data) save,
|
||||
required TResult Function() close,
|
||||
}) {
|
||||
return save(data);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String data)? changeset,
|
||||
TResult Function(String data)? save,
|
||||
TResult Function()? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (save != null) {
|
||||
return save(data);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(Changeset value) changeset,
|
||||
required TResult Function(Save value) save,
|
||||
required TResult Function(Close value) close,
|
||||
}) {
|
||||
return save(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(Changeset value)? changeset,
|
||||
TResult Function(Save value)? save,
|
||||
TResult Function(Close value)? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (save != null) {
|
||||
return save(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Save implements DocEditEvent {
|
||||
const factory Save(String data) = _$Save;
|
||||
|
||||
String get data => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$SaveCopyWith<Save> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CloseCopyWith<$Res> {
|
||||
factory $CloseCopyWith(Close value, $Res Function(Close) then) =
|
||||
@ -464,8 +195,6 @@ class _$Close implements Close {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String data) changeset,
|
||||
required TResult Function(String data) save,
|
||||
required TResult Function() close,
|
||||
}) {
|
||||
return close();
|
||||
@ -475,8 +204,6 @@ class _$Close implements Close {
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String data)? changeset,
|
||||
TResult Function(String data)? save,
|
||||
TResult Function()? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
@ -490,8 +217,6 @@ class _$Close implements Close {
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(Changeset value) changeset,
|
||||
required TResult Function(Save value) save,
|
||||
required TResult Function(Close value) close,
|
||||
}) {
|
||||
return close(this);
|
||||
@ -501,8 +226,6 @@ class _$Close implements Close {
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(Changeset value)? changeset,
|
||||
TResult Function(Save value)? save,
|
||||
TResult Function(Close value)? close,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flowy_editor/flowy_editor.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
// ignore: implementation_imports
|
||||
@ -8,40 +8,52 @@ import 'package:flowy_log/flowy_log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-document/doc.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
|
||||
|
||||
class FlowyDoc implements EditorDeltaSender {
|
||||
class FlowyDoc {
|
||||
final DocDelta doc;
|
||||
final IDoc iDocImpl;
|
||||
Document data;
|
||||
late Document document;
|
||||
late StreamSubscription _subscription;
|
||||
|
||||
FlowyDoc({required this.doc, required this.data, required this.iDocImpl}) {
|
||||
data.sender = this;
|
||||
FlowyDoc({required this.doc, required this.iDocImpl}) {
|
||||
document = _decodeJsonToDocument(doc.data);
|
||||
|
||||
_subscription = document.changes.listen((event) {
|
||||
final delta = event.item2;
|
||||
final documentDelta = document.toDelta();
|
||||
_composeDelta(delta, documentDelta);
|
||||
});
|
||||
}
|
||||
|
||||
String get id => doc.docId;
|
||||
|
||||
@override
|
||||
void sendNewDelta(Delta changeset, Delta delta) async {
|
||||
final json = jsonEncode(changeset.toJson());
|
||||
Future<void> close() async {
|
||||
await _subscription.cancel();
|
||||
}
|
||||
|
||||
void _composeDelta(Delta composedDelta, Delta documentDelta) async {
|
||||
final json = jsonEncode(composedDelta.toJson());
|
||||
Log.debug("Send json: $json");
|
||||
final result = await iDocImpl.applyChangeset(json: json);
|
||||
final result = await iDocImpl.composeDelta(json: json);
|
||||
|
||||
result.fold((rustDoc) {
|
||||
// final json = utf8.decode(doc.data);
|
||||
final rustDelta = Delta.fromJson(jsonDecode(rustDoc.data));
|
||||
|
||||
if (delta != rustDelta) {
|
||||
if (documentDelta != rustDelta) {
|
||||
Log.error("Receive : $rustDelta");
|
||||
Log.error("Expected : $delta");
|
||||
} else {
|
||||
Log.info("Receive : $rustDelta");
|
||||
Log.info("Expected : $delta");
|
||||
Log.error("Expected : $documentDelta");
|
||||
}
|
||||
}, (r) => null);
|
||||
}
|
||||
|
||||
Document _decodeJsonToDocument(String data) {
|
||||
final json = jsonDecode(data);
|
||||
final document = Document.fromJson(json);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class IDoc {
|
||||
Future<Either<DocDelta, WorkspaceError>> readDoc();
|
||||
Future<Either<DocDelta, WorkspaceError>> applyChangeset(
|
||||
{required String json});
|
||||
Future<Either<DocDelta, WorkspaceError>> composeDelta({required String json});
|
||||
Future<Either<Unit, WorkspaceError>> closeDoc();
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ class IDocImpl extends IDoc {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<DocDelta, WorkspaceError>> applyChangeset(
|
||||
Future<Either<DocDelta, WorkspaceError>> composeDelta(
|
||||
{required String json}) {
|
||||
return repo.applyDelta(data: json);
|
||||
return repo.composeDelta(data: json);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_log/flowy_log.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-document/doc.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
|
||||
@ -15,7 +16,8 @@ class DocRepository {
|
||||
return WorkspaceEventOpenView(request).send();
|
||||
}
|
||||
|
||||
Future<Either<DocDelta, WorkspaceError>> applyDelta({required String data}) {
|
||||
Future<Either<DocDelta, WorkspaceError>> composeDelta(
|
||||
{required String data}) {
|
||||
final request = DocDelta.create()
|
||||
..docId = docId
|
||||
..data = data;
|
||||
@ -24,6 +26,9 @@ class DocRepository {
|
||||
|
||||
Future<Either<Unit, WorkspaceError>> closeDoc(
|
||||
{String? name, String? desc, String? text}) {
|
||||
throw UnimplementedError();
|
||||
Log.error('Close the doc');
|
||||
return Future(() {
|
||||
return left(unit);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,31 +8,37 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class DocPage extends StatelessWidget {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
class DocPage extends StatefulWidget {
|
||||
late EditorController controller;
|
||||
late DocEditBloc editBloc;
|
||||
final FlowyDoc doc;
|
||||
|
||||
DocPage({Key? key, required this.doc}) : super(key: key) {
|
||||
// getIt<EditorDeltaSender>(param1: doc.id))
|
||||
|
||||
editBloc = getIt<DocEditBloc>(param1: doc.id);
|
||||
controller = EditorController(
|
||||
document: doc.data,
|
||||
document: doc.document,
|
||||
selection: const TextSelection.collapsed(offset: 0),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<DocPage> createState() => _DocPageState();
|
||||
}
|
||||
|
||||
class _DocPageState extends State<DocPage> {
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => getIt<DocEditBloc>(param1: doc.id),
|
||||
return BlocProvider.value(
|
||||
value: widget.editBloc,
|
||||
child: BlocBuilder<DocEditBloc, DocEditState>(
|
||||
builder: (ctx, state) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_renderEditor(controller),
|
||||
_renderToolbar(controller),
|
||||
_renderEditor(widget.controller),
|
||||
_renderToolbar(widget.controller),
|
||||
],
|
||||
);
|
||||
},
|
||||
@ -40,6 +46,14 @@ class DocPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
widget.editBloc.add(const DocEditEvent.close());
|
||||
widget.editBloc.close();
|
||||
super.dispose();
|
||||
await widget.doc.close();
|
||||
}
|
||||
|
||||
Widget _renderEditor(EditorController controller) {
|
||||
final editor = FlowyEditor(
|
||||
controller: controller,
|
||||
|
@ -14,14 +14,9 @@ import 'node/line.dart';
|
||||
import 'node/node.dart';
|
||||
import 'package:flowy_log/flowy_log.dart';
|
||||
|
||||
abstract class EditorDeltaSender {
|
||||
void sendNewDelta(Delta changeset, Delta delta);
|
||||
}
|
||||
|
||||
/// The rich text document
|
||||
class Document {
|
||||
EditorDeltaSender? sender;
|
||||
Document({this.sender}) : _delta = Delta()..insert('\n') {
|
||||
Document() : _delta = Delta()..insert('\n') {
|
||||
_loadDocument(_delta);
|
||||
}
|
||||
|
||||
@ -170,8 +165,6 @@ class Document {
|
||||
final changeset = delta;
|
||||
|
||||
_delta = _delta.compose(delta);
|
||||
|
||||
sender?.sendNewDelta(changeset, _delta);
|
||||
} catch (e) {
|
||||
throw '_delta compose failed';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user