mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
config navigation widget
This commit is contained in:
parent
199fbd8873
commit
23ac4d0249
@ -1,57 +1,72 @@
|
|||||||
import 'package:app_flowy/workspace/domain/page_stack/page_stack_bloc.dart';
|
|
||||||
import 'package:app_flowy/workspace/presentation/doc/doc_page.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/doc/doc_page.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/blank_page.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/blank_page.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/fading_index_stack.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/fading_index_stack.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
abstract class HomeStackView extends Equatable {
|
abstract class HomeStackView extends Equatable {
|
||||||
final ViewType type;
|
final ViewType type;
|
||||||
final String title;
|
final String title;
|
||||||
const HomeStackView({required this.type, required this.title});
|
final String identifier;
|
||||||
|
const HomeStackView(
|
||||||
|
{required this.type, required this.title, required this.identifier});
|
||||||
|
}
|
||||||
|
|
||||||
|
class PageStackNotifier extends ChangeNotifier {
|
||||||
|
HomeStackView? innerView;
|
||||||
|
|
||||||
|
PageStackNotifier({
|
||||||
|
this.innerView,
|
||||||
|
});
|
||||||
|
|
||||||
|
set view(HomeStackView view) {
|
||||||
|
innerView = view;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeStackView get view {
|
||||||
|
return innerView ?? const AnnouncementStackView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomePageStack is initialized as singleton to controll the page stack.
|
// HomePageStack is initialized as singleton to controll the page stack.
|
||||||
class HomePageStack {
|
class HomePageStack {
|
||||||
final PageStackBloc _bloc = PageStackBloc();
|
final PageStackNotifier _notifier = PageStackNotifier();
|
||||||
HomePageStack();
|
HomePageStack();
|
||||||
|
|
||||||
String title() {
|
String title() {
|
||||||
return _bloc.state.stackView.title;
|
return _notifier.view.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStackView(HomeStackView? stackView) {
|
void setStackView(HomeStackView? stackView) {
|
||||||
_bloc.add(PageStackEvent.setStackView(
|
_notifier.view = stackView ?? const AnnouncementStackView();
|
||||||
stackView ?? const AnnouncementStackView()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget stackTopBar() {
|
Widget stackTopBar() {
|
||||||
return BlocProvider<PageStackBloc>(
|
return MultiProvider(
|
||||||
create: (context) => _bloc,
|
providers: [
|
||||||
child: BlocBuilder<PageStackBloc, PageStackState>(
|
ChangeNotifierProvider(create: (_) => _notifier),
|
||||||
builder: (context, state) {
|
],
|
||||||
return HomeTopBar(
|
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
|
||||||
view: state.stackView,
|
return HomeTopBar(view: notifier.view);
|
||||||
);
|
}),
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget stackWidget() {
|
Widget stackWidget() {
|
||||||
return BlocProvider<PageStackBloc>(
|
return MultiProvider(
|
||||||
create: (context) => _bloc,
|
providers: [
|
||||||
child: BlocBuilder<PageStackBloc, PageStackState>(
|
ChangeNotifierProvider(create: (_) => _notifier),
|
||||||
builder: (context, state) {
|
],
|
||||||
return FadingIndexedStack(
|
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
|
||||||
index: pages.indexOf(state.stackView.type),
|
return FadingIndexedStack(
|
||||||
children: _buildStackWidget(state.stackView),
|
index: pages.indexOf(notifier.view.type),
|
||||||
);
|
children: _buildStackWidget(notifier.view),
|
||||||
},
|
);
|
||||||
),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
|
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/blank_page.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
part 'page_stack_bloc.freezed.dart';
|
|
||||||
|
|
||||||
class PageStackBloc extends Bloc<PageStackEvent, PageStackState> {
|
|
||||||
PageStackBloc() : super(PageStackState.initial());
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<PageStackState> mapEventToState(
|
|
||||||
PageStackEvent event,
|
|
||||||
) async* {
|
|
||||||
yield* event.map(setStackView: (NewPageContext value) async* {
|
|
||||||
yield state.copyWith(stackView: value.newStackView);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class PageStackEvent with _$PageStackEvent {
|
|
||||||
const factory PageStackEvent.setStackView(HomeStackView newStackView) =
|
|
||||||
NewPageContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
abstract class PageStackState implements _$PageStackState {
|
|
||||||
const factory PageStackState({
|
|
||||||
required HomeStackView stackView,
|
|
||||||
}) = _PageStackState;
|
|
||||||
|
|
||||||
factory PageStackState.initial() => const PageStackState(
|
|
||||||
stackView: AnnouncementStackView(),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,337 +0,0 @@
|
|||||||
// 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, invalid_annotation_target
|
|
||||||
|
|
||||||
part of 'page_stack_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 _$PageStackEventTearOff {
|
|
||||||
const _$PageStackEventTearOff();
|
|
||||||
|
|
||||||
NewPageContext setStackView(HomeStackView newStackView) {
|
|
||||||
return NewPageContext(
|
|
||||||
newStackView,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
const $PageStackEvent = _$PageStackEventTearOff();
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$PageStackEvent {
|
|
||||||
HomeStackView get newStackView => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult when<TResult extends Object?>({
|
|
||||||
required TResult Function(HomeStackView newStackView) setStackView,
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeWhen<TResult extends Object?>({
|
|
||||||
TResult Function(HomeStackView newStackView)? setStackView,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult map<TResult extends Object?>({
|
|
||||||
required TResult Function(NewPageContext value) setStackView,
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeMap<TResult extends Object?>({
|
|
||||||
TResult Function(NewPageContext value)? setStackView,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
$PageStackEventCopyWith<PageStackEvent> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $PageStackEventCopyWith<$Res> {
|
|
||||||
factory $PageStackEventCopyWith(
|
|
||||||
PageStackEvent value, $Res Function(PageStackEvent) then) =
|
|
||||||
_$PageStackEventCopyWithImpl<$Res>;
|
|
||||||
$Res call({HomeStackView newStackView});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$PageStackEventCopyWithImpl<$Res>
|
|
||||||
implements $PageStackEventCopyWith<$Res> {
|
|
||||||
_$PageStackEventCopyWithImpl(this._value, this._then);
|
|
||||||
|
|
||||||
final PageStackEvent _value;
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Res Function(PageStackEvent) _then;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? newStackView = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_value.copyWith(
|
|
||||||
newStackView: newStackView == freezed
|
|
||||||
? _value.newStackView
|
|
||||||
: newStackView // ignore: cast_nullable_to_non_nullable
|
|
||||||
as HomeStackView,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $NewPageContextCopyWith<$Res>
|
|
||||||
implements $PageStackEventCopyWith<$Res> {
|
|
||||||
factory $NewPageContextCopyWith(
|
|
||||||
NewPageContext value, $Res Function(NewPageContext) then) =
|
|
||||||
_$NewPageContextCopyWithImpl<$Res>;
|
|
||||||
@override
|
|
||||||
$Res call({HomeStackView newStackView});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$NewPageContextCopyWithImpl<$Res>
|
|
||||||
extends _$PageStackEventCopyWithImpl<$Res>
|
|
||||||
implements $NewPageContextCopyWith<$Res> {
|
|
||||||
_$NewPageContextCopyWithImpl(
|
|
||||||
NewPageContext _value, $Res Function(NewPageContext) _then)
|
|
||||||
: super(_value, (v) => _then(v as NewPageContext));
|
|
||||||
|
|
||||||
@override
|
|
||||||
NewPageContext get _value => super._value as NewPageContext;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? newStackView = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(NewPageContext(
|
|
||||||
newStackView == freezed
|
|
||||||
? _value.newStackView
|
|
||||||
: newStackView // ignore: cast_nullable_to_non_nullable
|
|
||||||
as HomeStackView,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
class _$NewPageContext implements NewPageContext {
|
|
||||||
const _$NewPageContext(this.newStackView);
|
|
||||||
|
|
||||||
@override
|
|
||||||
final HomeStackView newStackView;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'PageStackEvent.setStackView(newStackView: $newStackView)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(dynamic other) {
|
|
||||||
return identical(this, other) ||
|
|
||||||
(other is NewPageContext &&
|
|
||||||
(identical(other.newStackView, newStackView) ||
|
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.newStackView, newStackView)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode =>
|
|
||||||
runtimeType.hashCode ^ const DeepCollectionEquality().hash(newStackView);
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
@override
|
|
||||||
$NewPageContextCopyWith<NewPageContext> get copyWith =>
|
|
||||||
_$NewPageContextCopyWithImpl<NewPageContext>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult when<TResult extends Object?>({
|
|
||||||
required TResult Function(HomeStackView newStackView) setStackView,
|
|
||||||
}) {
|
|
||||||
return setStackView(newStackView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeWhen<TResult extends Object?>({
|
|
||||||
TResult Function(HomeStackView newStackView)? setStackView,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (setStackView != null) {
|
|
||||||
return setStackView(newStackView);
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult map<TResult extends Object?>({
|
|
||||||
required TResult Function(NewPageContext value) setStackView,
|
|
||||||
}) {
|
|
||||||
return setStackView(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeMap<TResult extends Object?>({
|
|
||||||
TResult Function(NewPageContext value)? setStackView,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (setStackView != null) {
|
|
||||||
return setStackView(this);
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class NewPageContext implements PageStackEvent {
|
|
||||||
const factory NewPageContext(HomeStackView newStackView) = _$NewPageContext;
|
|
||||||
|
|
||||||
@override
|
|
||||||
HomeStackView get newStackView => throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
$NewPageContextCopyWith<NewPageContext> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$PageStackStateTearOff {
|
|
||||||
const _$PageStackStateTearOff();
|
|
||||||
|
|
||||||
_PageStackState call({required HomeStackView stackView}) {
|
|
||||||
return _PageStackState(
|
|
||||||
stackView: stackView,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
const $PageStackState = _$PageStackStateTearOff();
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$PageStackState {
|
|
||||||
HomeStackView get stackView => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
$PageStackStateCopyWith<PageStackState> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $PageStackStateCopyWith<$Res> {
|
|
||||||
factory $PageStackStateCopyWith(
|
|
||||||
PageStackState value, $Res Function(PageStackState) then) =
|
|
||||||
_$PageStackStateCopyWithImpl<$Res>;
|
|
||||||
$Res call({HomeStackView stackView});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$PageStackStateCopyWithImpl<$Res>
|
|
||||||
implements $PageStackStateCopyWith<$Res> {
|
|
||||||
_$PageStackStateCopyWithImpl(this._value, this._then);
|
|
||||||
|
|
||||||
final PageStackState _value;
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Res Function(PageStackState) _then;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? stackView = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_value.copyWith(
|
|
||||||
stackView: stackView == freezed
|
|
||||||
? _value.stackView
|
|
||||||
: stackView // ignore: cast_nullable_to_non_nullable
|
|
||||||
as HomeStackView,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class _$PageStackStateCopyWith<$Res>
|
|
||||||
implements $PageStackStateCopyWith<$Res> {
|
|
||||||
factory _$PageStackStateCopyWith(
|
|
||||||
_PageStackState value, $Res Function(_PageStackState) then) =
|
|
||||||
__$PageStackStateCopyWithImpl<$Res>;
|
|
||||||
@override
|
|
||||||
$Res call({HomeStackView stackView});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class __$PageStackStateCopyWithImpl<$Res>
|
|
||||||
extends _$PageStackStateCopyWithImpl<$Res>
|
|
||||||
implements _$PageStackStateCopyWith<$Res> {
|
|
||||||
__$PageStackStateCopyWithImpl(
|
|
||||||
_PageStackState _value, $Res Function(_PageStackState) _then)
|
|
||||||
: super(_value, (v) => _then(v as _PageStackState));
|
|
||||||
|
|
||||||
@override
|
|
||||||
_PageStackState get _value => super._value as _PageStackState;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? stackView = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_PageStackState(
|
|
||||||
stackView: stackView == freezed
|
|
||||||
? _value.stackView
|
|
||||||
: stackView // ignore: cast_nullable_to_non_nullable
|
|
||||||
as HomeStackView,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
class _$_PageStackState implements _PageStackState {
|
|
||||||
const _$_PageStackState({required this.stackView});
|
|
||||||
|
|
||||||
@override
|
|
||||||
final HomeStackView stackView;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'PageStackState(stackView: $stackView)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(dynamic other) {
|
|
||||||
return identical(this, other) ||
|
|
||||||
(other is _PageStackState &&
|
|
||||||
(identical(other.stackView, stackView) ||
|
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.stackView, stackView)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode =>
|
|
||||||
runtimeType.hashCode ^ const DeepCollectionEquality().hash(stackView);
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
@override
|
|
||||||
_$PageStackStateCopyWith<_PageStackState> get copyWith =>
|
|
||||||
__$PageStackStateCopyWithImpl<_PageStackState>(this, _$identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class _PageStackState implements PageStackState {
|
|
||||||
const factory _PageStackState({required HomeStackView stackView}) =
|
|
||||||
_$_PageStackState;
|
|
||||||
|
|
||||||
@override
|
|
||||||
HomeStackView get stackView => throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
_$PageStackStateCopyWith<_PageStackState> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
@ -60,6 +60,7 @@ class DocPageStackView extends HomeStackView {
|
|||||||
: super(
|
: super(
|
||||||
type: view.viewType,
|
type: view.viewType,
|
||||||
title: view.name,
|
title: view.name,
|
||||||
|
identifier: view.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
137
app_flowy/lib/workspace/presentation/home/navigation_list.dart
Normal file
137
app_flowy/lib/workspace/presentation/home/navigation_list.dart
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/widgets/home_top_bar.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/text_button.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
typedef NaviAction = void Function();
|
||||||
|
|
||||||
|
abstract class NaviItem {
|
||||||
|
String get identifier;
|
||||||
|
String get title;
|
||||||
|
NaviAction get action;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NavigationNotifier extends ChangeNotifier {
|
||||||
|
PageStackNotifier pageStackNotifier;
|
||||||
|
NavigationNotifier(this.pageStackNotifier);
|
||||||
|
|
||||||
|
void update(PageStackNotifier notifier) {
|
||||||
|
pageStackNotifier = notifier;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NaviItem> get naviItems {
|
||||||
|
List<NaviItem> items = [
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view),
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view),
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view),
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view),
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view),
|
||||||
|
ViewNaviItemImpl(pageStackNotifier.view)
|
||||||
|
];
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StyledNavigationList extends StatelessWidget {
|
||||||
|
const StyledNavigationList({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ChangeNotifierProxyProvider<PageStackNotifier, NavigationNotifier>(
|
||||||
|
create: (_) => NavigationNotifier(
|
||||||
|
Provider.of<PageStackNotifier>(
|
||||||
|
context,
|
||||||
|
listen: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
update: (_, notifier, controller) => controller!..update(notifier),
|
||||||
|
child: Consumer(builder: (ctx, NavigationNotifier notifier, child) {
|
||||||
|
return Row(children: _renderChildren(notifier.naviItems));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _renderChildren(List<NaviItem> items) {
|
||||||
|
if (items.isEmpty) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NaviItem> newItems = _filter(items);
|
||||||
|
Widget last = NaviItemWidget(newItems.removeLast());
|
||||||
|
|
||||||
|
List<Widget> widgets = List.empty(growable: true);
|
||||||
|
widgets.addAll(newItems
|
||||||
|
.map((item) => NaviItemDivider(child: NaviItemWidget(item)))
|
||||||
|
.toList());
|
||||||
|
widgets.add(last);
|
||||||
|
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NaviItem> _filter(List<NaviItem> items) {
|
||||||
|
final length = items.length;
|
||||||
|
if (length > 4) {
|
||||||
|
final first = items[0];
|
||||||
|
final ellipsisItems = items.getRange(1, length - 2).toList();
|
||||||
|
final last = items.getRange(length - 2, length).toList();
|
||||||
|
return [
|
||||||
|
first,
|
||||||
|
EllipsisNaviItem(items: ellipsisItems),
|
||||||
|
...last,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NaviItemWidget extends StatelessWidget {
|
||||||
|
final NaviItem item;
|
||||||
|
const NaviItemWidget(this.item, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 30,
|
||||||
|
child: FlowyTextButton(
|
||||||
|
item.title,
|
||||||
|
fontSize: 14,
|
||||||
|
onPressed: () {
|
||||||
|
debugPrint('show app document');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NaviItemDivider extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
const NaviItemDivider({Key? key, required this.child}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [child, const Text('/').padding(horizontal: 2)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EllipsisNaviItem extends NaviItem {
|
||||||
|
final List<NaviItem> items;
|
||||||
|
EllipsisNaviItem({
|
||||||
|
required this.items,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
NaviAction get action => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get identifier => "Ellipsis";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => "...";
|
||||||
|
}
|
@ -3,7 +3,7 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AnnouncementStackView extends HomeStackView {
|
class AnnouncementStackView extends HomeStackView {
|
||||||
const AnnouncementStackView() : super(type: ViewType.Blank, title: 'Blank');
|
const AnnouncementStackView() : super(type: ViewType.Blank, title: 'Blank', identifier: "Announcement");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
import 'package:app_flowy/workspace/domain/image.dart';
|
import 'package:app_flowy/workspace/domain/image.dart';
|
||||||
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
|
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/home/navigation_list.dart';
|
||||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
|
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||||
// import 'package:flowy_infra_ui/style_widget/styled_navigation_list.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
|
|
||||||
@ -21,13 +23,15 @@ class HomeTopBar extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
HomeTitle(title: view.title, type: view.type),
|
_renderNavigationList(view),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
_renderShareButton(),
|
_renderShareButton(),
|
||||||
_renderMoreButton(),
|
_renderMoreButton(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.padding(horizontal: HomeInsets.topBarTitlePadding)
|
.padding(
|
||||||
|
horizontal: HomeInsets.topBarTitlePadding,
|
||||||
|
)
|
||||||
.bottomBorder(color: Colors.grey.shade300),
|
.bottomBorder(color: Colors.grey.shade300),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -55,8 +59,8 @@ class HomeTopBar extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _renderNavigationList() {
|
Widget _renderNavigationList(HomeStackView view) {
|
||||||
return Container();
|
return const StyledNavigationList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,3 +91,18 @@ class HomeTitle extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ViewNaviItemImpl extends NaviItem {
|
||||||
|
final HomeStackView view;
|
||||||
|
|
||||||
|
ViewNaviItemImpl(this.view);
|
||||||
|
|
||||||
|
@override
|
||||||
|
NaviAction get action => () => getIt<HomePageStack>().setStackView(view);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get identifier => view.identifier;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => view.title;
|
||||||
|
}
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
typedef NaviAction = void Function(String);
|
|
||||||
|
|
||||||
abstract class NaviItem {
|
|
||||||
String get identifier;
|
|
||||||
NaviAction get action;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StyledNavigationController extends ChangeNotifier {
|
|
||||||
List<NaviItem> naviItems;
|
|
||||||
StyledNavigationController({this.naviItems = const []});
|
|
||||||
}
|
|
||||||
|
|
||||||
class StyledNavigationList extends StatelessWidget {
|
|
||||||
const StyledNavigationList({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MultiProvider(
|
|
||||||
providers: [
|
|
||||||
ChangeNotifierProvider(create: (_) => StyledNavigationController()),
|
|
||||||
],
|
|
||||||
child: Consumer(builder: (ctx, StyledNavigationController ctrl, child) {
|
|
||||||
return Row(
|
|
||||||
children: _buildNaviItemWidget(ctrl.naviItems),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _buildNaviItemWidget(List<NaviItem> items) {
|
|
||||||
if (items.isEmpty) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
List<NaviItem> newItems = _filter(items);
|
|
||||||
Widget last = NaviItemWidget(newItems.removeLast());
|
|
||||||
|
|
||||||
List<Widget> widgets = newItems
|
|
||||||
.map((item) => NaviItemDivider(child: NaviItemWidget(item)))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
widgets.add(last);
|
|
||||||
|
|
||||||
return widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<NaviItem> _filter(List<NaviItem> items) {
|
|
||||||
final length = items.length;
|
|
||||||
if (length > 4) {
|
|
||||||
final first = items[0];
|
|
||||||
final ellipsisItems = items.getRange(1, length - 2).toList();
|
|
||||||
final last = items.getRange(length - 2, length).toList();
|
|
||||||
return [
|
|
||||||
first,
|
|
||||||
EllipsisNaviItem(items: ellipsisItems),
|
|
||||||
...last,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NaviItemWidget extends StatelessWidget {
|
|
||||||
final NaviItem item;
|
|
||||||
const NaviItemWidget(this.item, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
child: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NaviItemDivider extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
const NaviItemDivider({Key? key, required this.child}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
children: [child, const Text('/')],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EllipsisNaviItem extends NaviItem {
|
|
||||||
final List<NaviItem> items;
|
|
||||||
EllipsisNaviItem({
|
|
||||||
required this.items,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
// TODO: implement action
|
|
||||||
NaviAction get action => throw UnimplementedError();
|
|
||||||
|
|
||||||
@override
|
|
||||||
// TODO: implement identifier
|
|
||||||
String get identifier => throw UnimplementedError();
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user