Skip to content

Commit

Permalink
feat: 使用 Material Design 3 中的 medium top app bar (#287)
Browse files Browse the repository at this point in the history
  • Loading branch information
he0119 authored Oct 27, 2022
1 parent eae16d3 commit a16de63
Show file tree
Hide file tree
Showing 50 changed files with 2,131 additions and 2,002 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/lang/zh-CN/

## [Unreleased]

### Changed

- 使用 Material Design 3 中的 medium top app bar

### Fixed

- 留言板中单击网址链接现在能正常转跳到对应网页
Expand Down
142 changes: 74 additions & 68 deletions lib/blog/view/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
Expand All @@ -11,7 +10,7 @@ import 'package:smarthome/routers/delegate.dart';
import 'package:smarthome/utils/launch_url.dart';
import 'package:smarthome/widgets/home_page.dart';
import 'package:smarthome/widgets/rounded_raised_button.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:smarthome/widgets/webview.dart';

class BlogHomePage extends Page {
const BlogHomePage()
Expand Down Expand Up @@ -43,82 +42,89 @@ class BlogHomeScreen extends StatefulWidget {
}

class _BlogHomeScreenState extends State<BlogHomeScreen> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
late NestedWebviewController _controller;

@override
Widget build(BuildContext context) {
return Consumer<SettingsController>(
builder: (context, settings, child) => FutureBuilder(
future: _controller.future,
builder: (BuildContext context,
AsyncSnapshot<WebViewController> controller) =>
MyHomePage(
activeTab: AppTab.blog,
actions: [
Tooltip(
message: '进入管理页面',
child: IconButton(
icon: const Icon(Icons.dvr),
builder: (context, settings, child) {
_controller = NestedWebviewController(settings.blogUrl);
return ValueListenableBuilder<WebViewStatus>(
valueListenable: _controller.webViewStatusNotifier,
builder: (
BuildContext context,
WebViewStatus webViewStatus,
Widget? child,
) {
return MyHomePage(
activeTab: AppTab.blog,
actions: [
Tooltip(
message: '进入管理页面',
child: IconButton(
icon: const Icon(Icons.dvr),
onPressed: () async {
final blogAdminUrl = settings.blogAdminUrl;
if (blogAdminUrl != null) {
if (kIsWeb) {
await launchUrl(blogAdminUrl);
} else if (_controller.webviewController != null) {
await _controller.webviewController!
.loadUrl(blogAdminUrl);
}
} else {
MyRouterDelegate.of(context)
.push(const BlogSettingsPage());
}
},
),
),
Tooltip(
message: '设置',
child: IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
MyRouterDelegate.of(context)
.push(const BlogSettingsPage());
},
),
),
],
slivers: [
(!kIsWeb && !Platform.isWindows)
? MyWebview(
controller: _controller,
)
: SliverCenterRoundedRaisedButton(
onPressed: () => launchUrl(settings.blogUrl),
child: const Text('博客'),
)
],
floatingActionButton: FloatingActionButton(
tooltip: '使用浏览器打开',
onPressed: () async {
final blogAdminUrl = settings.blogAdminUrl;
if (blogAdminUrl != null) {
if (kIsWeb) {
await launchUrl(blogAdminUrl);
} else if (controller.hasData) {
await controller.data!.loadUrl(blogAdminUrl);
if (_controller.webviewController?.currentUrl() != null) {
final currentUrl =
await _controller.webviewController?.currentUrl();
if (currentUrl != null) {
await launchUrl(currentUrl);
}
} else {
MyRouterDelegate.of(context).push(const BlogSettingsPage());
}
},
child: const Icon(Icons.open_in_new),
),
),
Tooltip(
message: '设置',
child: IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
MyRouterDelegate.of(context).push(const BlogSettingsPage());
},
),
),
],
body: (!kIsWeb && !Platform.isWindows)
? WillPopScope(
onWillPop: () async {
if (controller.hasData &&
await controller.data!.canGoBack()) {
await controller.data!.goBack();
return false;
}
return true;
},
child: WebView(
initialUrl: settings.blogUrl,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: _controller.complete,
))
: Center(
child: RoundedRaisedButton(
onPressed: () => launchUrl(settings.blogUrl),
child: const Text('博客'),
),
),
floatingActionButton: FloatingActionButton(
tooltip: '使用浏览器打开',
onPressed: () async {
if (controller.hasData) {
final currentUrl = await controller.data!.currentUrl();
if (currentUrl != null) {
await launchUrl(currentUrl);
onWillPop: () async {
if (_controller.webviewController != null &&
await _controller.webviewController!.canGoBack()) {
await _controller.webviewController!.goBack();
return false;
}
}
},
child: const Icon(Icons.open_in_new),
),
),
),
return true;
},
);
},
);
},
);
}
}
Expand Down
9 changes: 4 additions & 5 deletions lib/blog/view/settings/settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
import 'package:smarthome/app/settings/settings_controller.dart';
import 'package:smarthome/blog/view/settings/blog_admin_url_page.dart';
import 'package:smarthome/blog/view/settings/blog_url_page.dart';
import 'package:smarthome/widgets/home_page.dart';
import 'package:smarthome/widgets/settings/settings.dart';

class BlogSettingsPage extends Page {
Expand All @@ -26,11 +27,9 @@ class BlogSettingsScreen extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('博客'),
),
body: Consumer<SettingsController>(
return MySliverScaffold(
title: const Text('博客'),
sliver: Consumer<SettingsController>(
builder: (context, settings, child) => SettingsList(
sections: [
SettingsSection(
Expand Down
30 changes: 18 additions & 12 deletions lib/board/bloc/board_home/board_home_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,63 @@ import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:smarthome/board/model/board.dart';
import 'package:smarthome/board/model/models.dart';
import 'package:smarthome/board/repository/board_repository.dart';
import 'package:smarthome/core/core.dart';
import 'package:smarthome/utils/exceptions.dart';

part 'board_home_event.dart';
part 'board_home_state.dart';

enum BoardHomeStatus { initial, loading, success, failure }

class BoardHomeBloc extends Bloc<BoardHomeEvent, BoardHomeState> {
final BoardRepository boardRepository;

BoardHomeBloc({
required this.boardRepository,
}) : super(BoardHomeInProgress()) {
}) : super(const BoardHomeState()) {
on<BoardHomeFetched>(_onBoardHomeFetched);
}

FutureOr<void> _onBoardHomeFetched(
BoardHomeFetched event, Emitter<BoardHomeState> emit) async {
final currentState = state;
try {
// 如果需要刷新,则显示加载界面
// 因为需要请求网络最好提示用户
if (!event.cache) {
emit(BoardHomeInProgress());
emit(state.copyWith(status: BoardHomeStatus.loading));
}
if (event.cache &&
currentState is BoardHomeSuccess &&
!currentState.hasReachedMax) {
state.status == BoardHomeStatus.success &&
!state.hasReachedMax) {
// 如果不需要刷新,不是首次启动,或遇到错误,并且有下一页
// 则获取下一页
final results = await boardRepository.topics(
after: currentState.pageInfo.endCursor,
after: state.pageInfo.endCursor,
cache: false,
);
emit(BoardHomeSuccess(
topics: currentState.topics + results.item1,
pageInfo: currentState.pageInfo.copyWith(results.item2),
emit(state.copyWith(
status: BoardHomeStatus.success,
topics: state.topics + results.item1,
pageInfo: state.pageInfo.copyWith(results.item2),
));
} else {
// 其他情况根据设置看是否需要打开缓存,并获取第一页
final results = await boardRepository.topics(
cache: event.cache,
);
emit(BoardHomeSuccess(
emit(state.copyWith(
status: BoardHomeStatus.success,
topics: results.item1,
pageInfo: results.item2,
));
}
} on MyException catch (e) {
emit(BoardHomeFailure(e.message));
emit(state.copyWith(
status: BoardHomeStatus.failure,
error: e.message,
));
}
}
}
57 changes: 28 additions & 29 deletions lib/board/bloc/board_home/board_home_state.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
part of 'board_home_bloc.dart';

abstract class BoardHomeState extends Equatable {
const BoardHomeState();
class BoardHomeState extends Equatable {
/// 当前状态
final BoardHomeStatus status;

@override
List<Object> get props => [];
}

class BoardHomeInProgress extends BoardHomeState {
@override
String toString() => 'BoardHomeInProgress';
}

class BoardHomeFailure extends BoardHomeState {
final String message;

const BoardHomeFailure(this.message);

@override
List<Object> get props => [message];

@override
String toString() => 'BoardHomeFailure(message: $message)';
}
/// 错误信息
final String error;

class BoardHomeSuccess extends BoardHomeState {
/// 位置页面所需数据
final List<Topic> topics;
final PageInfo pageInfo;

const BoardHomeSuccess({
required this.topics,
required this.pageInfo,
const BoardHomeState({
this.status = BoardHomeStatus.initial,
this.error = '',
// 初始为空值
this.topics = const [],
this.pageInfo = const PageInfo(hasNextPage: false),
});

bool get hasReachedMax => !pageInfo.hasNextPage;

@override
List<Object> get props => [topics, pageInfo];
List<Object?> get props => [status, error, topics, pageInfo];

@override
String toString() =>
'BoardHomeSuccess(topics: ${topics.length}, pageInfo: $pageInfo)';
bool get stringify => true;

BoardHomeState copyWith({
BoardHomeStatus? status,
String? error,
List<Topic>? topics,
PageInfo? pageInfo,
}) {
return BoardHomeState(
status: status ?? this.status,
error: error ?? this.error,
topics: topics ?? this.topics,
pageInfo: pageInfo ?? this.pageInfo,
);
}
}
Loading

0 comments on commit a16de63

Please sign in to comment.