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:flowy_sdk/protobuf/flowy-workspace/view_create.pb.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/fading_index_stack.dart';
|
||||
import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
abstract class HomeStackView extends Equatable {
|
||||
final ViewType type;
|
||||
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.
|
||||
class HomePageStack {
|
||||
final PageStackBloc _bloc = PageStackBloc();
|
||||
final PageStackNotifier _notifier = PageStackNotifier();
|
||||
HomePageStack();
|
||||
|
||||
String title() {
|
||||
return _bloc.state.stackView.title;
|
||||
return _notifier.view.title;
|
||||
}
|
||||
|
||||
void setStackView(HomeStackView? stackView) {
|
||||
_bloc.add(PageStackEvent.setStackView(
|
||||
stackView ?? const AnnouncementStackView()));
|
||||
_notifier.view = stackView ?? const AnnouncementStackView();
|
||||
}
|
||||
|
||||
Widget stackTopBar() {
|
||||
return BlocProvider<PageStackBloc>(
|
||||
create: (context) => _bloc,
|
||||
child: BlocBuilder<PageStackBloc, PageStackState>(
|
||||
builder: (context, state) {
|
||||
return HomeTopBar(
|
||||
view: state.stackView,
|
||||
);
|
||||
},
|
||||
),
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => _notifier),
|
||||
],
|
||||
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
|
||||
return HomeTopBar(view: notifier.view);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stackWidget() {
|
||||
return BlocProvider<PageStackBloc>(
|
||||
create: (context) => _bloc,
|
||||
child: BlocBuilder<PageStackBloc, PageStackState>(
|
||||
builder: (context, state) {
|
||||
return FadingIndexedStack(
|
||||
index: pages.indexOf(state.stackView.type),
|
||||
children: _buildStackWidget(state.stackView),
|
||||
);
|
||||
},
|
||||
),
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => _notifier),
|
||||
],
|
||||
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
|
||||
return FadingIndexedStack(
|
||||
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(
|
||||
type: view.viewType,
|
||||
title: view.name,
|
||||
identifier: view.id,
|
||||
);
|
||||
|
||||
@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';
|
||||
|
||||
class AnnouncementStackView extends HomeStackView {
|
||||
const AnnouncementStackView() : super(type: ViewType.Blank, title: 'Blank');
|
||||
const AnnouncementStackView() : super(type: ViewType.Blank, title: 'Blank', identifier: "Announcement");
|
||||
|
||||
@override
|
||||
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/page_stack/page_stack.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/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:flutter/material.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/text.dart';
|
||||
|
||||
@ -21,13 +23,15 @@ class HomeTopBar extends StatelessWidget {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
HomeTitle(title: view.title, type: view.type),
|
||||
_renderNavigationList(view),
|
||||
const Spacer(),
|
||||
_renderShareButton(),
|
||||
_renderMoreButton(),
|
||||
],
|
||||
)
|
||||
.padding(horizontal: HomeInsets.topBarTitlePadding)
|
||||
.padding(
|
||||
horizontal: HomeInsets.topBarTitlePadding,
|
||||
)
|
||||
.bottomBorder(color: Colors.grey.shade300),
|
||||
);
|
||||
}
|
||||
@ -55,8 +59,8 @@ class HomeTopBar extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderNavigationList() {
|
||||
return Container();
|
||||
Widget _renderNavigationList(HomeStackView view) {
|
||||
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