construct appflowy home screen

This commit is contained in:
appflowy 2021-07-12 23:27:58 +08:00
parent 222f6c7ba7
commit 02f0eef08b
86 changed files with 4793 additions and 353 deletions

View File

@ -66,6 +66,18 @@
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/flowy_editor/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/flowy_editor/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/flowy_editor/example/build" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/example/build" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/build" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/flowy_editor/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/build" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/app_flowy/macos/Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/example/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@ -219,6 +219,13 @@
</list>
</value>
</entry>
<entry key="expandable">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/expandable-4.1.4/lib" />
</list>
</value>
</entry>
<entry key="fake_async">
<value>
<list>
@ -238,7 +245,6 @@
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib" />
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.1/lib" />
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.0/lib" />
</list>
</value>
@ -424,6 +430,13 @@
</list>
</value>
</entry>
<entry key="lint">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/lint-1.5.3/lib" />
</list>
</value>
</entry>
<entry key="lints">
<value>
<list>
@ -625,6 +638,13 @@
</list>
</value>
</entry>
<entry key="sized_context">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/sized_context-0.2.1+1/lib" />
</list>
</value>
</entry>
<entry key="sky_engine">
<value>
<list>
@ -681,6 +701,13 @@
</list>
</value>
</entry>
<entry key="styled_widget">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/styled_widget-0.3.1+2/lib" />
</list>
</value>
</entry>
<entry key="sync_http">
<value>
<list>
@ -739,6 +766,13 @@
</list>
</value>
</entry>
<entry key="universal_platform">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/universal_platform-0.1.3/lib" />
</list>
</value>
</entry>
<entry key="url_launcher">
<value>
<list>
@ -801,7 +835,7 @@
<entry key="vm_service">
<value>
<list>
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-6.2.0/lib" />
<option value="$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-7.1.0/lib" />
</list>
</value>
</entry>
@ -903,11 +937,11 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/dart_style-2.0.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/dartz-0.10.0-nullsafety.2/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/equatable-2.0.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/expandable-4.1.4/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/ffi-1.1.2/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/file-6.1.2/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/fixnum-1.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/flutter_bloc-7.0.1/lib" />
@ -934,6 +968,7 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/isolates-3.0.3+8/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/json_annotation-4.0.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/lint-1.5.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/logger-1.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/logging-1.0.1/lib" />
@ -966,6 +1001,7 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/shelf-1.1.4/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-1.0.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/sized_context-0.2.1+1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/source_gen-1.0.2/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
@ -973,6 +1009,7 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/stream_transform-2.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/string_validator-0.3.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/styled_widget-0.3.1+2/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/sync_http-0.3.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.3.0/lib" />
@ -983,6 +1020,7 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/timing-1.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/tuple-2.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/universal_platform-0.1.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.3/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.9/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-2.0.0/lib" />
@ -994,7 +1032,7 @@
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-2.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/uuid-3.0.4/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-6.2.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/vm_service-7.1.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/watcher-1.0.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.2.0/lib" />
<root url="file://$PROJECT_DIR$/../../flutter/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-2.1.0/lib" />

View File

@ -0,0 +1,28 @@
import 'package:app_flowy/home/domain/edit_context.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:flutter_bloc/flutter_bloc.dart';
part 'edit_pannel_event.dart';
part 'edit_pannel_state.dart';
part 'edit_pannel_bloc.freezed.dart';
class EditPannelBloc extends Bloc<EditPannelEvent, EditPannelState> {
EditPannelBloc() : super(EditPannelState.initial());
@override
Stream<EditPannelState> mapEventToState(
EditPannelEvent event,
) async* {
yield* event.map(
startEdit: (e) async* {
yield state.copyWith(isEditing: true, editContext: some(e.context));
},
endEdit: (value) async* {
yield state.copyWith(isEditing: false, editContext: none());
},
);
}
}

View File

@ -0,0 +1,492 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides
part of 'edit_pannel_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
class _$EditPannelEventTearOff {
const _$EditPannelEventTearOff();
_StartEdit startEdit(EditPannelContext context) {
return _StartEdit(
context,
);
}
_EndEdit endEdit(EditPannelContext context) {
return _EndEdit(
context,
);
}
}
/// @nodoc
const $EditPannelEvent = _$EditPannelEventTearOff();
/// @nodoc
mixin _$EditPannelEvent {
EditPannelContext get context => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(EditPannelContext context) startEdit,
required TResult Function(EditPannelContext context) endEdit,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(EditPannelContext context)? startEdit,
TResult Function(EditPannelContext context)? endEdit,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_StartEdit value) startEdit,
required TResult Function(_EndEdit value) endEdit,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StartEdit value)? startEdit,
TResult Function(_EndEdit value)? endEdit,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$EditPannelEventCopyWith<EditPannelEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $EditPannelEventCopyWith<$Res> {
factory $EditPannelEventCopyWith(
EditPannelEvent value, $Res Function(EditPannelEvent) then) =
_$EditPannelEventCopyWithImpl<$Res>;
$Res call({EditPannelContext context});
}
/// @nodoc
class _$EditPannelEventCopyWithImpl<$Res>
implements $EditPannelEventCopyWith<$Res> {
_$EditPannelEventCopyWithImpl(this._value, this._then);
final EditPannelEvent _value;
// ignore: unused_field
final $Res Function(EditPannelEvent) _then;
@override
$Res call({
Object? context = freezed,
}) {
return _then(_value.copyWith(
context: context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as EditPannelContext,
));
}
}
/// @nodoc
abstract class _$StartEditCopyWith<$Res>
implements $EditPannelEventCopyWith<$Res> {
factory _$StartEditCopyWith(
_StartEdit value, $Res Function(_StartEdit) then) =
__$StartEditCopyWithImpl<$Res>;
@override
$Res call({EditPannelContext context});
}
/// @nodoc
class __$StartEditCopyWithImpl<$Res> extends _$EditPannelEventCopyWithImpl<$Res>
implements _$StartEditCopyWith<$Res> {
__$StartEditCopyWithImpl(_StartEdit _value, $Res Function(_StartEdit) _then)
: super(_value, (v) => _then(v as _StartEdit));
@override
_StartEdit get _value => super._value as _StartEdit;
@override
$Res call({
Object? context = freezed,
}) {
return _then(_StartEdit(
context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as EditPannelContext,
));
}
}
/// @nodoc
class _$_StartEdit implements _StartEdit {
const _$_StartEdit(this.context);
@override
final EditPannelContext context;
@override
String toString() {
return 'EditPannelEvent.startEdit(context: $context)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _StartEdit &&
(identical(other.context, context) ||
const DeepCollectionEquality().equals(other.context, context)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(context);
@JsonKey(ignore: true)
@override
_$StartEditCopyWith<_StartEdit> get copyWith =>
__$StartEditCopyWithImpl<_StartEdit>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(EditPannelContext context) startEdit,
required TResult Function(EditPannelContext context) endEdit,
}) {
return startEdit(context);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(EditPannelContext context)? startEdit,
TResult Function(EditPannelContext context)? endEdit,
required TResult orElse(),
}) {
if (startEdit != null) {
return startEdit(context);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_StartEdit value) startEdit,
required TResult Function(_EndEdit value) endEdit,
}) {
return startEdit(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StartEdit value)? startEdit,
TResult Function(_EndEdit value)? endEdit,
required TResult orElse(),
}) {
if (startEdit != null) {
return startEdit(this);
}
return orElse();
}
}
abstract class _StartEdit implements EditPannelEvent {
const factory _StartEdit(EditPannelContext context) = _$_StartEdit;
@override
EditPannelContext get context => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$StartEditCopyWith<_StartEdit> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$EndEditCopyWith<$Res>
implements $EditPannelEventCopyWith<$Res> {
factory _$EndEditCopyWith(_EndEdit value, $Res Function(_EndEdit) then) =
__$EndEditCopyWithImpl<$Res>;
@override
$Res call({EditPannelContext context});
}
/// @nodoc
class __$EndEditCopyWithImpl<$Res> extends _$EditPannelEventCopyWithImpl<$Res>
implements _$EndEditCopyWith<$Res> {
__$EndEditCopyWithImpl(_EndEdit _value, $Res Function(_EndEdit) _then)
: super(_value, (v) => _then(v as _EndEdit));
@override
_EndEdit get _value => super._value as _EndEdit;
@override
$Res call({
Object? context = freezed,
}) {
return _then(_EndEdit(
context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as EditPannelContext,
));
}
}
/// @nodoc
class _$_EndEdit implements _EndEdit {
const _$_EndEdit(this.context);
@override
final EditPannelContext context;
@override
String toString() {
return 'EditPannelEvent.endEdit(context: $context)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _EndEdit &&
(identical(other.context, context) ||
const DeepCollectionEquality().equals(other.context, context)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(context);
@JsonKey(ignore: true)
@override
_$EndEditCopyWith<_EndEdit> get copyWith =>
__$EndEditCopyWithImpl<_EndEdit>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(EditPannelContext context) startEdit,
required TResult Function(EditPannelContext context) endEdit,
}) {
return endEdit(context);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(EditPannelContext context)? startEdit,
TResult Function(EditPannelContext context)? endEdit,
required TResult orElse(),
}) {
if (endEdit != null) {
return endEdit(context);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_StartEdit value) startEdit,
required TResult Function(_EndEdit value) endEdit,
}) {
return endEdit(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_StartEdit value)? startEdit,
TResult Function(_EndEdit value)? endEdit,
required TResult orElse(),
}) {
if (endEdit != null) {
return endEdit(this);
}
return orElse();
}
}
abstract class _EndEdit implements EditPannelEvent {
const factory _EndEdit(EditPannelContext context) = _$_EndEdit;
@override
EditPannelContext get context => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$EndEditCopyWith<_EndEdit> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
class _$EditPannelStateTearOff {
const _$EditPannelStateTearOff();
_EditPannelState call(
{required bool isEditing,
required Option<EditPannelContext> editContext}) {
return _EditPannelState(
isEditing: isEditing,
editContext: editContext,
);
}
}
/// @nodoc
const $EditPannelState = _$EditPannelStateTearOff();
/// @nodoc
mixin _$EditPannelState {
bool get isEditing => throw _privateConstructorUsedError;
Option<EditPannelContext> get editContext =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$EditPannelStateCopyWith<EditPannelState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $EditPannelStateCopyWith<$Res> {
factory $EditPannelStateCopyWith(
EditPannelState value, $Res Function(EditPannelState) then) =
_$EditPannelStateCopyWithImpl<$Res>;
$Res call({bool isEditing, Option<EditPannelContext> editContext});
}
/// @nodoc
class _$EditPannelStateCopyWithImpl<$Res>
implements $EditPannelStateCopyWith<$Res> {
_$EditPannelStateCopyWithImpl(this._value, this._then);
final EditPannelState _value;
// ignore: unused_field
final $Res Function(EditPannelState) _then;
@override
$Res call({
Object? isEditing = freezed,
Object? editContext = freezed,
}) {
return _then(_value.copyWith(
isEditing: isEditing == freezed
? _value.isEditing
: isEditing // ignore: cast_nullable_to_non_nullable
as bool,
editContext: editContext == freezed
? _value.editContext
: editContext // ignore: cast_nullable_to_non_nullable
as Option<EditPannelContext>,
));
}
}
/// @nodoc
abstract class _$EditPannelStateCopyWith<$Res>
implements $EditPannelStateCopyWith<$Res> {
factory _$EditPannelStateCopyWith(
_EditPannelState value, $Res Function(_EditPannelState) then) =
__$EditPannelStateCopyWithImpl<$Res>;
@override
$Res call({bool isEditing, Option<EditPannelContext> editContext});
}
/// @nodoc
class __$EditPannelStateCopyWithImpl<$Res>
extends _$EditPannelStateCopyWithImpl<$Res>
implements _$EditPannelStateCopyWith<$Res> {
__$EditPannelStateCopyWithImpl(
_EditPannelState _value, $Res Function(_EditPannelState) _then)
: super(_value, (v) => _then(v as _EditPannelState));
@override
_EditPannelState get _value => super._value as _EditPannelState;
@override
$Res call({
Object? isEditing = freezed,
Object? editContext = freezed,
}) {
return _then(_EditPannelState(
isEditing: isEditing == freezed
? _value.isEditing
: isEditing // ignore: cast_nullable_to_non_nullable
as bool,
editContext: editContext == freezed
? _value.editContext
: editContext // ignore: cast_nullable_to_non_nullable
as Option<EditPannelContext>,
));
}
}
/// @nodoc
class _$_EditPannelState implements _EditPannelState {
const _$_EditPannelState(
{required this.isEditing, required this.editContext});
@override
final bool isEditing;
@override
final Option<EditPannelContext> editContext;
@override
String toString() {
return 'EditPannelState(isEditing: $isEditing, editContext: $editContext)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _EditPannelState &&
(identical(other.isEditing, isEditing) ||
const DeepCollectionEquality()
.equals(other.isEditing, isEditing)) &&
(identical(other.editContext, editContext) ||
const DeepCollectionEquality()
.equals(other.editContext, editContext)));
}
@override
int get hashCode =>
runtimeType.hashCode ^
const DeepCollectionEquality().hash(isEditing) ^
const DeepCollectionEquality().hash(editContext);
@JsonKey(ignore: true)
@override
_$EditPannelStateCopyWith<_EditPannelState> get copyWith =>
__$EditPannelStateCopyWithImpl<_EditPannelState>(this, _$identity);
}
abstract class _EditPannelState implements EditPannelState {
const factory _EditPannelState(
{required bool isEditing,
required Option<EditPannelContext> editContext}) = _$_EditPannelState;
@override
bool get isEditing => throw _privateConstructorUsedError;
@override
Option<EditPannelContext> get editContext =>
throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$EditPannelStateCopyWith<_EditPannelState> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,9 @@
part of 'edit_pannel_bloc.dart';
@freezed
abstract class EditPannelEvent with _$EditPannelEvent {
const factory EditPannelEvent.startEdit(EditPannelContext context) =
_StartEdit;
const factory EditPannelEvent.endEdit(EditPannelContext context) = _EndEdit;
}

View File

@ -0,0 +1,14 @@
part of 'edit_pannel_bloc.dart';
@freezed
abstract class EditPannelState implements _$EditPannelState {
const factory EditPannelState({
required bool isEditing,
required Option<EditPannelContext> editContext,
}) = _EditPannelState;
factory EditPannelState.initial() => EditPannelState(
isEditing: false,
editContext: none(),
);
}

View File

@ -0,0 +1,44 @@
import 'dart:async';
import 'package:app_flowy/home/domain/page_context.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
part 'menu_event.dart';
part 'menu_state.dart';
part 'menu_bloc.freezed.dart';
class MenuBloc extends Bloc<MenuEvent, MenuState> {
MenuBloc() : super(MenuState.initial());
@override
Stream<MenuState> mapEventToState(
MenuEvent event,
) async* {
yield* event.map(
collapse: (e) async* {
final isCollapse = state.isCollapse;
yield state.copyWith(isCollapse: !isCollapse);
},
openPage: (e) async* {
yield* _performActionOnOpenPage(e);
},
createApp: (e) async* {
yield* _performActionOnCreateApp(e);
},
);
}
Stream<MenuState> _performActionOnOpenPage(_OpenPage e) async* {
yield state.copyWith(pageContext: some(e.context));
}
Stream<MenuState> _performActionOnCreateApp(_CreateApp e) async* {
yield state;
}
@override
Future<void> close() {
return super.close();
}
}

View File

@ -0,0 +1,525 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides
part of 'menu_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
class _$MenuEventTearOff {
const _$MenuEventTearOff();
Collapse collapse() {
return const Collapse();
}
_OpenPage openPage(PageContext context) {
return _OpenPage(
context,
);
}
_CreateApp createApp() {
return const _CreateApp();
}
}
/// @nodoc
const $MenuEvent = _$MenuEventTearOff();
/// @nodoc
mixin _$MenuEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() collapse,
required TResult Function(PageContext context) openPage,
required TResult Function() createApp,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? collapse,
TResult Function(PageContext context)? openPage,
TResult Function()? createApp,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Collapse value) collapse,
required TResult Function(_OpenPage value) openPage,
required TResult Function(_CreateApp value) createApp,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Collapse value)? collapse,
TResult Function(_OpenPage value)? openPage,
TResult Function(_CreateApp value)? createApp,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MenuEventCopyWith<$Res> {
factory $MenuEventCopyWith(MenuEvent value, $Res Function(MenuEvent) then) =
_$MenuEventCopyWithImpl<$Res>;
}
/// @nodoc
class _$MenuEventCopyWithImpl<$Res> implements $MenuEventCopyWith<$Res> {
_$MenuEventCopyWithImpl(this._value, this._then);
final MenuEvent _value;
// ignore: unused_field
final $Res Function(MenuEvent) _then;
}
/// @nodoc
abstract class $CollapseCopyWith<$Res> {
factory $CollapseCopyWith(Collapse value, $Res Function(Collapse) then) =
_$CollapseCopyWithImpl<$Res>;
}
/// @nodoc
class _$CollapseCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
implements $CollapseCopyWith<$Res> {
_$CollapseCopyWithImpl(Collapse _value, $Res Function(Collapse) _then)
: super(_value, (v) => _then(v as Collapse));
@override
Collapse get _value => super._value as Collapse;
}
/// @nodoc
class _$Collapse implements Collapse {
const _$Collapse();
@override
String toString() {
return 'MenuEvent.collapse()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Collapse);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() collapse,
required TResult Function(PageContext context) openPage,
required TResult Function() createApp,
}) {
return collapse();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? collapse,
TResult Function(PageContext context)? openPage,
TResult Function()? createApp,
required TResult orElse(),
}) {
if (collapse != null) {
return collapse();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Collapse value) collapse,
required TResult Function(_OpenPage value) openPage,
required TResult Function(_CreateApp value) createApp,
}) {
return collapse(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Collapse value)? collapse,
TResult Function(_OpenPage value)? openPage,
TResult Function(_CreateApp value)? createApp,
required TResult orElse(),
}) {
if (collapse != null) {
return collapse(this);
}
return orElse();
}
}
abstract class Collapse implements MenuEvent {
const factory Collapse() = _$Collapse;
}
/// @nodoc
abstract class _$OpenPageCopyWith<$Res> {
factory _$OpenPageCopyWith(_OpenPage value, $Res Function(_OpenPage) then) =
__$OpenPageCopyWithImpl<$Res>;
$Res call({PageContext context});
}
/// @nodoc
class __$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
implements _$OpenPageCopyWith<$Res> {
__$OpenPageCopyWithImpl(_OpenPage _value, $Res Function(_OpenPage) _then)
: super(_value, (v) => _then(v as _OpenPage));
@override
_OpenPage get _value => super._value as _OpenPage;
@override
$Res call({
Object? context = freezed,
}) {
return _then(_OpenPage(
context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as PageContext,
));
}
}
/// @nodoc
class _$_OpenPage implements _OpenPage {
const _$_OpenPage(this.context);
@override
final PageContext context;
@override
String toString() {
return 'MenuEvent.openPage(context: $context)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _OpenPage &&
(identical(other.context, context) ||
const DeepCollectionEquality().equals(other.context, context)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(context);
@JsonKey(ignore: true)
@override
_$OpenPageCopyWith<_OpenPage> get copyWith =>
__$OpenPageCopyWithImpl<_OpenPage>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() collapse,
required TResult Function(PageContext context) openPage,
required TResult Function() createApp,
}) {
return openPage(context);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? collapse,
TResult Function(PageContext context)? openPage,
TResult Function()? createApp,
required TResult orElse(),
}) {
if (openPage != null) {
return openPage(context);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Collapse value) collapse,
required TResult Function(_OpenPage value) openPage,
required TResult Function(_CreateApp value) createApp,
}) {
return openPage(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Collapse value)? collapse,
TResult Function(_OpenPage value)? openPage,
TResult Function(_CreateApp value)? createApp,
required TResult orElse(),
}) {
if (openPage != null) {
return openPage(this);
}
return orElse();
}
}
abstract class _OpenPage implements MenuEvent {
const factory _OpenPage(PageContext context) = _$_OpenPage;
PageContext get context => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
_$OpenPageCopyWith<_OpenPage> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$CreateAppCopyWith<$Res> {
factory _$CreateAppCopyWith(
_CreateApp value, $Res Function(_CreateApp) then) =
__$CreateAppCopyWithImpl<$Res>;
}
/// @nodoc
class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
implements _$CreateAppCopyWith<$Res> {
__$CreateAppCopyWithImpl(_CreateApp _value, $Res Function(_CreateApp) _then)
: super(_value, (v) => _then(v as _CreateApp));
@override
_CreateApp get _value => super._value as _CreateApp;
}
/// @nodoc
class _$_CreateApp implements _CreateApp {
const _$_CreateApp();
@override
String toString() {
return 'MenuEvent.createApp()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _CreateApp);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() collapse,
required TResult Function(PageContext context) openPage,
required TResult Function() createApp,
}) {
return createApp();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? collapse,
TResult Function(PageContext context)? openPage,
TResult Function()? createApp,
required TResult orElse(),
}) {
if (createApp != null) {
return createApp();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Collapse value) collapse,
required TResult Function(_OpenPage value) openPage,
required TResult Function(_CreateApp value) createApp,
}) {
return createApp(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Collapse value)? collapse,
TResult Function(_OpenPage value)? openPage,
TResult Function(_CreateApp value)? createApp,
required TResult orElse(),
}) {
if (createApp != null) {
return createApp(this);
}
return orElse();
}
}
abstract class _CreateApp implements MenuEvent {
const factory _CreateApp() = _$_CreateApp;
}
/// @nodoc
class _$MenuStateTearOff {
const _$MenuStateTearOff();
_MenuState call(
{required bool isCollapse, required Option<PageContext> pageContext}) {
return _MenuState(
isCollapse: isCollapse,
pageContext: pageContext,
);
}
}
/// @nodoc
const $MenuState = _$MenuStateTearOff();
/// @nodoc
mixin _$MenuState {
bool get isCollapse => throw _privateConstructorUsedError;
Option<PageContext> get pageContext => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$MenuStateCopyWith<MenuState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MenuStateCopyWith<$Res> {
factory $MenuStateCopyWith(MenuState value, $Res Function(MenuState) then) =
_$MenuStateCopyWithImpl<$Res>;
$Res call({bool isCollapse, Option<PageContext> pageContext});
}
/// @nodoc
class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
_$MenuStateCopyWithImpl(this._value, this._then);
final MenuState _value;
// ignore: unused_field
final $Res Function(MenuState) _then;
@override
$Res call({
Object? isCollapse = freezed,
Object? pageContext = freezed,
}) {
return _then(_value.copyWith(
isCollapse: isCollapse == freezed
? _value.isCollapse
: isCollapse // ignore: cast_nullable_to_non_nullable
as bool,
pageContext: pageContext == freezed
? _value.pageContext
: pageContext // ignore: cast_nullable_to_non_nullable
as Option<PageContext>,
));
}
}
/// @nodoc
abstract class _$MenuStateCopyWith<$Res> implements $MenuStateCopyWith<$Res> {
factory _$MenuStateCopyWith(
_MenuState value, $Res Function(_MenuState) then) =
__$MenuStateCopyWithImpl<$Res>;
@override
$Res call({bool isCollapse, Option<PageContext> pageContext});
}
/// @nodoc
class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
implements _$MenuStateCopyWith<$Res> {
__$MenuStateCopyWithImpl(_MenuState _value, $Res Function(_MenuState) _then)
: super(_value, (v) => _then(v as _MenuState));
@override
_MenuState get _value => super._value as _MenuState;
@override
$Res call({
Object? isCollapse = freezed,
Object? pageContext = freezed,
}) {
return _then(_MenuState(
isCollapse: isCollapse == freezed
? _value.isCollapse
: isCollapse // ignore: cast_nullable_to_non_nullable
as bool,
pageContext: pageContext == freezed
? _value.pageContext
: pageContext // ignore: cast_nullable_to_non_nullable
as Option<PageContext>,
));
}
}
/// @nodoc
class _$_MenuState implements _MenuState {
const _$_MenuState({required this.isCollapse, required this.pageContext});
@override
final bool isCollapse;
@override
final Option<PageContext> pageContext;
@override
String toString() {
return 'MenuState(isCollapse: $isCollapse, pageContext: $pageContext)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _MenuState &&
(identical(other.isCollapse, isCollapse) ||
const DeepCollectionEquality()
.equals(other.isCollapse, isCollapse)) &&
(identical(other.pageContext, pageContext) ||
const DeepCollectionEquality()
.equals(other.pageContext, pageContext)));
}
@override
int get hashCode =>
runtimeType.hashCode ^
const DeepCollectionEquality().hash(isCollapse) ^
const DeepCollectionEquality().hash(pageContext);
@JsonKey(ignore: true)
@override
_$MenuStateCopyWith<_MenuState> get copyWith =>
__$MenuStateCopyWithImpl<_MenuState>(this, _$identity);
}
abstract class _MenuState implements MenuState {
const factory _MenuState(
{required bool isCollapse,
required Option<PageContext> pageContext}) = _$_MenuState;
@override
bool get isCollapse => throw _privateConstructorUsedError;
@override
Option<PageContext> get pageContext => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$MenuStateCopyWith<_MenuState> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,8 @@
part of 'menu_bloc.dart';
@freezed
abstract class MenuEvent with _$MenuEvent {
const factory MenuEvent.collapse() = Collapse;
const factory MenuEvent.openPage(PageContext context) = _OpenPage;
const factory MenuEvent.createApp() = _CreateApp;
}

View File

@ -0,0 +1,14 @@
part of 'menu_bloc.dart';
@freezed
abstract class MenuState implements _$MenuState {
const factory MenuState({
required bool isCollapse,
required Option<PageContext> pageContext,
}) = _MenuState;
factory MenuState.initial() => MenuState(
isCollapse: false,
pageContext: none(),
);
}

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:flutter_bloc/flutter_bloc.dart';
part 'home_watcher_event.dart';
part 'home_watcher_state.dart';
part 'home_watcher_bloc.freezed.dart';
class HomeWatcherBloc extends Bloc<HomeWatcherEvent, HomeWatcherState> {
HomeWatcherBloc() : super(const HomeWatcherState.initial());
@override
Stream<HomeWatcherState> mapEventToState(
HomeWatcherEvent event,
) async* {
yield state;
}
}

View File

@ -0,0 +1,562 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides
part of 'home_watcher_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
class _$HomeWatcherEventTearOff {
const _$HomeWatcherEventTearOff();
_Started started(String workspaceId) {
return _Started(
workspaceId,
);
}
_Stop stop(String workspaceId) {
return _Stop(
workspaceId,
);
}
}
/// @nodoc
const $HomeWatcherEvent = _$HomeWatcherEventTearOff();
/// @nodoc
mixin _$HomeWatcherEvent {
String get workspaceId => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String workspaceId) started,
required TResult Function(String workspaceId) stop,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String workspaceId)? started,
TResult Function(String workspaceId)? stop,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(_Stop value) stop,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(_Stop value)? stop,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$HomeWatcherEventCopyWith<HomeWatcherEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeWatcherEventCopyWith<$Res> {
factory $HomeWatcherEventCopyWith(
HomeWatcherEvent value, $Res Function(HomeWatcherEvent) then) =
_$HomeWatcherEventCopyWithImpl<$Res>;
$Res call({String workspaceId});
}
/// @nodoc
class _$HomeWatcherEventCopyWithImpl<$Res>
implements $HomeWatcherEventCopyWith<$Res> {
_$HomeWatcherEventCopyWithImpl(this._value, this._then);
final HomeWatcherEvent _value;
// ignore: unused_field
final $Res Function(HomeWatcherEvent) _then;
@override
$Res call({
Object? workspaceId = freezed,
}) {
return _then(_value.copyWith(
workspaceId: workspaceId == freezed
? _value.workspaceId
: workspaceId // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
abstract class _$StartedCopyWith<$Res>
implements $HomeWatcherEventCopyWith<$Res> {
factory _$StartedCopyWith(_Started value, $Res Function(_Started) then) =
__$StartedCopyWithImpl<$Res>;
@override
$Res call({String workspaceId});
}
/// @nodoc
class __$StartedCopyWithImpl<$Res> extends _$HomeWatcherEventCopyWithImpl<$Res>
implements _$StartedCopyWith<$Res> {
__$StartedCopyWithImpl(_Started _value, $Res Function(_Started) _then)
: super(_value, (v) => _then(v as _Started));
@override
_Started get _value => super._value as _Started;
@override
$Res call({
Object? workspaceId = freezed,
}) {
return _then(_Started(
workspaceId == freezed
? _value.workspaceId
: workspaceId // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$_Started implements _Started {
const _$_Started(this.workspaceId);
@override
final String workspaceId;
@override
String toString() {
return 'HomeWatcherEvent.started(workspaceId: $workspaceId)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _Started &&
(identical(other.workspaceId, workspaceId) ||
const DeepCollectionEquality()
.equals(other.workspaceId, workspaceId)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(workspaceId);
@JsonKey(ignore: true)
@override
_$StartedCopyWith<_Started> get copyWith =>
__$StartedCopyWithImpl<_Started>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String workspaceId) started,
required TResult Function(String workspaceId) stop,
}) {
return started(workspaceId);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String workspaceId)? started,
TResult Function(String workspaceId)? stop,
required TResult orElse(),
}) {
if (started != null) {
return started(workspaceId);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(_Stop value) stop,
}) {
return started(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(_Stop value)? stop,
required TResult orElse(),
}) {
if (started != null) {
return started(this);
}
return orElse();
}
}
abstract class _Started implements HomeWatcherEvent {
const factory _Started(String workspaceId) = _$_Started;
@override
String get workspaceId => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$StartedCopyWith<_Started> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$StopCopyWith<$Res> implements $HomeWatcherEventCopyWith<$Res> {
factory _$StopCopyWith(_Stop value, $Res Function(_Stop) then) =
__$StopCopyWithImpl<$Res>;
@override
$Res call({String workspaceId});
}
/// @nodoc
class __$StopCopyWithImpl<$Res> extends _$HomeWatcherEventCopyWithImpl<$Res>
implements _$StopCopyWith<$Res> {
__$StopCopyWithImpl(_Stop _value, $Res Function(_Stop) _then)
: super(_value, (v) => _then(v as _Stop));
@override
_Stop get _value => super._value as _Stop;
@override
$Res call({
Object? workspaceId = freezed,
}) {
return _then(_Stop(
workspaceId == freezed
? _value.workspaceId
: workspaceId // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$_Stop implements _Stop {
const _$_Stop(this.workspaceId);
@override
final String workspaceId;
@override
String toString() {
return 'HomeWatcherEvent.stop(workspaceId: $workspaceId)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _Stop &&
(identical(other.workspaceId, workspaceId) ||
const DeepCollectionEquality()
.equals(other.workspaceId, workspaceId)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(workspaceId);
@JsonKey(ignore: true)
@override
_$StopCopyWith<_Stop> get copyWith =>
__$StopCopyWithImpl<_Stop>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String workspaceId) started,
required TResult Function(String workspaceId) stop,
}) {
return stop(workspaceId);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String workspaceId)? started,
TResult Function(String workspaceId)? stop,
required TResult orElse(),
}) {
if (stop != null) {
return stop(workspaceId);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(_Stop value) stop,
}) {
return stop(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(_Stop value)? stop,
required TResult orElse(),
}) {
if (stop != null) {
return stop(this);
}
return orElse();
}
}
abstract class _Stop implements HomeWatcherEvent {
const factory _Stop(String workspaceId) = _$_Stop;
@override
String get workspaceId => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$StopCopyWith<_Stop> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
class _$HomeWatcherStateTearOff {
const _$HomeWatcherStateTearOff();
_Initial initial() {
return const _Initial();
}
_Loading loading() {
return const _Loading();
}
}
/// @nodoc
const $HomeWatcherState = _$HomeWatcherStateTearOff();
/// @nodoc
mixin _$HomeWatcherState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeWatcherStateCopyWith<$Res> {
factory $HomeWatcherStateCopyWith(
HomeWatcherState value, $Res Function(HomeWatcherState) then) =
_$HomeWatcherStateCopyWithImpl<$Res>;
}
/// @nodoc
class _$HomeWatcherStateCopyWithImpl<$Res>
implements $HomeWatcherStateCopyWith<$Res> {
_$HomeWatcherStateCopyWithImpl(this._value, this._then);
final HomeWatcherState _value;
// ignore: unused_field
final $Res Function(HomeWatcherState) _then;
}
/// @nodoc
abstract class _$InitialCopyWith<$Res> {
factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
__$InitialCopyWithImpl<$Res>;
}
/// @nodoc
class __$InitialCopyWithImpl<$Res> extends _$HomeWatcherStateCopyWithImpl<$Res>
implements _$InitialCopyWith<$Res> {
__$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
: super(_value, (v) => _then(v as _Initial));
@override
_Initial get _value => super._value as _Initial;
}
/// @nodoc
class _$_Initial implements _Initial {
const _$_Initial();
@override
String toString() {
return 'HomeWatcherState.initial()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Initial);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements HomeWatcherState {
const factory _Initial() = _$_Initial;
}
/// @nodoc
abstract class _$LoadingCopyWith<$Res> {
factory _$LoadingCopyWith(_Loading value, $Res Function(_Loading) then) =
__$LoadingCopyWithImpl<$Res>;
}
/// @nodoc
class __$LoadingCopyWithImpl<$Res> extends _$HomeWatcherStateCopyWithImpl<$Res>
implements _$LoadingCopyWith<$Res> {
__$LoadingCopyWithImpl(_Loading _value, $Res Function(_Loading) _then)
: super(_value, (v) => _then(v as _Loading));
@override
_Loading get _value => super._value as _Loading;
}
/// @nodoc
class _$_Loading implements _Loading {
const _$_Loading();
@override
String toString() {
return 'HomeWatcherState.loading()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Loading);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
}) {
return loading();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
required TResult orElse(),
}) {
if (loading != null) {
return loading();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
}) {
return loading(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
required TResult orElse(),
}) {
if (loading != null) {
return loading(this);
}
return orElse();
}
}
abstract class _Loading implements HomeWatcherState {
const factory _Loading() = _$_Loading;
}

View File

@ -0,0 +1,7 @@
part of 'home_watcher_bloc.dart';
@freezed
abstract class HomeWatcherEvent with _$HomeWatcherEvent {
const factory HomeWatcherEvent.started(String workspaceId) = _Started;
const factory HomeWatcherEvent.stop(String workspaceId) = _Stop;
}

View File

@ -0,0 +1,7 @@
part of 'home_watcher_bloc.dart';
@freezed
abstract class HomeWatcherState with _$HomeWatcherState {
const factory HomeWatcherState.initial() = _Initial;
const factory HomeWatcherState.loading() = _Loading;
}

View File

@ -1,5 +0,0 @@
import 'package:flutter/widgets.dart';
abstract class IAuth {
Widget authScreen();
}

View File

@ -0,0 +1,43 @@
import 'package:app_flowy/home/application/home_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flowy_style/time/duration.dart';
import 'package:flowy_style/size.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:sized_context/sized_context.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'home_sizes.dart';
class HomeLayout {
late double menuWidth;
late bool showMenu;
late bool showEditPannel;
late double editPannelWidth;
late double homePageLOffset;
late double homePageROffset;
late Duration animDuration;
HomeLayout(BuildContext context, BoxConstraints homeScreenConstraint) {
final homeBlocState = context.read<HomeBloc>().state;
showEditPannel = homeBlocState.editContext.isSome();
menuWidth = Sizes.sideBarSm;
if (context.widthPx >= PageBreaks.desktop) {
menuWidth = Sizes.sideBarLg;
}
// if (menuBlocState.isCollapse) {
// showMenu = false;
// } else {
// showMenu = context.widthPx > PageBreaks.TabletPortrait;
// }
showMenu = context.widthPx > PageBreaks.tabletPortrait;
homePageLOffset = showMenu ? menuWidth : 0.0;
animDuration = .35.seconds;
editPannelWidth = HomeSizes.editPannelWidth;
homePageROffset = showEditPannel ? editPannelWidth : 0;
}
}

View File

@ -1,15 +1,144 @@
import 'package:app_flowy/home/application/home_bloc.dart';
import 'package:app_flowy/home/application/watcher/home_watcher_bloc.dart';
import 'package:app_flowy/home/domain/page_context.dart';
import 'package:app_flowy/home/presentation/widgets/blank_page.dart';
import 'package:app_flowy/home/presentation/widgets/edit_pannel/edit_pannel.dart';
import 'package:app_flowy/home/presentation/widgets/edit_pannel/pannel_animation.dart';
import 'package:app_flowy/home/presentation/widgets/home_top_bar.dart';
import 'package:app_flowy/home/presentation/widgets/menu/home_menu.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:flowy_logger/flowy_logger.dart';
import 'package:flowy_sdk/protobuf/user_detail.pb.dart';
import 'package:flowy_style/styled_container.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:styled_widget/styled_widget.dart';
import 'home_layout.dart';
import 'widgets/fading_index_stack.dart';
class HomeScreen extends StatelessWidget {
static GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
const HomeScreen({Key? key}) : super(key: key);
final UserDetail userDetail;
const HomeScreen(this.userDetail, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: null,
return MultiBlocProvider(
providers: [
BlocProvider<HomeWatcherBloc>(
create: (context) => getIt<HomeWatcherBloc>()),
BlocProvider<HomeBloc>(create: (context) => getIt<HomeBloc>()),
],
child: Scaffold(
key: HomeScreen.scaffoldKey,
body: BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
return StyledContainer(
Theme.of(context).colorScheme.background,
child: _buildBody(state),
);
},
),
),
);
}
Widget _buildBody(HomeState state) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final layout = HomeLayout(context, constraints);
const homePage = HomePage();
final menu = _buildHomeMenu(
layout: layout,
context: context,
);
final editPannel = _buildEditPannel(
homeState: state,
layout: layout,
context: context,
);
return _layoutWidgets(
layout: layout,
homePage: homePage,
homeMenu: menu,
editPannel: editPannel);
},
);
}
Widget _buildHomeMenu(
{required HomeLayout layout, required BuildContext context}) {
final homeBloc = context.read<HomeBloc>();
Widget homeMenu = HomeMenu(
pageContextChanged: (pageContext) {
pageContext.fold(
() => homeBloc.add(const HomeEvent.setPage(BlankPageContext())),
(pageContext) {
homeBloc.add(HomeEvent.setPage(pageContext));
},
);
},
isCollapseChanged: (isCollapse) {
homeBloc.add(HomeEvent.showMenu(!isCollapse));
},
);
homeMenu = RepaintBoundary(child: homeMenu);
homeMenu = FocusTraversalGroup(child: homeMenu);
return homeMenu;
}
Widget _buildEditPannel(
{required HomeState homeState,
required BuildContext context,
required HomeLayout layout}) {
final homeBloc = context.read<HomeBloc>();
Widget editPannel = EditPannel(
context: homeState.editContext,
onEndEdit: () => homeBloc.add(const HomeEvent.dismissEditPannel()),
);
// editPannel = RepaintBoundary(child: editPannel);
// editPannel = FocusTraversalGroup(child: editPannel);
return editPannel;
}
Widget _layoutWidgets(
{required HomeLayout layout,
required Widget homeMenu,
required Widget homePage,
required Widget editPannel}) {
return Stack(
children: [
homeMenu
.animatedPanelX(
closeX: -layout.menuWidth,
isClosed: !layout.showMenu,
)
.positioned(
left: 0,
top: 0,
width: layout.menuWidth,
bottom: 0,
animate: true)
.animate(layout.animDuration, Curves.easeOut),
homePage
.constrained(minWidth: 500)
.positioned(
left: layout.homePageLOffset,
right: layout.homePageROffset,
bottom: 0,
top: 0,
animate: true)
.animate(layout.animDuration, Curves.easeOut),
editPannel
.animatedPanelX(
duration: layout.animDuration.inMilliseconds * 0.001,
closeX: layout.editPannelWidth,
isClosed: !layout.showEditPannel,
)
.positioned(
right: 0, top: 0, bottom: 0, width: layout.editPannelWidth),
],
);
}
}
@ -32,3 +161,51 @@ List<Widget> buildPagesWidget(PageContext pageContext) {
}
}).toList();
}
class HomePage extends StatelessWidget {
static GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
// final Size size;
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Log.info('HomePage build');
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
HomeTopBar(),
HomeIndexStack(),
],
);
}
}
class HomeIndexStack extends StatelessWidget {
const HomeIndexStack({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<HomeBloc, HomeState>(
buildWhen: (p, c) {
if (p.pageContext != c.pageContext) {
Log.info(
'PageContext switch from ${p.pageContext.pageType} to ${c.pageContext.pageType}');
}
return p.pageContext != c.pageContext;
},
builder: (context, state) {
final pageContext = context.read<HomeBloc>().state.pageContext;
return Expanded(
child: Container(
color: Colors.white,
child: FocusTraversalGroup(
child: FadingIndexedStack(
index: pages.indexOf(pageContext.pageType),
children: buildPagesWidget(pageContext),
),
),
),
);
},
);
}
}

View File

@ -0,0 +1,11 @@
class HomeSizes {
static double get menuTopBarHeight => 60;
static double get menuAddButtonHeight => 60;
static double get topBarHeight => 60;
static double get editPannelTopBarHeight => 60;
static double get editPannelWidth => 400;
}
class HomeInsets {
static double get topBarTitlePadding => 12;
}

View File

@ -0,0 +1,67 @@
import 'package:app_flowy/home/application/edit_pannel/edit_pannel_bloc.dart';
import 'package:app_flowy/home/domain/edit_context.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_style/styled_bar_title.dart';
import 'package:flowy_style/styled_close_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../home_sizes.dart';
class EditPannel extends StatelessWidget {
late final EditPannelContext editContext;
final VoidCallback onEndEdit;
EditPannel(
{Key? key,
required Option<EditPannelContext> context,
required this.onEndEdit})
: super(key: key) {
editContext = context.fold(() => const BlankEditPannelContext(), (c) => c);
}
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.primaryVariant,
child: BlocProvider(
create: (context) => getIt<EditPannelBloc>(),
child: BlocBuilder<EditPannelBloc, EditPannelState>(
builder: (context, state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
EditPannelTopBar(onClose: () => onEndEdit()),
Expanded(
child: editContext.child,
),
],
);
},
),
),
);
}
}
class EditPannelTopBar extends StatelessWidget {
final VoidCallback onClose;
const EditPannelTopBar({Key? key, required this.onClose}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: HomeSizes.editPannelTopBarHeight,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
const StyleBarTitle(
title: 'Title',
),
const Spacer(),
StyleCloseButton(onPressed: onClose),
],
),
),
);
}
}

View File

@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
class AnimatedPanel extends StatefulWidget {
final bool isClosed;
final double closedX;
final double closedY;
final double duration;
final Curve? curve;
final Widget? child;
const AnimatedPanel(
{Key? key,
this.isClosed = false,
this.closedX = 0.0,
this.closedY = 0.0,
this.duration = 0.0,
this.curve,
this.child})
: super(key: key);
@override
_AnimatedPanelState createState() => _AnimatedPanelState();
}
class _AnimatedPanelState extends State<AnimatedPanel> {
bool _isHidden = true;
@override
Widget build(BuildContext context) {
Offset closePos = Offset(widget.closedX, widget.closedY);
double duration = _isHidden && widget.isClosed ? 0 : widget.duration;
return TweenAnimationBuilder(
curve: widget.curve ?? Curves.easeOut,
tween: Tween<Offset>(
begin: !widget.isClosed ? Offset.zero : closePos,
end: !widget.isClosed ? Offset.zero : closePos,
),
duration: Duration(milliseconds: (duration * 1000).round()),
builder: (_, Offset value, Widget? c) {
_isHidden =
widget.isClosed && value == Offset(widget.closedX, widget.closedY);
return _isHidden
? Container()
: Transform.translate(offset: value, child: c);
},
child: widget.child,
);
}
}
extension AnimatedPanelExtensions on Widget {
Widget animatedPanelX(
{double closeX = 0.0,
bool? isClosed,
double? duration,
Curve? curve}) =>
animatedPanel(
closePos: Offset(closeX, 0),
isClosed: isClosed,
curve: curve,
duration: duration);
Widget animatedPanelY(
{double closeY = 0.0,
bool? isClosed,
double? duration,
Curve? curve}) =>
animatedPanel(
closePos: Offset(0, closeY),
isClosed: isClosed,
curve: curve,
duration: duration);
Widget animatedPanel(
{required Offset closePos,
bool? isClosed,
double? duration,
Curve? curve}) {
return AnimatedPanel(
closedX: closePos.dx,
closedY: closePos.dy,
child: this,
isClosed: isClosed ?? false,
duration: duration ?? .35,
curve: curve);
}
}

View File

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:time/time.dart';
class FadingIndexedStack extends StatefulWidget {
final int index;
final List<Widget> children;
final Duration duration;
const FadingIndexedStack({
Key? key,
required this.index,
required this.children,
this.duration = const Duration(
milliseconds: 250,
),
}) : super(key: key);
@override
_FadingIndexedStackState createState() => _FadingIndexedStackState();
}
class _FadingIndexedStackState extends State<FadingIndexedStack> {
double _targetOpacity = 1;
@override
void didUpdateWidget(FadingIndexedStack oldWidget) {
if (oldWidget.index == widget.index) return;
setState(() => _targetOpacity = 0);
Future.delayed(1.milliseconds, () => setState(() => _targetOpacity = 1));
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return TweenAnimationBuilder<double>(
duration: _targetOpacity > 0 ? widget.duration : 0.milliseconds,
tween: Tween(begin: 0, end: _targetOpacity),
builder: (_, value, child) {
return Opacity(opacity: value, child: child);
},
child: IndexedStack(index: widget.index, children: widget.children),
);
}
}

View File

@ -0,0 +1,7 @@
import 'package:app_flowy/home/domain/page_context.dart';
import 'package:flutter/material.dart';
abstract class HomeStackPage extends StatefulWidget {
final PageContext pageContext;
const HomeStackPage({Key? key, required this.pageContext}) : super(key: key);
}

View File

@ -0,0 +1,51 @@
import 'package:app_flowy/home/application/home_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../home_sizes.dart';
class HomeTopBar extends StatelessWidget {
const HomeTopBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: HomeInsets.topBarTitlePadding),
height: HomeSizes.topBarHeight,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
HomeTitle(),
],
),
);
}
}
class HomeTitle extends StatelessWidget {
final _editingController = TextEditingController(
text: '',
);
HomeTitle({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
_editingController.text =
context.read<HomeBloc>().state.pageContext.pageTitle;
return Expanded(
child: TextField(
controller: _editingController,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 28.0),
decoration: const InputDecoration(
hintText: 'Name the view',
border: UnderlineInputBorder(borderSide: BorderSide.none),
),
),
);
}
}

View File

@ -0,0 +1,4 @@
class HomeMenuSize {
static double get createViewButtonSize => 30;
static double get collapseIconSize => 24;
}

View File

@ -0,0 +1,121 @@
import 'package:app_flowy/home/application/menu/menu_bloc.dart';
import 'package:app_flowy/home/domain/page_context.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_style/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../home_sizes.dart';
import 'package:styled_widget/styled_widget.dart';
class HomeMenu extends StatelessWidget {
final Function(Option<PageContext>) pageContextChanged;
final Function(bool) isCollapseChanged;
const HomeMenu(
{Key? key,
required this.pageContextChanged,
required this.isCollapseChanged})
: super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<MenuBloc>(create: (context) => getIt<MenuBloc>()),
],
child: MultiBlocListener(
listeners: bind(),
child: Container(
color: Theme.of(context).colorScheme.primaryVariant,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: Insets.sm),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const MenuTopBar(),
Container(),
const NewAppButton(),
],
),
),
),
));
}
// bind the function passed by ooutter with the bloc listener
List<BlocListener<MenuBloc, MenuState>> bind() {
return [
BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.pageContext != c.pageContext,
listener: (context, state) => pageContextChanged(state.pageContext),
),
BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.isCollapse != c.isCollapse,
listener: (context, state) => isCollapseChanged(state.isCollapse),
)
];
}
}
class MenuTopBar extends StatelessWidget {
const MenuTopBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<MenuBloc, MenuState>(
builder: (context, state) {
return SizedBox(
height: HomeSizes.menuTopBarHeight,
child: Row(
children: [
const Text(
'AppFlowy',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
).constrained(minWidth: 100),
const Spacer(),
IconButton(
icon: const Icon(Icons.arrow_left),
onPressed: () =>
context.read<MenuBloc>().add(const MenuEvent.collapse()),
),
],
),
);
},
);
}
}
class NewAppButton extends StatelessWidget {
const NewAppButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: HomeSizes.menuAddButtonHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Icon(Icons.add),
const SizedBox(
width: 10,
),
TextButton(
onPressed: () async {
// Dialogs.show(OkCancelDialog(
// title: "No Connection",
// message:
// "It appears your device is offline. Please check your connection and try again.",
// onOkPressed: () => AppGlobals.nav.pop(),
// ));
},
child: const Text('New App',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20)),
)
],
),
);
}
}

View File

@ -0,0 +1,2 @@
export 'home_menu.dart';
export 'hom_menu_size.dart';

View File

@ -1,6 +1,6 @@
import 'package:app_flowy/startup/launch.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/welcome/infrastructure/deps_impl.dart';
import 'package:app_flowy/welcome/infrastructure/interface_impl.dart';
import 'package:flowy_sdk/flowy_sdk.dart';
import 'package:get_it/get_it.dart';

View File

@ -16,7 +16,7 @@ enum LaunchTaskType {
/// some nonresident indispensable task in app launching task.
abstract class LaunchTask {
LaunchTaskType get type => LaunchTaskType.dataProcessing;
void initialize(LaunchContext context);
Future<void> initialize(LaunchContext context);
}
class AppLauncher {
@ -30,10 +30,10 @@ class AppLauncher {
tasks.add(task);
}
void launch() {
void launch() async {
final context = LaunchContext(getIt, env);
for (var task in tasks) {
task.initialize(context);
await task.initialize(context);
}
}
}

View File

@ -10,10 +10,12 @@ class AppWidgetTask extends LaunchTask {
LaunchTaskType get type => LaunchTaskType.appLauncher;
@override
void initialize(LaunchContext context) {
Future<void> initialize(LaunchContext context) {
final widget = context.getIt<AppFactory>().create();
final app = AppWidget(child: widget);
runApp(app);
return Future(() => {});
}
}

View File

@ -12,7 +12,7 @@ class RustSDKInitTask extends LaunchTask {
LaunchTaskType get type => LaunchTaskType.dataProcessing;
@override
void initialize(LaunchContext context) async {
Future<void> initialize(LaunchContext context) async {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = ApplicationBlocObserver();
@ -31,6 +31,8 @@ class RustSDKInitTask extends LaunchTask {
default:
assert(false, 'Unsupported env');
}
return Future(() => {});
}
}

View File

@ -1,5 +1,5 @@
import 'package:app_flowy/welcome/domain/auth_state.dart';
import 'package:app_flowy/welcome/domain/deps.dart';
import 'package:app_flowy/welcome/domain/interface.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -8,18 +8,14 @@ part 'welcome_state.dart';
part 'welcome_bloc.freezed.dart';
class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
final IWelcomeAuth authCheck;
WelcomeBloc(this.authCheck) : super(WelcomeState.initial());
final IWelcomeAuth authImpl;
WelcomeBloc(this.authImpl) : super(WelcomeState.initial());
@override
Stream<WelcomeState> mapEventToState(WelcomeEvent event) async* {
yield* event.map(
check: (val) async* {
add(const WelcomeEvent.authCheck());
yield state;
},
authCheck: (val) async* {
final authState = await authCheck.getAuthState();
getUser: (val) async* {
final authState = await authImpl.currentUserState();
yield state.copyWith(auth: authState);
},
);

View File

@ -16,12 +16,8 @@ final _privateConstructorUsedError = UnsupportedError(
class _$WelcomeEventTearOff {
const _$WelcomeEventTearOff();
_Check check() {
return const _Check();
}
_AuthCheck authCheck() {
return const _AuthCheck();
_GetUser getUser() {
return const _GetUser();
}
}
@ -32,27 +28,23 @@ const $WelcomeEvent = _$WelcomeEventTearOff();
mixin _$WelcomeEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() check,
required TResult Function() authCheck,
required TResult Function() getUser,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? check,
TResult Function()? authCheck,
TResult Function()? getUser,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Check value) check,
required TResult Function(_AuthCheck value) authCheck,
required TResult Function(_GetUser value) getUser,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Check value)? check,
TResult Function(_AuthCheck value)? authCheck,
TResult Function(_GetUser value)? getUser,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@ -75,34 +67,34 @@ class _$WelcomeEventCopyWithImpl<$Res> implements $WelcomeEventCopyWith<$Res> {
}
/// @nodoc
abstract class _$CheckCopyWith<$Res> {
factory _$CheckCopyWith(_Check value, $Res Function(_Check) then) =
__$CheckCopyWithImpl<$Res>;
abstract class _$GetUserCopyWith<$Res> {
factory _$GetUserCopyWith(_GetUser value, $Res Function(_GetUser) then) =
__$GetUserCopyWithImpl<$Res>;
}
/// @nodoc
class __$CheckCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
implements _$CheckCopyWith<$Res> {
__$CheckCopyWithImpl(_Check _value, $Res Function(_Check) _then)
: super(_value, (v) => _then(v as _Check));
class __$GetUserCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
implements _$GetUserCopyWith<$Res> {
__$GetUserCopyWithImpl(_GetUser _value, $Res Function(_GetUser) _then)
: super(_value, (v) => _then(v as _GetUser));
@override
_Check get _value => super._value as _Check;
_GetUser get _value => super._value as _GetUser;
}
/// @nodoc
class _$_Check implements _Check {
const _$_Check();
class _$_GetUser implements _GetUser {
const _$_GetUser();
@override
String toString() {
return 'WelcomeEvent.check()';
return 'WelcomeEvent.getUser()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Check);
return identical(this, other) || (other is _GetUser);
}
@override
@ -111,21 +103,19 @@ class _$_Check implements _Check {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() check,
required TResult Function() authCheck,
required TResult Function() getUser,
}) {
return check();
return getUser();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? check,
TResult Function()? authCheck,
TResult Function()? getUser,
required TResult orElse(),
}) {
if (check != null) {
return check();
if (getUser != null) {
return getUser();
}
return orElse();
}
@ -133,112 +123,26 @@ class _$_Check implements _Check {
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Check value) check,
required TResult Function(_AuthCheck value) authCheck,
required TResult Function(_GetUser value) getUser,
}) {
return check(this);
return getUser(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Check value)? check,
TResult Function(_AuthCheck value)? authCheck,
TResult Function(_GetUser value)? getUser,
required TResult orElse(),
}) {
if (check != null) {
return check(this);
if (getUser != null) {
return getUser(this);
}
return orElse();
}
}
abstract class _Check implements WelcomeEvent {
const factory _Check() = _$_Check;
}
/// @nodoc
abstract class _$AuthCheckCopyWith<$Res> {
factory _$AuthCheckCopyWith(
_AuthCheck value, $Res Function(_AuthCheck) then) =
__$AuthCheckCopyWithImpl<$Res>;
}
/// @nodoc
class __$AuthCheckCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
implements _$AuthCheckCopyWith<$Res> {
__$AuthCheckCopyWithImpl(_AuthCheck _value, $Res Function(_AuthCheck) _then)
: super(_value, (v) => _then(v as _AuthCheck));
@override
_AuthCheck get _value => super._value as _AuthCheck;
}
/// @nodoc
class _$_AuthCheck implements _AuthCheck {
const _$_AuthCheck();
@override
String toString() {
return 'WelcomeEvent.authCheck()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _AuthCheck);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() check,
required TResult Function() authCheck,
}) {
return authCheck();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? check,
TResult Function()? authCheck,
required TResult orElse(),
}) {
if (authCheck != null) {
return authCheck();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Check value) check,
required TResult Function(_AuthCheck value) authCheck,
}) {
return authCheck(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Check value)? check,
TResult Function(_AuthCheck value)? authCheck,
required TResult orElse(),
}) {
if (authCheck != null) {
return authCheck(this);
}
return orElse();
}
}
abstract class _AuthCheck implements WelcomeEvent {
const factory _AuthCheck() = _$_AuthCheck;
abstract class _GetUser implements WelcomeEvent {
const factory _GetUser() = _$_GetUser;
}
/// @nodoc

View File

@ -2,6 +2,5 @@ part of 'welcome_bloc.dart';
@freezed
abstract class WelcomeEvent with _$WelcomeEvent {
const factory WelcomeEvent.check() = _Check;
const factory WelcomeEvent.authCheck() = _AuthCheck;
const factory WelcomeEvent.getUser() = _GetUser;
}

View File

@ -7,6 +7,6 @@ abstract class WelcomeState implements _$WelcomeState {
}) = _WelcomeState;
factory WelcomeState.initial() => const WelcomeState(
auth: AuthState.unauthenticated(),
auth: AuthState.initial(),
);
}

View File

@ -1,8 +1,11 @@
import 'package:flowy_sdk/protobuf/errors.pb.dart';
import 'package:flowy_sdk/protobuf/user_detail.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'auth_state.freezed.dart';
@freezed
abstract class AuthState with _$AuthState {
const factory AuthState.authenticated() = Authenticated;
const factory AuthState.unauthenticated() = Unauthenticated;
const factory AuthState.authenticated(UserDetail userDetail) = Authenticated;
const factory AuthState.unauthenticated(UserError error) = Unauthenticated;
const factory AuthState.initial() = _Initial;
}

View File

@ -16,12 +16,20 @@ final _privateConstructorUsedError = UnsupportedError(
class _$AuthStateTearOff {
const _$AuthStateTearOff();
Authenticated authenticated() {
return const Authenticated();
Authenticated authenticated(UserDetail userDetail) {
return Authenticated(
userDetail,
);
}
Unauthenticated unauthenticated() {
return const Unauthenticated();
Unauthenticated unauthenticated(UserError error) {
return Unauthenticated(
error,
);
}
_Initial initial() {
return const _Initial();
}
}
@ -32,14 +40,16 @@ const $AuthState = _$AuthStateTearOff();
mixin _$AuthState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function(UserDetail userDetail) authenticated,
required TResult Function(UserError error) unauthenticated,
required TResult Function() initial,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function(UserDetail userDetail)? authenticated,
TResult Function(UserError error)? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@ -47,12 +57,14 @@ mixin _$AuthState {
TResult map<TResult extends Object?>({
required TResult Function(Authenticated value) authenticated,
required TResult Function(Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Authenticated value)? authenticated,
TResult Function(Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@ -78,6 +90,7 @@ abstract class $AuthenticatedCopyWith<$Res> {
factory $AuthenticatedCopyWith(
Authenticated value, $Res Function(Authenticated) then) =
_$AuthenticatedCopyWithImpl<$Res>;
$Res call({UserDetail userDetail});
}
/// @nodoc
@ -89,44 +102,71 @@ class _$AuthenticatedCopyWithImpl<$Res> extends _$AuthStateCopyWithImpl<$Res>
@override
Authenticated get _value => super._value as Authenticated;
@override
$Res call({
Object? userDetail = freezed,
}) {
return _then(Authenticated(
userDetail == freezed
? _value.userDetail
: userDetail // ignore: cast_nullable_to_non_nullable
as UserDetail,
));
}
}
/// @nodoc
class _$Authenticated implements Authenticated {
const _$Authenticated();
const _$Authenticated(this.userDetail);
@override
final UserDetail userDetail;
@override
String toString() {
return 'AuthState.authenticated()';
return 'AuthState.authenticated(userDetail: $userDetail)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Authenticated);
return identical(this, other) ||
(other is Authenticated &&
(identical(other.userDetail, userDetail) ||
const DeepCollectionEquality()
.equals(other.userDetail, userDetail)));
}
@override
int get hashCode => runtimeType.hashCode;
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(userDetail);
@JsonKey(ignore: true)
@override
$AuthenticatedCopyWith<Authenticated> get copyWith =>
_$AuthenticatedCopyWithImpl<Authenticated>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function(UserDetail userDetail) authenticated,
required TResult Function(UserError error) unauthenticated,
required TResult Function() initial,
}) {
return authenticated();
return authenticated(userDetail);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function(UserDetail userDetail)? authenticated,
TResult Function(UserError error)? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (authenticated != null) {
return authenticated();
return authenticated(userDetail);
}
return orElse();
}
@ -136,6 +176,7 @@ class _$Authenticated implements Authenticated {
TResult map<TResult extends Object?>({
required TResult Function(Authenticated value) authenticated,
required TResult Function(Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return authenticated(this);
}
@ -145,6 +186,7 @@ class _$Authenticated implements Authenticated {
TResult maybeMap<TResult extends Object?>({
TResult Function(Authenticated value)? authenticated,
TResult Function(Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (authenticated != null) {
@ -155,7 +197,12 @@ class _$Authenticated implements Authenticated {
}
abstract class Authenticated implements AuthState {
const factory Authenticated() = _$Authenticated;
const factory Authenticated(UserDetail userDetail) = _$Authenticated;
UserDetail get userDetail => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$AuthenticatedCopyWith<Authenticated> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
@ -163,6 +210,7 @@ abstract class $UnauthenticatedCopyWith<$Res> {
factory $UnauthenticatedCopyWith(
Unauthenticated value, $Res Function(Unauthenticated) then) =
_$UnauthenticatedCopyWithImpl<$Res>;
$Res call({UserError error});
}
/// @nodoc
@ -174,44 +222,70 @@ class _$UnauthenticatedCopyWithImpl<$Res> extends _$AuthStateCopyWithImpl<$Res>
@override
Unauthenticated get _value => super._value as Unauthenticated;
@override
$Res call({
Object? error = freezed,
}) {
return _then(Unauthenticated(
error == freezed
? _value.error
: error // ignore: cast_nullable_to_non_nullable
as UserError,
));
}
}
/// @nodoc
class _$Unauthenticated implements Unauthenticated {
const _$Unauthenticated();
const _$Unauthenticated(this.error);
@override
final UserError error;
@override
String toString() {
return 'AuthState.unauthenticated()';
return 'AuthState.unauthenticated(error: $error)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Unauthenticated);
return identical(this, other) ||
(other is Unauthenticated &&
(identical(other.error, error) ||
const DeepCollectionEquality().equals(other.error, error)));
}
@override
int get hashCode => runtimeType.hashCode;
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(error);
@JsonKey(ignore: true)
@override
$UnauthenticatedCopyWith<Unauthenticated> get copyWith =>
_$UnauthenticatedCopyWithImpl<Unauthenticated>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() authenticated,
required TResult Function() unauthenticated,
required TResult Function(UserDetail userDetail) authenticated,
required TResult Function(UserError error) unauthenticated,
required TResult Function() initial,
}) {
return unauthenticated();
return unauthenticated(error);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? authenticated,
TResult Function()? unauthenticated,
TResult Function(UserDetail userDetail)? authenticated,
TResult Function(UserError error)? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (unauthenticated != null) {
return unauthenticated();
return unauthenticated(error);
}
return orElse();
}
@ -221,6 +295,7 @@ class _$Unauthenticated implements Unauthenticated {
TResult map<TResult extends Object?>({
required TResult Function(Authenticated value) authenticated,
required TResult Function(Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return unauthenticated(this);
}
@ -230,6 +305,7 @@ class _$Unauthenticated implements Unauthenticated {
TResult maybeMap<TResult extends Object?>({
TResult Function(Authenticated value)? authenticated,
TResult Function(Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (unauthenticated != null) {
@ -240,5 +316,97 @@ class _$Unauthenticated implements Unauthenticated {
}
abstract class Unauthenticated implements AuthState {
const factory Unauthenticated() = _$Unauthenticated;
const factory Unauthenticated(UserError error) = _$Unauthenticated;
UserError get error => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$UnauthenticatedCopyWith<Unauthenticated> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$InitialCopyWith<$Res> {
factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
__$InitialCopyWithImpl<$Res>;
}
/// @nodoc
class __$InitialCopyWithImpl<$Res> extends _$AuthStateCopyWithImpl<$Res>
implements _$InitialCopyWith<$Res> {
__$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
: super(_value, (v) => _then(v as _Initial));
@override
_Initial get _value => super._value as _Initial;
}
/// @nodoc
class _$_Initial implements _Initial {
const _$_Initial();
@override
String toString() {
return 'AuthState.initial()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Initial);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(UserDetail userDetail) authenticated,
required TResult Function(UserError error) unauthenticated,
required TResult Function() initial,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(UserDetail userDetail)? authenticated,
TResult Function(UserError error)? unauthenticated,
TResult Function()? initial,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Authenticated value) authenticated,
required TResult Function(Unauthenticated value) unauthenticated,
required TResult Function(_Initial value) initial,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Authenticated value)? authenticated,
TResult Function(Unauthenticated value)? unauthenticated,
TResult Function(_Initial value)? initial,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements AuthState {
const factory _Initial() = _$_Initial;
}

View File

@ -1,12 +0,0 @@
import 'package:flutter/widgets.dart';
import 'auth_state.dart';
abstract class IWelcomeAuth {
Future<AuthState> getAuthState();
}
abstract class IWelcomeRoute {
Widget signIn();
Widget home();
}

View File

@ -0,0 +1,13 @@
import 'package:flowy_sdk/protobuf/user_detail.pb.dart';
import 'package:flutter/widgets.dart';
import 'auth_state.dart';
abstract class IWelcomeAuth {
Future<AuthState> currentUserState();
}
abstract class IWelcomeRoute {
Widget pushSignInScreen();
Widget pushHomeScreen(UserDetail userDetail);
}

View File

@ -1,38 +0,0 @@
import 'package:app_flowy/home/presentation/home_screen.dart';
import 'package:app_flowy/welcome/application/welcome_bloc.dart';
import 'package:app_flowy/welcome/domain/auth_state.dart';
import 'package:app_flowy/welcome/domain/deps.dart';
import 'package:flutter/widgets.dart';
import 'package:get_it/get_it.dart';
import 'package:time/time.dart';
class Welcome {
static Future<void> dependencyResolved(GetIt getIt) async {
getIt.registerFactory<IWelcomeAuth>(() => AuthCheck());
getIt.registerFactory<IWelcomeRoute>(() => WelcomeRoute());
getIt
.registerFactory<WelcomeBloc>(() => WelcomeBloc(getIt<IWelcomeAuth>()));
}
}
class AuthCheck implements IWelcomeAuth {
@override
Future<AuthState> getAuthState() async {
return Future<AuthState>.delayed(3.0.seconds, () {
return const AuthState.authenticated();
});
}
}
class WelcomeRoute implements IWelcomeRoute {
@override
Widget home() {
return const HomeScreen();
}
@override
Widget signIn() {
return Container();
}
}

View File

@ -0,0 +1,61 @@
import 'package:app_flowy/home/application/edit_pannel/edit_pannel_bloc.dart';
import 'package:app_flowy/home/application/home_bloc.dart';
import 'package:app_flowy/home/application/menu/menu_bloc.dart';
import 'package:app_flowy/home/application/watcher/home_watcher_bloc.dart';
import 'package:app_flowy/home/presentation/home_screen.dart';
import 'package:app_flowy/welcome/application/welcome_bloc.dart';
import 'package:app_flowy/welcome/domain/auth_state.dart';
import 'package:app_flowy/welcome/domain/interface.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/user_detail.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get_it/get_it.dart';
class Welcome {
static Future<void> dependencyResolved(GetIt getIt) async {
getIt.registerFactory<IWelcomeAuth>(() => WelcomeAuthImpl());
getIt.registerFactory<IWelcomeRoute>(() => WelcomeRoute());
getIt.registerFactory<HomeBloc>(() => HomeBloc());
getIt.registerFactory<HomeWatcherBloc>(() => HomeWatcherBloc());
getIt.registerFactory<EditPannelBloc>(() => EditPannelBloc());
getIt.registerFactory<MenuBloc>(() => MenuBloc());
getIt
.registerFactory<WelcomeBloc>(() => WelcomeBloc(getIt<IWelcomeAuth>()));
}
}
class WelcomeAuthImpl implements IWelcomeAuth {
@override
Future<AuthState> currentUserState() {
final result = UserEventGetStatus().send();
return result.then((result) {
return result.fold(
(userDetail) {
return AuthState.authenticated(userDetail);
},
(userError) {
return AuthState.unauthenticated(userError);
},
);
});
}
}
class WelcomeRoute implements IWelcomeRoute {
@override
Widget pushHomeScreen(UserDetail user) {
return HomeScreen(user);
}
@override
Widget pushSignInScreen() {
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
}

View File

@ -1,7 +1,8 @@
import 'package:app_flowy/welcome/domain/deps.dart';
import 'package:app_flowy/welcome/presentation/widgets/body.dart';
import 'package:app_flowy/welcome/domain/interface.dart';
import 'package:app_flowy/welcome/domain/auth_state.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/welcome/application/welcome_bloc.dart';
import 'package:flowy_logger/flowy_logger.dart';
import 'package:flowy_style/route/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -14,16 +15,15 @@ class WelcomeScreen extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) {
return getIt<WelcomeBloc>()..add(const WelcomeEvent.check());
return getIt<WelcomeBloc>()..add(const WelcomeEvent.getUser());
},
child: Scaffold(
body: BlocListener<WelcomeBloc, WelcomeState>(
listener: (context, state) {
state.auth.map(
authenticated: (_) =>
_pushToScreen(context, getIt<IWelcomeRoute>().home()),
unauthenticated: (_) =>
_pushToScreen(context, getIt<IWelcomeRoute>().signIn()),
authenticated: (r) => _handleAuthenticated(context, r),
unauthenticated: (r) => _handleUnauthenticated(context, r),
initial: (r) => {},
);
},
child: const Body(),
@ -34,11 +34,46 @@ class WelcomeScreen extends StatelessWidget {
void _pushToScreen(BuildContext context, Widget screen) {
/// Let the splash view sit for a bit. Mainly for aesthetics and to ensure a smooth intro animation.
Future<void>.delayed(1.0.seconds, () {
Navigator.push(
context,
PageRoutes.fade(
() => screen, RouteDurations.slow.inMilliseconds * .001));
});
Navigator.push(
context,
PageRoutes.fade(
() => screen, RouteDurations.slow.inMilliseconds * .001));
}
void _handleAuthenticated(BuildContext context, Authenticated result) {
_pushToScreen(
context, getIt<IWelcomeRoute>().pushHomeScreen(result.userDetail));
}
void _handleUnauthenticated(BuildContext context, Unauthenticated result) {
Log.error(result.error);
_pushToScreen(context, getIt<IWelcomeRoute>().pushSignInScreen());
}
}
class Body extends StatelessWidget {
const Body({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Container(
alignment: Alignment.center,
child: SingleChildScrollView(
child: Stack(
alignment: Alignment.center,
children: [
Image(
fit: BoxFit.cover,
width: size.width,
height: size.height,
image: const AssetImage(
'assets/images/appflowy_launch_splash.jpg')),
const CircularProgressIndicator.adaptive(),
],
),
),
);
}
}

View File

@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
class Body extends StatelessWidget {
const Body({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Container(
alignment: Alignment.center,
child: SingleChildScrollView(
child: Stack(
alignment: Alignment.center,
children: [
Image(
fit: BoxFit.cover,
width: size.width,
height: size.height,
image: const AssetImage(
'assets/images/appflowy_launch_splash.jpg')),
const CircularProgressIndicator.adaptive(),
],
),
),
);
}
}

View File

@ -7,7 +7,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.7.0"
boolean_selector:
dependency: transitive
description:
@ -28,7 +28,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.1"
clock:
dependency: transitive
description:
@ -94,7 +94,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
path:
dependency: transitive
description:
@ -148,7 +148,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.1"
typed_data:
dependency: transitive
description:

View File

@ -14,7 +14,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.7.0"
boolean_selector:
dependency: transitive
description:
@ -35,7 +35,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.1"
clock:
dependency: transitive
description:
@ -91,7 +91,7 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.1"
version: "6.1.2"
fixnum:
dependency: transitive
description:
@ -200,7 +200,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
path:
dependency: transitive
description:
@ -282,7 +282,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.1"
time:
dependency: transitive
description:
@ -317,7 +317,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "6.2.0"
version: "7.1.0"
webdriver:
dependency: transitive
description:

View File

@ -2,15 +2,12 @@ export 'package:async/async.dart';
import 'dart:io';
import 'dart:async';
import 'package:dartz/dartz.dart';
// import 'package:dartz/dartz.dart';
import 'package:flutter/services.dart';
import 'dart:ffi';
import 'ffi/ffi.dart' as ffi;
import 'package:ffi/ffi.dart';
import 'package:flowy_sdk/protobuf.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
class FlowySDK {
static const MethodChannel _channel = MethodChannel('flowy_sdk');
static Future<String> get platformVersion async {
@ -24,21 +21,6 @@ class FlowySDK {
Future<void> init(Directory sdkDir) async {
ffi.store_dart_post_cobject(NativeApi.postCObject);
ffi.init_sdk(sdkDir.path.toNativeUtf8());
final params = SignInRequest.create();
params.email = "nathan.fu@gmail.com";
params.password = "Helloworld!2";
Either<UserDetail, UserError> resp = await UserEventSignIn(params).send();
resp.fold(
(result) {
print(result);
},
(error) {
print(error);
},
);
}
}

View File

@ -1,10 +1,10 @@
// Auto-generated, do not edit
// Auto-generated, do not edit
export 'protobuf/kv.pb.dart';
export 'protobuf/ffi_response.pb.dart';
export 'protobuf/ffi_request.pb.dart';
export 'protobuf/user_status.pb.dart';
export 'protobuf/sign_up.pb.dart';
export 'protobuf/sign_in.pb.dart';
export 'protobuf/user_table.pb.dart';
export 'protobuf/errors.pb.dart';
export 'protobuf/user_detail.pb.dart';
export 'protobuf/event.pb.dart';

View File

@ -1,6 +1,6 @@
///
// Generated code. Do not modify.
// source: user_status.proto
// source: user_detail.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
@ -9,9 +9,9 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
import 'user_status.pbenum.dart';
import 'user_detail.pbenum.dart';
export 'user_status.pbenum.dart';
export 'user_detail.pbenum.dart';
class UserDetail extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UserDetail', createEmptyInstance: create)

View File

@ -1,6 +1,6 @@
///
// Generated code. Do not modify.
// source: user_status.proto
// source: user_detail.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

View File

@ -1,6 +1,6 @@
///
// Generated code. Do not modify.
// source: user_status.proto
// source: user_detail.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

View File

@ -1,9 +1,9 @@
///
// Generated code. Do not modify.
// source: user_status.proto
// source: user_detail.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
export 'user_status.pb.dart';
export 'user_detail.pb.dart';

View File

@ -28,7 +28,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.7.0"
boolean_selector:
dependency: transitive
description:
@ -105,7 +105,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
@ -325,7 +325,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
mime:
dependency: transitive
description:
@ -449,7 +449,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.1"
time:
dependency: transitive
description:

View File

@ -0,0 +1,143 @@
import 'package:flowy_style/size.dart';
import 'package:flowy_style/text_style.dart';
import 'package:flowy_style/theme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:provider/provider.dart';
class BaseStyledButton extends StatefulWidget {
final Widget child;
final VoidCallback? onPressed;
final Function(bool)? onFocusChanged;
final Function(bool)? onHighlightChanged;
final Color? bgColor;
final Color? focusColor;
final Color? hoverColor;
final Color? downColor;
final EdgeInsets? contentPadding;
final double? minWidth;
final double? minHeight;
final double? borderRadius;
final bool useBtnText;
final bool autoFocus;
final ShapeBorder? shape;
final Color outlineColor;
const BaseStyledButton({
Key? key,
required this.child,
this.onPressed,
this.onFocusChanged,
this.onHighlightChanged,
this.bgColor,
this.focusColor,
this.contentPadding,
this.minWidth,
this.minHeight,
this.borderRadius,
this.hoverColor,
this.downColor,
this.shape,
this.useBtnText = true,
this.autoFocus = false,
this.outlineColor = Colors.transparent,
}) : super(key: key);
@override
_BaseStyledBtnState createState() => _BaseStyledBtnState();
}
class _BaseStyledBtnState extends State<BaseStyledButton> {
late FocusNode _focusNode;
bool _isFocused = false;
@override
void initState() {
super.initState();
_focusNode = FocusNode(debugLabel: '', canRequestFocus: true);
_focusNode.addListener(() {
if (_focusNode.hasFocus != _isFocused) {
setState(() => _isFocused = _focusNode.hasFocus);
widget.onFocusChanged?.call(_isFocused);
}
});
}
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return Container(
decoration: BoxDecoration(
color: widget.bgColor ?? theme.surface,
borderRadius: BorderRadius.circular(widget.borderRadius ?? Corners.s5),
boxShadow: _isFocused
? [
BoxShadow(
color: theme.focus.withOpacity(0.25),
offset: Offset.zero,
blurRadius: 8.0,
spreadRadius: 0.0),
BoxShadow(
color: widget.bgColor ?? theme.surface,
offset: Offset.zero,
blurRadius: 8.0,
spreadRadius: -4.0),
]
: [],
),
foregroundDecoration: _isFocused
? ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1.8,
color: theme.focus,
),
borderRadius:
BorderRadius.circular(widget.borderRadius ?? Corners.s5),
),
)
: null,
child: RawMaterialButton(
focusNode: _focusNode,
autofocus: widget.autoFocus,
textStyle: widget.useBtnText ? TextStyles.Btn : null,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
splashColor: Colors.transparent,
mouseCursor: SystemMouseCursors.click,
elevation: 0,
hoverElevation: 0,
highlightElevation: 0,
focusElevation: 0,
fillColor: Colors.transparent,
hoverColor: widget.hoverColor ?? theme.surface,
highlightColor: widget.downColor ?? theme.accent1.withOpacity(.1),
focusColor: widget.focusColor ?? Colors.grey.withOpacity(0.35),
child: Opacity(
child: Padding(
padding: widget.contentPadding ?? EdgeInsets.all(Insets.m),
child: widget.child,
),
opacity: widget.onPressed != null ? 1 : .7,
),
constraints: BoxConstraints(
minHeight: widget.minHeight ?? 0, minWidth: widget.minWidth ?? 0),
onPressed: widget.onPressed,
shape: widget.shape ??
RoundedRectangleBorder(
side: BorderSide(color: widget.outlineColor, width: 1.5),
borderRadius:
BorderRadius.circular(widget.borderRadius ?? Corners.s5)),
),
);
}
}

View File

@ -0,0 +1,40 @@
import 'package:flowy_style/size.dart';
import 'package:flowy_style/spacing.dart';
import 'package:flowy_style/strings.dart';
import 'package:flutter/material.dart';
import 'primary_button.dart';
import 'secondary_button.dart';
class OkCancelButton extends StatelessWidget {
final VoidCallback? onOkPressed;
final VoidCallback? onCancelPressed;
final String? okTitle;
final String? cancelTitle;
final double? minHeight;
const OkCancelButton(
{Key? key,
this.onOkPressed,
this.onCancelPressed,
this.okTitle,
this.cancelTitle,
this.minHeight})
: super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (onOkPressed != null)
PrimaryTextButton(okTitle ?? S.BTN_OK.toUpperCase(),
onPressed: onOkPressed),
HSpace(Insets.m),
if (onCancelPressed != null)
SecondaryTextButton(cancelTitle ?? S.BTN_CANCEL.toUpperCase(),
onPressed: onCancelPressed),
],
);
}
}

View File

@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../size.dart';
import '../text_style.dart';
import '../theme.dart';
import 'base_styled_button.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:textstyle_extensions/textstyle_extensions.dart';
class PrimaryButton extends StatelessWidget {
final Widget child;
final VoidCallback? onPressed;
final bool bigMode;
const PrimaryButton(
{Key? key, required this.child, this.onPressed, this.bigMode = false})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return BaseStyledButton(
minWidth: bigMode ? 160 : 78,
minHeight: bigMode ? 60 : 42,
contentPadding: EdgeInsets.all(bigMode ? Insets.l : Insets.m),
bgColor: theme.accent1Darker,
hoverColor: theme.isDark ? theme.accent1 : theme.accent1Dark,
downColor: theme.accent1Darker,
borderRadius: bigMode ? Corners.s8 : Corners.s5,
child: child,
onPressed: onPressed,
);
}
}
class PrimaryTextButton extends StatelessWidget {
final String label;
final VoidCallback? onPressed;
final bool bigMode;
const PrimaryTextButton(this.label,
{Key? key, this.onPressed, this.bigMode = false})
: super(key: key);
@override
Widget build(BuildContext context) {
TextStyle txtStyle = (bigMode ? TextStyles.Callout : TextStyles.Footnote)
.textColor(Colors.white);
return PrimaryButton(
bigMode: bigMode,
onPressed: onPressed,
child: Text(label, style: txtStyle));
}
}

View File

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:textstyle_extensions/textstyle_extensions.dart';
import '../size.dart';
import '../styled_image_icon.dart';
import '../text_style.dart';
import '../theme.dart';
import 'base_styled_button.dart';
class SecondaryTextButton extends StatelessWidget {
final String label;
final VoidCallback? onPressed;
const SecondaryTextButton(this.label, {Key? key, this.onPressed})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
TextStyle txtStyle = TextStyles.Footnote.textColor(theme.accent1Darker);
return SecondaryButton(
onPressed: onPressed, child: Text(label, style: txtStyle));
}
}
class SecondaryIconButton extends StatelessWidget {
/// Must be either an `AssetImage` for an `ImageIcon` or an `IconData` for a regular `Icon`
final AssetImage icon;
final Function()? onPressed;
final Color? color;
const SecondaryIconButton(this.icon, {Key? key, this.onPressed, this.color})
: assert((icon is AssetImage) || (icon is IconData)),
super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return SecondaryButton(
onPressed: onPressed,
minHeight: 36,
minWidth: 36,
contentPadding: Insets.sm,
child: StyledImageIcon(icon, size: 20, color: color ?? theme.grey),
);
}
}
class SecondaryButton extends StatefulWidget {
final Widget child;
final VoidCallback? onPressed;
final double? minWidth;
final double? minHeight;
final double? contentPadding;
final Function(bool)? onFocusChanged;
const SecondaryButton(
{Key? key,
required this.child,
this.onPressed,
this.minWidth,
this.minHeight,
this.contentPadding,
this.onFocusChanged})
: super(key: key);
@override
_SecondaryButtonState createState() => _SecondaryButtonState();
}
class _SecondaryButtonState extends State<SecondaryButton> {
bool _isMouseOver = false;
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return MouseRegion(
onEnter: (_) => setState(() => _isMouseOver = true),
onExit: (_) => setState(() => _isMouseOver = false),
child: BaseStyledButton(
minWidth: widget.minWidth ?? 78,
minHeight: widget.minHeight ?? 42,
contentPadding: EdgeInsets.all(widget.contentPadding ?? Insets.m),
bgColor: theme.surface,
outlineColor:
(_isMouseOver ? theme.accent1 : theme.grey).withOpacity(.35),
hoverColor: theme.surface,
onFocusChanged: widget.onFocusChanged,
downColor: theme.greyWeak.withOpacity(.35),
borderRadius: Corners.s5,
child: IgnorePointer(child: widget.child),
onPressed: widget.onPressed,
),
);
}
}

View File

@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
extension ClickableExtensions on Widget {
Widget clickable(void Function() action, {bool opaque = true}) {
return GestureDetector(
behavior: opaque ? HitTestBehavior.opaque : HitTestBehavior.deferToChild,
onTap: action,
child: MouseRegion(
cursor: SystemMouseCursors.click,
opaque: opaque,
child: this,
),
);
}
}

View File

@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
class ConstrainedFlexView extends StatelessWidget {
final Widget child;
final double minSize;
final Axis axis;
final EdgeInsets scrollPadding;
const ConstrainedFlexView(this.minSize,
{Key? key,
required this.child,
this.axis = Axis.horizontal,
this.scrollPadding = EdgeInsets.zero})
: super(key: key);
bool get isHz => axis == Axis.horizontal;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (_, constraints) {
final viewSize = isHz ? constraints.maxWidth : constraints.maxHeight;
if (viewSize > minSize) return child;
return Padding(
padding: scrollPadding,
child: SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isHz ? double.infinity : minSize,
maxWidth: isHz ? minSize : double.infinity),
child: child,
),
),
);
},
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class DialogContext extends Equatable {
bool get barrierDismissable => true;
final String identifier;
const DialogContext({required this.identifier});
Widget buildWiget(BuildContext context);
}

View File

@ -0,0 +1,3 @@
class DialogSize {
static double get minDialogWidth => 380;
}

View File

@ -0,0 +1,218 @@
import 'package:flowy_style/buttons/ok_cancel_button.dart';
import 'package:flowy_style/dialog/dialog_size.dart';
import 'package:flowy_style/scrolling/styled_list.dart';
import 'package:flowy_style/size.dart';
import 'package:flowy_style/spacing.dart';
import 'package:flowy_style/text_style.dart';
import 'package:flowy_style/theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'dialog_context.dart';
export 'dialog_context.dart';
class Dialogs {
static Future<dynamic> show(Widget child, BuildContext context) async {
return await Navigator.of(context).push(
StyledDialogRoute(
pageBuilder: (BuildContext buildContext, Animation<double> animation,
Animation<double> secondaryAnimation) {
return SafeArea(child: child);
},
),
);
/*return await showDialog(
context: context ?? MainViewContext.value,
builder: (context) => child,
);*/
}
static Future<dynamic> showWithContext(
DialogContext dialogContext, BuildContext context) async {
return await Navigator.of(context).push(
StyledDialogRoute(
barrierDismissible: dialogContext.barrierDismissable,
pageBuilder: (BuildContext buildContext, Animation<double> animation,
Animation<double> secondaryAnimation) {
return SafeArea(child: dialogContext.buildWiget(buildContext));
},
),
);
}
}
class StyledDialogRoute<T> extends PopupRoute<T> {
StyledDialogRoute({
required RoutePageBuilder pageBuilder,
bool barrierDismissible = false,
String? barrierLabel,
Color barrierColor = const Color(0x80000000),
Duration transitionDuration = const Duration(milliseconds: 200),
RouteTransitionsBuilder? transitionBuilder,
RouteSettings? settings,
}) : _pageBuilder = pageBuilder,
_barrierDismissible = barrierDismissible,
_barrierLabel = barrierLabel ?? '',
_barrierColor = barrierColor,
_transitionDuration = transitionDuration,
_transitionBuilder = transitionBuilder,
super(settings: settings);
final RoutePageBuilder _pageBuilder;
@override
bool get barrierDismissible => _barrierDismissible;
final bool _barrierDismissible;
@override
String get barrierLabel => _barrierLabel;
final String _barrierLabel;
@override
Color get barrierColor => _barrierColor;
final Color _barrierColor;
@override
Duration get transitionDuration => _transitionDuration;
final Duration _transitionDuration;
final RouteTransitionsBuilder? _transitionBuilder;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return Semantics(
child: _pageBuilder(context, animation, secondaryAnimation),
scopesRoute: true,
explicitChildNodes: true,
);
}
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (_transitionBuilder == null) {
return FadeTransition(
opacity: CurvedAnimation(parent: animation, curve: Curves.linear),
child: child);
} else {
return _transitionBuilder!(context, animation, secondaryAnimation, child);
} // Some default transition
}
}
class StyledDialog extends StatelessWidget {
final Widget child;
final double? maxWidth;
final double? maxHeight;
final EdgeInsets? padding;
final EdgeInsets? margin;
final BorderRadius? borderRadius;
final Color? bgColor;
final bool shrinkWrap;
const StyledDialog({
Key? key,
required this.child,
this.maxWidth,
this.maxHeight,
this.padding,
this.margin,
this.bgColor,
this.borderRadius,
this.shrinkWrap = true,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final radius = borderRadius ?? Corners.s8Border;
final theme = context.watch<AppTheme>();
Widget innerContent = Container(
padding: padding ?? EdgeInsets.all(Insets.lGutter),
color: bgColor ?? theme.surface,
child: child,
);
if (shrinkWrap) {
innerContent =
IntrinsicWidth(child: IntrinsicHeight(child: innerContent));
}
return FocusTraversalGroup(
child: Container(
margin: margin ?? EdgeInsets.all(Insets.lGutter * 2),
alignment: Alignment.center,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: DialogSize.minDialogWidth,
maxHeight: maxHeight ?? double.infinity,
maxWidth: maxWidth ?? double.infinity,
),
child: ClipRRect(
borderRadius: radius,
child: SingleChildScrollView(
physics: StyledScrollPhysics(),
//https://medium.com/saugo360/https-medium-com-saugo360-flutter-using-overlay-to-display-floating-widgets-2e6d0e8decb9
child: Material(
type: MaterialType.transparency,
child: innerContent,
),
),
),
),
),
);
}
}
class OkCancelDialog extends StatelessWidget {
final VoidCallback? onOkPressed;
final VoidCallback? onCancelPressed;
final String? okTitle;
final String? cancelTitle;
final String? title;
final String message;
final double? maxWidth;
const OkCancelDialog(
{Key? key,
this.onOkPressed,
this.onCancelPressed,
this.okTitle,
this.cancelTitle,
this.title,
required this.message,
this.maxWidth})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return StyledDialog(
maxWidth: maxWidth ?? 500,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (title != null) ...[
Text(title!.toUpperCase(),
style: TextStyles.T1.textColor(theme.accent1Darker)),
VSpace(Insets.sm * 1.5),
Container(color: theme.greyWeak.withOpacity(.35), height: 1),
VSpace(Insets.m * 1.5),
],
Text(message, style: TextStyles.Body1.textHeight(1.5)),
SizedBox(height: Insets.l),
OkCancelButton(
onOkPressed: onOkPressed,
onCancelPressed: onCancelPressed,
okTitle: okTitle?.toUpperCase(),
cancelTitle: cancelTitle?.toUpperCase(),
)
],
),
);
}
}

View File

@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
typedef HoverBuilder = Widget Function(BuildContext context, bool isHovering);
class MouseHoverBuilder extends StatefulWidget {
final bool isClickable;
const MouseHoverBuilder(
{Key? key, required this.builder, this.isClickable = false})
: super(key: key);
final HoverBuilder builder;
@override
_MouseHoverBuilderState createState() => _MouseHoverBuilderState();
}
class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
bool isOver = false;
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: widget.isClickable
? SystemMouseCursors.click
: SystemMouseCursors.basic,
onEnter: (p) => setOver(true),
onExit: (p) => setOver(false),
child: widget.builder(context, isOver),
);
}
void setOver(bool value) => setState(() => isOver = value);
}

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class RoundedButton extends StatelessWidget {
final VoidCallback? press;
final String? title;
final Size? size;
const RoundedButton({
Key? key,
this.press,
this.title,
this.size,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: 100,
maxWidth: size?.width ?? double.infinity,
minHeight: 50,
maxHeight: size?.height ?? double.infinity,
),
child: Container(
margin: const EdgeInsets.symmetric(vertical: 10),
child: TextButton(
child: Text(title ?? ''),
onPressed: press,
),
),
);
}
}

View File

@ -0,0 +1,35 @@
import 'package:flowy_style/text_field_container.dart';
import 'package:flutter/material.dart';
class RoundedInputField extends StatelessWidget {
final String? hintText;
final IconData? icon;
final bool obscureText;
final ValueChanged<String>? onChanged;
const RoundedInputField({
Key? key,
this.hintText,
this.icon = Icons.person,
this.obscureText = false,
this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
onChanged: onChanged,
cursorColor: const Color(0xFF6F35A5),
obscureText: obscureText,
decoration: InputDecoration(
icon: Icon(
icon,
color: const Color(0xFF6F35A5),
),
hintText: hintText,
border: InputBorder.none,
),
));
}
}

View File

@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'styled_scroll_bar.dart';
class StyledScrollPhysics extends AlwaysScrollableScrollPhysics {}
/// Core ListView for the app.
/// Wraps a [ScrollbarListStack] + [ListView.builder] and assigns the 'Styled' scroll physics for the app
/// Exposes a controller so other widgets can manipulate the list
class StyledListView extends StatefulWidget {
final double? itemExtent;
final int? itemCount;
final Axis axis;
final EdgeInsets? padding;
final EdgeInsets? scrollbarPadding;
final double? barSize;
final IndexedWidgetBuilder itemBuilder;
StyledListView({
Key? key,
required this.itemBuilder,
required this.itemCount,
this.itemExtent,
this.axis = Axis.vertical,
this.padding,
this.barSize,
this.scrollbarPadding,
}) : super(key: key) {
assert(itemExtent != 0, 'Item extent should never be 0, null is ok.');
}
@override
StyledListViewState createState() => StyledListViewState();
}
/// State is public so this can easily be controlled externally
class StyledListViewState extends State<StyledListView> {
late ScrollController scrollController;
@override
void initState() {
scrollController = ScrollController();
super.initState();
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
void didUpdateWidget(StyledListView oldWidget) {
if (oldWidget.itemCount != widget.itemCount ||
oldWidget.itemExtent != widget.itemExtent) {
setState(() {});
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
final contentSize = (widget.itemCount ?? 0.0) * (widget.itemExtent ?? 00.0);
Widget listContent = ScrollbarListStack(
contentSize: contentSize,
axis: widget.axis,
controller: scrollController,
barSize: widget.barSize ?? 12,
scrollbarPadding: widget.scrollbarPadding,
child: ListView.builder(
padding: widget.padding,
scrollDirection: widget.axis,
physics: StyledScrollPhysics(),
controller: scrollController,
itemExtent: widget.itemExtent,
itemCount: widget.itemCount,
itemBuilder: (c, i) => widget.itemBuilder(c, i),
),
);
return listContent;
}
}

View File

@ -0,0 +1,243 @@
import 'dart:math';
import 'package:flowy_style/mouse_hover_builder.dart';
import 'package:flowy_style/size.dart';
import 'package:flowy_style/theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
class StyledScrollbar extends StatefulWidget {
final double? size;
final Axis axis;
final ScrollController controller;
final Function(double)? onDrag;
final bool showTrack;
final Color? handleColor;
final Color? trackColor;
// ignore: todo
// TODO: Remove contentHeight if we can fix this issue
// https://stackoverflow.com/questions/60855712/flutter-how-to-force-scrollcontroller-to-recalculate-position-maxextents
final double? contentSize;
const StyledScrollbar(
{Key? key,
this.size,
required this.axis,
required this.controller,
this.onDrag,
this.contentSize,
this.showTrack = false,
this.handleColor,
this.trackColor})
: super(key: key);
@override
ScrollbarState createState() => ScrollbarState();
}
class ScrollbarState extends State<StyledScrollbar> {
double _viewExtent = 100;
@override
void initState() {
widget.controller.addListener(() => setState(() {}));
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(StyledScrollbar oldWidget) {
if (oldWidget.contentSize != widget.contentSize) setState(() {});
super.didUpdateWidget(oldWidget);
}
// void calculateSize() {
// //[SB] Only hack I can find to make the ScrollController update it's maxExtents.
// //Call this whenever the content changes, so the scrollbar can recalculate it's size
// widget.controller.jumpTo(widget.controller.position.pixels + 1);
// Future.microtask(() => widget.controller
// .animateTo(widget.controller.position.pixels - 1, duration: 100.milliseconds, curve: Curves.linear));
// }
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return LayoutBuilder(
builder: (_, BoxConstraints constraints) {
double maxExtent;
final contentSize = widget.contentSize;
switch (widget.axis) {
case Axis.vertical:
// Use supplied contentSize if we have it, otherwise just fallback to maxScrollExtents
if (contentSize != null && contentSize > 0) {
maxExtent = contentSize - constraints.maxHeight;
} else {
maxExtent = widget.controller.position.maxScrollExtent;
}
_viewExtent = constraints.maxHeight;
break;
case Axis.horizontal:
// Use supplied contentSize if we have it, otherwise just fallback to maxScrollExtents
if (contentSize != null && contentSize > 0) {
maxExtent = contentSize - constraints.maxWidth;
} else {
maxExtent = widget.controller.position.maxScrollExtent;
}
_viewExtent = constraints.maxWidth;
break;
}
final contentExtent = maxExtent + _viewExtent;
// Calculate the alignment for the handle, this is a value between 0 and 1,
// it automatically takes the handle size into acct
// ignore: omit_local_variable_types
double handleAlignment =
maxExtent == 0 ? 0 : widget.controller.offset / maxExtent;
// Convert handle alignment from [0, 1] to [-1, 1]
handleAlignment *= 2.0;
handleAlignment -= 1.0;
// Calculate handleSize by comparing the total content size to our viewport
var handleExtent = _viewExtent;
if (contentExtent > _viewExtent) {
//Make sure handle is never small than the minSize
handleExtent = max(60, _viewExtent * _viewExtent / contentExtent);
}
// Hide the handle if content is < the viewExtent
var showHandle = contentExtent > _viewExtent && contentExtent > 0;
// Handle color
var handleColor = widget.handleColor ??
(theme.isDark ? theme.greyWeak.withOpacity(.2) : theme.greyWeak);
// Track color
var trackColor = widget.trackColor ??
(theme.isDark
? theme.greyWeak.withOpacity(.1)
: theme.greyWeak.withOpacity(.3));
//Layout the stack, it just contains a child, and
return Stack(children: <Widget>[
/// TRACK, thin strip, aligned along the end of the parent
if (widget.showTrack)
Align(
alignment: const Alignment(1, 1),
child: Container(
color: trackColor,
width: widget.axis == Axis.vertical
? widget.size
: double.infinity,
height: widget.axis == Axis.horizontal
? widget.size
: double.infinity,
),
),
/// HANDLE - Clickable shape that changes scrollController when dragged
Align(
// Use calculated alignment to position handle from -1 to 1, let Alignment do the rest of the work
alignment: Alignment(
widget.axis == Axis.vertical ? 1 : handleAlignment,
widget.axis == Axis.horizontal ? 1 : handleAlignment,
),
child: GestureDetector(
onVerticalDragUpdate: _handleVerticalDrag,
onHorizontalDragUpdate: _handleHorizontalDrag,
// HANDLE SHAPE
child: MouseHoverBuilder(
builder: (_, isHovered) => Container(
width:
widget.axis == Axis.vertical ? widget.size : handleExtent,
height: widget.axis == Axis.horizontal
? widget.size
: handleExtent,
decoration: BoxDecoration(
color: handleColor.withOpacity(isHovered ? 1 : .85),
borderRadius: Corners.s3Border),
),
),
),
)
]).opacity(showHandle ? 1.0 : 0.0, animate: false);
},
);
}
void _handleHorizontalDrag(DragUpdateDetails details) {
var pos = widget.controller.offset;
var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) /
_viewExtent;
widget.controller.jumpTo((pos + details.delta.dx * pxRatio)
.clamp(0.0, widget.controller.position.maxScrollExtent));
widget.onDrag?.call(details.delta.dx);
}
void _handleVerticalDrag(DragUpdateDetails details) {
var pos = widget.controller.offset;
var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) /
_viewExtent;
widget.controller.jumpTo((pos + details.delta.dy * pxRatio)
.clamp(0.0, widget.controller.position.maxScrollExtent));
widget.onDrag?.call(details.delta.dy);
}
}
class ScrollbarListStack extends StatelessWidget {
final double barSize;
final Axis axis;
final Widget child;
final ScrollController controller;
final double? contentSize;
final EdgeInsets? scrollbarPadding;
final Color? handleColor;
final Color? trackColor;
const ScrollbarListStack(
{Key? key,
required this.barSize,
required this.axis,
required this.child,
required this.controller,
this.contentSize,
this.scrollbarPadding,
this.handleColor,
this.trackColor})
: super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
/// LIST
/// Wrap with a bit of padding on the right
child.padding(
right: axis == Axis.vertical ? barSize + Insets.sm : 0,
bottom: axis == Axis.horizontal ? barSize + Insets.sm : 0,
),
/// SCROLLBAR
Padding(
padding: scrollbarPadding ?? EdgeInsets.zero,
child: StyledScrollbar(
size: barSize,
axis: axis,
controller: controller,
contentSize: contentSize,
trackColor: trackColor,
handleColor: handleColor,
showTrack: true,
),
),
],
);
}
}

View File

@ -0,0 +1,135 @@
import 'package:flutter/material.dart';
import 'styled_list.dart';
import 'styled_scroll_bar.dart';
class StyledSingleChildScrollView extends StatefulWidget {
final double? contentSize;
final Axis axis;
final Color? trackColor;
final Color? handleColor;
final ScrollController? controller;
final Widget? child;
const StyledSingleChildScrollView({
Key? key,
@required this.child,
this.contentSize,
this.axis = Axis.vertical,
this.trackColor,
this.handleColor,
this.controller,
}) : super(key: key);
@override
_StyledSingleChildScrollViewState createState() =>
_StyledSingleChildScrollViewState();
}
class _StyledSingleChildScrollViewState
extends State<StyledSingleChildScrollView> {
late ScrollController scrollController;
@override
void initState() {
scrollController = widget.controller ?? ScrollController();
super.initState();
}
@override
void dispose() {
// scrollController.dispose();
super.dispose();
}
@override
void didUpdateWidget(StyledSingleChildScrollView oldWidget) {
if (oldWidget.child != widget.child) {
setState(() {});
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return ScrollbarListStack(
contentSize: widget.contentSize,
axis: widget.axis,
controller: scrollController,
barSize: 12,
trackColor: widget.trackColor,
handleColor: widget.handleColor,
child: SingleChildScrollView(
scrollDirection: widget.axis,
physics: StyledScrollPhysics(),
controller: scrollController,
child: widget.child,
),
);
}
}
class StyledCustomScrollView extends StatefulWidget {
final double? contentSize;
final Axis axis;
final Color? trackColor;
final Color? handleColor;
final ScrollController? controller;
final List<Widget> slivers;
const StyledCustomScrollView({
Key? key,
this.contentSize,
this.axis = Axis.vertical,
this.trackColor,
this.handleColor,
this.controller,
this.slivers = const <Widget>[],
}) : super(key: key);
@override
_StyledCustomScrollViewState createState() => _StyledCustomScrollViewState();
}
class _StyledCustomScrollViewState extends State<StyledCustomScrollView> {
late ScrollController scrollController;
@override
void initState() {
scrollController = widget.controller ?? ScrollController();
super.initState();
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
void didUpdateWidget(StyledCustomScrollView oldWidget) {
if (oldWidget.slivers != widget.slivers) {
setState(() {});
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return ScrollbarListStack(
contentSize: widget.contentSize,
axis: widget.axis,
controller: scrollController,
barSize: 12,
trackColor: widget.trackColor,
handleColor: widget.handleColor,
child: CustomScrollView(
scrollDirection: widget.axis,
physics: StyledScrollPhysics(),
controller: scrollController,
slivers: widget.slivers,
),
);
}
}

View File

@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
typedef SeparatorBuilder = Widget Function();
class SeparatedColumn extends StatelessWidget {
final List<Widget> children;
final SeparatorBuilder? separatorBuilder;
final MainAxisAlignment mainAxisAlignment;
final CrossAxisAlignment crossAxisAlignment;
final MainAxisSize mainAxisSize;
final TextBaseline? textBaseline;
final TextDirection? textDirection;
final VerticalDirection verticalDirection;
const SeparatedColumn({
Key? key,
required this.children,
this.separatorBuilder,
this.mainAxisAlignment = MainAxisAlignment.start,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.mainAxisSize = MainAxisSize.max,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
this.textDirection,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var c = children.toList();
for (var i = c.length; i-- > 0;) {
if (i > 0 && separatorBuilder != null) c.insert(i, separatorBuilder!());
}
return Column(
children: c,
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
mainAxisSize: mainAxisSize,
textBaseline: textBaseline,
textDirection: textDirection,
verticalDirection: verticalDirection,
);
}
}

View File

@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
class PageBreaks {
static double get largePhone => 550;
static double get tabletPortrait => 768;
static double get tabletLandscape => 1024;
static double get desktop => 1440;
}
class Insets {
static double gutterScale = 1;
static double scale = 1;
/// Dynamic insets, may get scaled with the device size
static double get mGutter => m * gutterScale;
static double get lGutter => l * gutterScale;
static double get xs => 2 * scale;
static double get sm => 6 * scale;
static double get m => 12 * scale;
static double get l => 24 * scale;
static double get xl => 36 * scale;
}
class FontSizes {
static double get scale => 1;
static double get s11 => 11 * scale;
static double get s12 => 12 * scale;
static double get s14 => 14 * scale;
static double get s16 => 16 * scale;
static double get s18 => 18 * scale;
}
class Sizes {
static double hitScale = 1;
static double get hit => 40 * hitScale;
static double get iconMed => 20;
static double get sideBarSm => 200 * hitScale;
static double get sideBarMed => 220 * hitScale;
static double get sideBarLg => 290 * hitScale;
}
class Corners {
static double get btn => s5;
static double get dialog => 12;
/// Xs
static double get s3 => 3;
static BorderRadius get s3Border => BorderRadius.all(s3Radius);
static Radius get s3Radius => Radius.circular(s3);
/// Small
static double get s5 => 5;
static BorderRadius get s5Border => BorderRadius.all(s5Radius);
static Radius get s5Radius => Radius.circular(s5);
/// Medium
static double get s8 => 8;
static BorderRadius get s8Border => BorderRadius.all(s8Radius);
static Radius get s8Radius => Radius.circular(s8);
/// Large
static double get s10 => 10;
static BorderRadius get s10Border => BorderRadius.all(s10Radius);
static Radius get s10Radius => Radius.circular(s10);
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/cupertino.dart';
class Space extends StatelessWidget {
final double width;
final double height;
const Space(this.width, this.height, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => SizedBox(width: width, height: height);
}
class VSpace extends StatelessWidget {
final double size;
const VSpace(this.size, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Space(0, size);
}
class HSpace extends StatelessWidget {
final double size;
const HSpace(this.size, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Space(size, 0);
}

View File

@ -0,0 +1,60 @@
// ignore_for_file: non_constant_identifier_names
class _Strings {
static _Strings instance = _Strings();
String TITLE_CONTACTS_PAGE = "Contacts";
String TITLE_WHATS_HAPPENING = "What's happening this week?";
String TITLE_ADD_CONTACT = "Add Contact";
String TITLE_EDIT_CONTACT = "Edit Contact";
String BTN_OK = "Ok";
String BTN_CANCEL = "Cancel";
String BTN_SIGN_IN = "Sign In";
String BTN_SIGN_OUT = "Sign Out";
String BTN_COMPLETE = "Complete";
String BTN_SAVE = "Save";
String LBL_WELCOME = "Welcome!";
String LBL_NAME_FIRST = "First Name";
String LBL_NAME_MIDDLE = "Middle Name";
String LBL_NAME_LAST = "Last Name";
String LBL_STEP_X = "Step {0}";
String ERR_DEVICE_OAUTH_FAILED_TITLE = "Unable to connect to your account.";
String ERR_DEVICE_OAUTH_FAILED_MSG =
"Please make sure you've completed the sign-in process in your browser.";
String GOOGLE_OAUTH_TITLE = "GOOGLE SIGN-IN";
String GOOGLE_OAUTH_INSTRUCTIONS_1 =
"In order to import your Google Contacts, you'll need to authorize this application using your web browser.";
String GOOGLE_OAUTH_INSTRUCTIONS_2 =
"Copy this code to your clipboard by clicking the icon or selecting the text:";
String GOOGLE_OAUTH_INSTRUCTIONS_3 =
"Navigate to the following link in your web browser, and enter the above code:";
String GOOGLE_OAUTH_INSTRUCTIONS_4 =
"Press the button below when you've completed signup:";
}
_Strings get S => _Strings.instance;
extension AddSupplant on String {
String sup(
[dynamic v0,
dynamic v1,
dynamic v2,
dynamic v3,
dynamic v4,
dynamic v5,
dynamic v6]) {
var _s = this;
if (v0 != null) _s = _s.replaceAll("{0}", "$v0");
if (v1 != null) _s = _s.replaceAll("{1}", "$v1");
if (v2 != null) _s = _s.replaceAll("{2}", "$v2");
if (v3 != null) _s = _s.replaceAll("{3}", "$v3");
if (v4 != null) _s = _s.replaceAll("{4}", "$v4");
if (v5 != null) _s = _s.replaceAll("{5}", "$v5");
if (v6 != null) _s = _s.replaceAll("{6}", "$v6");
return _s;
}
}

View File

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
class StyleBarTitle extends StatelessWidget {
final String title;
const StyleBarTitle({
Key? key,
required this.title,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
title,
style: const TextStyle(fontSize: 24),
);
}
}

View File

@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class StyleCloseButton extends StatelessWidget {
final VoidCallback? onPressed;
const StyleCloseButton({
Key? key,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextButton(onPressed: onPressed, child: const Icon(Icons.close));
}
}

View File

@ -0,0 +1,44 @@
import 'package:flowy_style/time/duration.dart';
import 'package:flutter/material.dart';
class StyledContainer extends StatelessWidget {
final Color color;
final BorderRadiusGeometry? borderRadius;
final List<BoxShadow>? shadows;
final Widget? child;
final double? width;
final double? height;
final Alignment? align;
final EdgeInsets? margin;
final Duration? duration;
final BoxBorder? border;
const StyledContainer(this.color,
{Key? key,
this.borderRadius,
this.shadows,
this.child,
this.width,
this.height,
this.align,
this.margin,
this.duration,
this.border})
: super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
width: width,
height: height,
child: child,
margin: margin,
alignment: align,
duration: duration ?? Durations.medium,
decoration: BoxDecoration(
color: color,
borderRadius: borderRadius,
boxShadow: shadows,
border: border));
}
}

View File

@ -0,0 +1,17 @@
import 'package:flowy_style/size.dart';
import 'package:flutter/material.dart';
class StyledImageIcon extends StatelessWidget {
final AssetImage image;
final Color? color;
final double? size;
const StyledImageIcon(this.image, {Key? key, this.color, this.size})
: super(key: key);
@override
Widget build(BuildContext context) {
return ImageIcon(image,
size: size ?? Sizes.iconMed, color: color ?? Colors.white);
}
}

View File

@ -0,0 +1,354 @@
import 'dart:async';
import 'dart:math' as math;
import 'package:flowy_style/size.dart';
import 'package:flowy_style/text_style.dart';
import 'package:flowy_style/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:textstyle_extensions/textstyle_extensions.dart';
class StyledFormTextInput extends StatelessWidget {
static EdgeInsets kDefaultTextInputPadding =
EdgeInsets.only(bottom: Insets.sm, top: 4);
final String? label;
final bool? autoFocus;
final String? initialValue;
final String? hintText;
final EdgeInsets? contentPadding;
final TextStyle? textStyle;
final int? maxLines;
final TextEditingController? controller;
final TextCapitalization? capitalization;
final Function(String)? onChanged;
final Function()? onEditingComplete;
final Function(bool)? onFocusChanged;
final Function(FocusNode)? onFocusCreated;
const StyledFormTextInput(
{Key? key,
this.label,
this.autoFocus,
this.initialValue,
this.onChanged,
this.onEditingComplete,
this.hintText,
this.onFocusChanged,
this.onFocusCreated,
this.controller,
this.contentPadding,
this.capitalization,
this.textStyle,
this.maxLines})
: super(key: key);
@override
Widget build(BuildContext context) {
return StyledSearchTextInput(
capitalization: capitalization,
label: label,
autoFocus: autoFocus,
initialValue: initialValue,
onChanged: onChanged,
onFocusCreated: onFocusCreated,
style: textStyle ?? TextStyles.Body1,
onEditingComplete: onEditingComplete,
onFocusChanged: onFocusChanged,
controller: controller,
maxLines: maxLines,
inputDecoration: InputDecoration(
isDense: true,
contentPadding: contentPadding ?? kDefaultTextInputPadding,
border: const ThinUnderlineBorder(
borderSide: BorderSide(width: 5, color: Colors.red)),
//focusedBorder: UnderlineInputBorder(borderSide: BorderSide(width: .5, color: Colors.red)),
hintText: hintText,
),
);
}
}
class StyledSearchTextInput extends StatefulWidget {
final String? label;
final TextStyle? style;
final EdgeInsets? contentPadding;
final bool? autoFocus;
final bool? obscureText;
final IconData? icon;
final String? initialValue;
final int? maxLines;
final TextEditingController? controller;
final TextCapitalization? capitalization;
final TextInputType? type;
final bool? enabled;
final bool? autoValidate;
final bool? enableSuggestions;
final bool? autoCorrect;
final String? errorText;
final String? hintText;
final Widget? prefixIcon;
final Widget? suffixIcon;
final InputDecoration? inputDecoration;
final Function(String)? onChanged;
final Function()? onEditingComplete;
final Function()? onEditingCancel;
final Function(bool)? onFocusChanged;
final Function(FocusNode)? onFocusCreated;
final Function(String)? onFieldSubmitted;
final Function(String?)? onSaved;
final VoidCallback? onTap;
const StyledSearchTextInput({
Key? key,
this.label,
this.autoFocus = false,
this.obscureText = false,
this.type = TextInputType.text,
this.icon,
this.initialValue = '',
this.controller,
this.enabled,
this.autoValidate = false,
this.enableSuggestions = true,
this.autoCorrect = true,
this.errorText,
this.style,
this.contentPadding,
this.prefixIcon,
this.suffixIcon,
this.inputDecoration,
this.onChanged,
this.onEditingComplete,
this.onEditingCancel,
this.onFocusChanged,
this.onFocusCreated,
this.onFieldSubmitted,
this.onSaved,
this.onTap,
this.hintText,
this.capitalization,
this.maxLines,
}) : super(key: key);
@override
StyledSearchTextInputState createState() => StyledSearchTextInputState();
}
class StyledSearchTextInputState extends State<StyledSearchTextInput> {
late TextEditingController _controller;
late FocusNode _focusNode;
@override
void initState() {
_controller =
widget.controller ?? TextEditingController(text: widget.initialValue);
_focusNode = FocusNode(
debugLabel: widget.label ?? '',
onKey: (FocusNode node, RawKeyEvent evt) {
if (evt is RawKeyDownEvent) {
if (evt.logicalKey == LogicalKeyboardKey.escape) {
widget.onEditingCancel?.call();
return KeyEventResult.handled;
}
}
return KeyEventResult.ignored;
},
canRequestFocus: true,
);
// Listen for focus out events
_focusNode
.addListener(() => widget.onFocusChanged?.call(_focusNode.hasFocus));
widget.onFocusCreated?.call(_focusNode);
if (widget.autoFocus ?? false) {
scheduleMicrotask(() => _focusNode.requestFocus());
}
super.initState();
}
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
void clear() => _controller.clear();
String get text => _controller.text;
set text(String value) => _controller.text = value;
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return Container(
padding: EdgeInsets.symmetric(vertical: Insets.sm),
child: TextFormField(
onChanged: widget.onChanged,
onEditingComplete: widget.onEditingComplete,
onFieldSubmitted: widget.onFieldSubmitted,
onSaved: widget.onSaved,
onTap: widget.onTap,
autofocus: widget.autoFocus ?? false,
focusNode: _focusNode,
keyboardType: widget.type,
obscureText: widget.obscureText ?? false,
autocorrect: widget.autoCorrect ?? false,
enableSuggestions: widget.enableSuggestions ?? false,
style: widget.style ?? TextStyles.Body1,
cursorColor: theme.accent1,
controller: _controller,
showCursor: true,
enabled: widget.enabled,
maxLines: widget.maxLines,
textCapitalization: widget.capitalization ?? TextCapitalization.none,
decoration: widget.inputDecoration ??
InputDecoration(
prefixIcon: widget.prefixIcon,
suffixIcon: widget.suffixIcon,
contentPadding:
widget.contentPadding ?? EdgeInsets.all(Insets.m),
border: const OutlineInputBorder(borderSide: BorderSide.none),
isDense: true,
icon: widget.icon == null ? null : Icon(widget.icon),
errorText: widget.errorText,
errorMaxLines: 2,
hintText: widget.hintText,
hintStyle: TextStyles.Body1.textColor(theme.grey),
labelText: widget.label),
),
);
}
}
class ThinUnderlineBorder extends InputBorder {
/// Creates an underline border for an [InputDecorator].
///
/// The [borderSide] parameter defaults to [BorderSide.none] (it must not be
/// null). Applications typically do not specify a [borderSide] parameter
/// because the input decorator substitutes its own, using [copyWith], based
/// on the current theme and [InputDecorator.isFocused].
///
/// The [borderRadius] parameter defaults to a value where the top left
/// and right corners have a circular radius of 4.0. The [borderRadius]
/// parameter must not be null.
const ThinUnderlineBorder({
BorderSide borderSide = const BorderSide(),
this.borderRadius = const BorderRadius.only(
topLeft: Radius.circular(4.0),
topRight: Radius.circular(4.0),
),
}) : super(borderSide: borderSide);
/// The radii of the border's rounded rectangle corners.
///
/// When this border is used with a filled input decorator, see
/// [InputDecoration.filled], the border radius defines the shape
/// of the background fill as well as the bottom left and right
/// edges of the underline itself.
///
/// By default the top right and top left corners have a circular radius
/// of 4.0.
final BorderRadius borderRadius;
@override
bool get isOutline => false;
@override
UnderlineInputBorder copyWith(
{BorderSide? borderSide, BorderRadius? borderRadius}) {
return UnderlineInputBorder(
borderSide: borderSide ?? this.borderSide,
borderRadius: borderRadius ?? this.borderRadius,
);
}
@override
EdgeInsetsGeometry get dimensions {
return EdgeInsets.only(bottom: borderSide.width);
}
@override
UnderlineInputBorder scale(double t) {
return UnderlineInputBorder(borderSide: borderSide.scale(t));
}
@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path()
..addRect(Rect.fromLTWH(rect.left, rect.top, rect.width,
math.max(0.0, rect.height - borderSide.width)));
}
@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
return Path()..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
}
@override
ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
if (a is UnderlineInputBorder) {
final newBorderRadius =
BorderRadius.lerp(a.borderRadius, borderRadius, t);
if (newBorderRadius != null) {
return UnderlineInputBorder(
borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
borderRadius: newBorderRadius,
);
}
}
return super.lerpFrom(a, t);
}
@override
ShapeBorder? lerpTo(ShapeBorder? b, double t) {
if (b is UnderlineInputBorder) {
final newBorderRadius =
BorderRadius.lerp(b.borderRadius, borderRadius, t);
if (newBorderRadius != null) {
return UnderlineInputBorder(
borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
borderRadius: newBorderRadius,
);
}
}
return super.lerpTo(b, t);
}
/// Draw a horizontal line at the bottom of [rect].
///
/// The [borderSide] defines the line's color and weight. The `textDirection`
/// `gap` and `textDirection` parameters are ignored.
/// @override
@override
void paint(
Canvas canvas,
Rect rect, {
double? gapStart,
double gapExtent = 0.0,
double gapPercentage = 0.0,
TextDirection? textDirection,
}) {
if (borderRadius.bottomLeft != Radius.zero ||
borderRadius.bottomRight != Radius.zero) {
canvas.clipPath(getOuterPath(rect, textDirection: textDirection));
}
canvas.drawLine(rect.bottomLeft, rect.bottomRight, borderSide.toPaint());
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
return other is InputBorder && other.borderSide == borderSide;
}
@override
int get hashCode => borderSide.hashCode;
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class TextFieldContainer extends StatelessWidget {
final Widget child;
const TextFieldContainer({
Key? key,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: child,
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<Widget>('child', child));
}
}

View File

@ -14,7 +14,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.7.0"
boolean_selector:
dependency: transitive
description:
@ -35,7 +35,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.1"
clock:
dependency: transitive
description:
@ -64,6 +64,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0-nullsafety.2"
equatable:
dependency: "direct main"
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
fake_async:
dependency: transitive
description:
@ -95,6 +102,13 @@ packages:
relative: true
source: path
version: "0.0.1"
lint:
dependency: transitive
description:
name: lint
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.3"
lints:
dependency: transitive
description:
@ -115,7 +129,14 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.4.0"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
@ -123,6 +144,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
provider:
dependency: "direct main"
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
sky_engine:
dependency: transitive
description: flutter
@ -156,6 +184,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
styled_widget:
dependency: "direct main"
description:
name: styled_widget
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1+2"
term_glyph:
dependency: transitive
description:
@ -169,7 +204,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.1"
textstyle_extensions:
dependency: "direct main"
description:

View File

@ -17,6 +17,9 @@ dependencies:
textstyle_extensions: '2.0.0-nullsafety'
animations: ^2.0.0
dartz: '0.10.0-nullsafety.2'
provider: ^5.0.0
styled_widget: '>=0.3.1'
equatable: '>=2.0.2'
dev_dependencies:
flutter_test:

View File

@ -197,6 +197,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
expandable:
dependency: "direct main"
description:
name: expandable
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.4"
fake_async:
dependency: transitive
description:
@ -233,7 +240,7 @@ packages:
source: path
version: "0.0.1"
flowy_logger:
dependency: transitive
dependency: "direct main"
description:
path: "packages/flowy_logger"
relative: true
@ -401,6 +408,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
lint:
dependency: transitive
description:
name: lint
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.3"
lints:
dependency: transitive
description:
@ -599,6 +613,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
sized_context:
dependency: "direct main"
description:
name: sized_context
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0+1"
sky_engine:
dependency: transitive
description: flutter
@ -653,6 +674,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
styled_widget:
dependency: "direct main"
description:
name: styled_widget
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1+2"
term_glyph:
dependency: transitive
description:
@ -702,6 +730,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
universal_platform:
dependency: transitive
description:
name: universal_platform
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0+1"
url_launcher:
dependency: transitive
description:

View File

@ -35,6 +35,8 @@ dependencies:
path: packages/flowy_style
flowy_editor:
path: packages/flowy_editor
flowy_logger:
path: packages/flowy_logger
# third party packages
time: '>=2.0.0'
@ -48,6 +50,9 @@ dependencies:
url: git://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
ref: e48abe7c3e9ebfe0b81622167c5201d4e783bb81
sized_context: ^1.0.0+1
styled_widget: '>=0.3.1'
expandable: ^4.1.4
# The following adds the Cupertino Icons font to your application.

View File

@ -1,15 +1,15 @@
mod sign_in;
mod sign_up;
mod user_detail;
mod user_email;
mod user_id;
mod user_name;
mod user_password;
mod user_status;
pub use sign_in::*;
pub use sign_up::*;
pub use user_detail::*;
pub use user_email::*;
pub use user_id::*;
pub use user_name::*;
pub use user_password::*;
pub use user_status::*;

View File

@ -1,8 +1,5 @@
// Auto-generated, do not edit
mod user_status;
pub use user_status::*;
mod sign_up;
pub use sign_up::*;
@ -15,5 +12,8 @@ pub use user_table::*;
mod errors;
pub use errors::*;
mod user_detail;
pub use user_detail::*;
mod event;
pub use event::*;

View File

@ -17,7 +17,7 @@
#![allow(trivial_casts)]
#![allow(unused_imports)]
#![allow(unused_results)]
//! Generated file from `user_status.proto`
//! Generated file from `user_detail.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
@ -309,28 +309,28 @@ impl ::protobuf::reflect::ProtobufValue for UserStatus {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x11user_status.proto\"[\n\nUserDetail\x12\x14\n\x05email\x18\x01\x20\
\n\x11user_detail.proto\"[\n\nUserDetail\x12\x14\n\x05email\x18\x01\x20\
\x01(\tR\x05email\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12#\n\
\x06status\x18\x03\x20\x01(\x0e2\x0b.UserStatusR\x06status*1\n\nUserStat\
us\x12\x0b\n\x07Unknown\x10\0\x12\t\n\x05Login\x10\x01\x12\x0b\n\x07Expi\
red\x10\x02J\xe2\x02\n\x06\x12\x04\0\0\x0b\x01\n\x08\n\x01\x0c\x12\x03\0\
\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\
\x02\x08\x12\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\x04\
\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\
\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x13\x14\n\x0b\n\x04\x04\
\0\x02\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\
\0\x02\x01\x03\x12\x03\x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\
\x04\x1a\n\x0c\n\x05\x04\0\x02\x02\x06\x12\x03\x05\x04\x0e\n\x0c\n\x05\
\x04\0\x02\x02\x01\x12\x03\x05\x0f\x15\n\x0c\n\x05\x04\0\x02\x02\x03\x12\
\x03\x05\x18\x19\n\n\n\x02\x05\0\x12\x04\x07\0\x0b\x01\n\n\n\x03\x05\0\
\x01\x12\x03\x07\x05\x0f\n\x0b\n\x04\x05\0\x02\0\x12\x03\x08\x04\x10\n\
\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x08\x04\x0b\n\x0c\n\x05\x05\0\x02\0\
\x02\x12\x03\x08\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\t\x04\x0e\n\
\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\t\x04\t\n\x0c\n\x05\x05\0\x02\x01\
\x02\x12\x03\t\x0c\r\n\x0b\n\x04\x05\0\x02\x02\x12\x03\n\x04\x10\n\x0c\n\
\x05\x05\0\x02\x02\x01\x12\x03\n\x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\
\x12\x03\n\x0e\x0fb\x06proto3\
red\x10\x02J\xe2\x02\n\x06\x12\x04\0\0\n\x01\n\x08\n\x01\x0c\x12\x03\0\0\
\x12\n\n\n\x02\x04\0\x12\x04\x01\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\
\x01\x08\x12\n\x0b\n\x04\x04\0\x02\0\x12\x03\x02\x04\x15\n\x0c\n\x05\x04\
\0\x02\0\x05\x12\x03\x02\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x02\
\x0b\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x02\x13\x14\n\x0b\n\x04\x04\
\0\x02\x01\x12\x03\x03\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x03\
\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x03\x0b\x0f\n\x0c\n\x05\x04\
\0\x02\x01\x03\x12\x03\x03\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x04\
\x04\x1a\n\x0c\n\x05\x04\0\x02\x02\x06\x12\x03\x04\x04\x0e\n\x0c\n\x05\
\x04\0\x02\x02\x01\x12\x03\x04\x0f\x15\n\x0c\n\x05\x04\0\x02\x02\x03\x12\
\x03\x04\x18\x19\n\n\n\x02\x05\0\x12\x04\x06\0\n\x01\n\n\n\x03\x05\0\x01\
\x12\x03\x06\x05\x0f\n\x0b\n\x04\x05\0\x02\0\x12\x03\x07\x04\x10\n\x0c\n\
\x05\x05\0\x02\0\x01\x12\x03\x07\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\
\x03\x07\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x08\x04\x0e\n\x0c\n\
\x05\x05\0\x02\x01\x01\x12\x03\x08\x04\t\n\x0c\n\x05\x05\0\x02\x01\x02\
\x12\x03\x08\x0c\r\n\x0b\n\x04\x05\0\x02\x02\x12\x03\t\x04\x10\n\x0c\n\
\x05\x05\0\x02\x02\x01\x12\x03\t\x04\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\
\x12\x03\t\x0e\x0fb\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -1,5 +1,4 @@
syntax = "proto3";
message UserDetail {
string email = 1;
string name = 2;

View File

@ -11,10 +11,10 @@ pub struct User {
pub(crate) name: String,
#[pb(index = 3)]
pub(crate) email: String,
password: String,
#[pb(index = 4)]
password: String,
pub(crate) email: String,
}
impl User {