mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-22 03:31:09 +08:00
@@ -1,14 +1,12 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/tabs.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
||||
import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/pages/home/view.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||
@@ -23,7 +21,6 @@ import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
@@ -34,7 +31,7 @@ class MainApp extends StatefulWidget {
|
||||
State<MainApp> createState() => _MainAppState();
|
||||
}
|
||||
|
||||
class _MainAppState extends State<MainApp>
|
||||
class _MainAppState extends PopScopeState<MainApp>
|
||||
with RouteAware, WidgetsBindingObserver, WindowListener, TrayListener {
|
||||
final _mainController = Get.put(MainController());
|
||||
late final _setting = GStorage.setting;
|
||||
@@ -234,7 +231,7 @@ class _MainAppState extends State<MainApp>
|
||||
await trayManager.setContextMenu(trayMenu);
|
||||
}
|
||||
|
||||
void onBack() {
|
||||
static void _onBack() {
|
||||
if (Platform.isAndroid) {
|
||||
Utils.channel.invokeMethod('back');
|
||||
} else {
|
||||
@@ -244,13 +241,8 @@ class _MainAppState extends State<MainApp>
|
||||
|
||||
late bool useBottomNav;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
useBottomNav =
|
||||
!_mainController.useSideBar && MediaQuery.sizeOf(context).isPortrait;
|
||||
Widget? bottomNav = useBottomNav
|
||||
Widget? get _bottomNav {
|
||||
return useBottomNav
|
||||
? _mainController.navigationBars.length > 1
|
||||
? _mainController.enableMYBar
|
||||
? Obx(
|
||||
@@ -279,7 +271,7 @@ class _MainAppState extends State<MainApp>
|
||||
iconSize: 16,
|
||||
selectedFontSize: 12,
|
||||
unselectedFontSize: 12,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
type: .fixed,
|
||||
items: _mainController.navigationBars
|
||||
.map(
|
||||
(e) => BottomNavigationBarItem(
|
||||
@@ -296,151 +288,151 @@ class _MainAppState extends State<MainApp>
|
||||
)
|
||||
: null
|
||||
: null;
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (bool didPop, Object? result) {
|
||||
if (_mainController.directExitOnBack) {
|
||||
onBack();
|
||||
} else {
|
||||
if (_mainController.selectedIndex.value != 0) {
|
||||
_mainController
|
||||
..setIndex(0)
|
||||
..bottomBar?.value = true
|
||||
..setSearchBar();
|
||||
} else {
|
||||
onBack();
|
||||
}
|
||||
}
|
||||
},
|
||||
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarIconBrightness: theme.brightness.reverse,
|
||||
),
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(toolbarHeight: 0),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: useBottomNav ? padding.left : 0.0,
|
||||
right: padding.right,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (!useBottomNav) ...[
|
||||
_mainController.navigationBars.length > 1
|
||||
? context.isTablet && _mainController.optTabletNav
|
||||
? Column(
|
||||
children: [
|
||||
const SizedBox(height: 25),
|
||||
userAndSearchVertical(theme),
|
||||
const Spacer(flex: 2),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: SizedBox(
|
||||
width: 130,
|
||||
child: Obx(
|
||||
() => NavigationDrawer(
|
||||
backgroundColor: Colors.transparent,
|
||||
tilePadding:
|
||||
const EdgeInsets.symmetric(
|
||||
vertical: 5,
|
||||
horizontal: 12,
|
||||
),
|
||||
indicatorShape:
|
||||
const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16),
|
||||
),
|
||||
),
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
selectedIndex: _mainController
|
||||
.selectedIndex
|
||||
.value,
|
||||
children: _mainController
|
||||
.navigationBars
|
||||
.map(
|
||||
(e) =>
|
||||
NavigationDrawerDestination(
|
||||
label: Text(e.label),
|
||||
icon: _buildIcon(
|
||||
type: e,
|
||||
),
|
||||
selectedIcon: _buildIcon(
|
||||
type: e,
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
}
|
||||
|
||||
@override
|
||||
void onPopInvokedWithResult(bool didPop, Object? result) {
|
||||
if (_mainController.directExitOnBack) {
|
||||
_onBack();
|
||||
} else {
|
||||
if (_mainController.selectedIndex.value != 0) {
|
||||
_mainController
|
||||
..setIndex(0)
|
||||
..bottomBar?.value = true
|
||||
..setSearchBar();
|
||||
} else {
|
||||
_onBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
useBottomNav =
|
||||
!_mainController.useSideBar && MediaQuery.sizeOf(context).isPortrait;
|
||||
final bottomNav = _bottomNav;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarIconBrightness: theme.brightness.reverse,
|
||||
),
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(toolbarHeight: 0),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: useBottomNav ? padding.left : 0.0,
|
||||
right: padding.right,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
if (!useBottomNav) ...[
|
||||
_mainController.navigationBars.length > 1
|
||||
? context.isTablet && _mainController.optTabletNav
|
||||
? Column(
|
||||
children: [
|
||||
const SizedBox(height: 25),
|
||||
userAndSearchVertical(theme),
|
||||
const Spacer(flex: 2),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: SizedBox(
|
||||
width: 130,
|
||||
child: Obx(
|
||||
() => NavigationDrawer(
|
||||
backgroundColor: Colors.transparent,
|
||||
tilePadding: const .symmetric(
|
||||
vertical: 5,
|
||||
horizontal: 12,
|
||||
),
|
||||
indicatorShape:
|
||||
const RoundedRectangleBorder(
|
||||
borderRadius: .all(
|
||||
.circular(16),
|
||||
),
|
||||
),
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
selectedIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
children: _mainController.navigationBars
|
||||
.map(
|
||||
(e) =>
|
||||
NavigationDrawerDestination(
|
||||
label: Text(e.label),
|
||||
icon: _buildIcon(type: e),
|
||||
selectedIcon: _buildIcon(
|
||||
type: e,
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Obx(
|
||||
() => NavigationRail(
|
||||
groupAlignment: 0.5,
|
||||
selectedIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
labelType: NavigationRailLabelType.selected,
|
||||
leading: userAndSearchVertical(theme),
|
||||
destinations: _mainController.navigationBars
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
label: Text(e.label),
|
||||
icon: _buildIcon(type: e),
|
||||
selectedIcon: _buildIcon(
|
||||
type: e,
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
width: 80,
|
||||
child: userAndSearchVertical(theme),
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
endIndent: padding.bottom,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.06),
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: _mainController.mainTabBarView
|
||||
? CustomTabBarView(
|
||||
scrollDirection: useBottomNav
|
||||
? Axis.horizontal
|
||||
: Axis.vertical,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: _mainController.controller,
|
||||
children: _mainController.navigationBars
|
||||
.map((i) => i.page)
|
||||
.toList(),
|
||||
)
|
||||
: PageView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: _mainController.controller,
|
||||
children: _mainController.navigationBars
|
||||
.map((i) => i.page)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Obx(
|
||||
() => NavigationRail(
|
||||
groupAlignment: 0.5,
|
||||
selectedIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
onDestinationSelected: _mainController.setIndex,
|
||||
labelType: .selected,
|
||||
leading: userAndSearchVertical(theme),
|
||||
destinations: _mainController.navigationBars
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
label: Text(e.label),
|
||||
icon: _buildIcon(type: e),
|
||||
selectedIcon: _buildIcon(
|
||||
type: e,
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
width: 80,
|
||||
padding: const .only(top: 10),
|
||||
child: userAndSearchVertical(theme),
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
endIndent: padding.bottom,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.06),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: _mainController.mainTabBarView
|
||||
? CustomTabBarView(
|
||||
scrollDirection: useBottomNav ? .horizontal : .vertical,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: _mainController.controller,
|
||||
children: _mainController.navigationBars
|
||||
.map((i) => i.page)
|
||||
.toList(),
|
||||
)
|
||||
: PageView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
controller: _mainController.controller,
|
||||
children: _mainController.navigationBars
|
||||
.map((i) => i.page)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: _buildBottom(bottomNav),
|
||||
),
|
||||
bottomNavigationBar: _buildBottom(bottomNav),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -461,22 +453,18 @@ class _MainAppState extends State<MainApp>
|
||||
return bottomNav;
|
||||
}
|
||||
|
||||
Widget _buildIcon({
|
||||
required NavigationBarType type,
|
||||
bool selected = false,
|
||||
}) {
|
||||
Widget _buildIcon({required NavigationBarType type, bool selected = false}) {
|
||||
final icon = selected ? type.selectIcon : type.icon;
|
||||
return type == NavigationBarType.dynamics
|
||||
return type == .dynamics
|
||||
? Obx(
|
||||
() {
|
||||
final dynCount = _mainController.dynCount.value;
|
||||
return Badge(
|
||||
isLabelVisible: dynCount > 0,
|
||||
label:
|
||||
_mainController.dynamicBadgeMode == DynamicBadgeMode.number
|
||||
label: _mainController.dynamicBadgeMode == .number
|
||||
? Text(dynCount.toString())
|
||||
: null,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
padding: const .symmetric(horizontal: 6),
|
||||
child: icon,
|
||||
);
|
||||
},
|
||||
@@ -487,69 +475,9 @@ class _MainAppState extends State<MainApp>
|
||||
Widget userAndSearchVertical(ThemeData theme) {
|
||||
return Column(
|
||||
children: [
|
||||
Semantics(
|
||||
label: "我的",
|
||||
child: Obx(
|
||||
() => _mainController.accountService.isLogin.value
|
||||
? Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
type: ImageType.avatar,
|
||||
width: 34,
|
||||
height: 34,
|
||||
src: _mainController.accountService.face.value,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: _mainController.toMinePage,
|
||||
splashColor: theme.colorScheme.primaryContainer
|
||||
.withValues(alpha: 0.3),
|
||||
customBorder: const CircleBorder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: -6,
|
||||
bottom: -6,
|
||||
child: Obx(
|
||||
() => MineController.anonymity.value
|
||||
? IgnorePointer(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
theme.colorScheme.secondaryContainer,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
size: 16,
|
||||
MdiIcons.incognito,
|
||||
color: theme
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: defaultUser(
|
||||
theme: theme,
|
||||
onPressed: _mainController.toMinePage,
|
||||
),
|
||||
),
|
||||
),
|
||||
userAvatar(theme: theme, mainController: _mainController),
|
||||
const SizedBox(height: 8),
|
||||
Obx(
|
||||
() => _mainController.accountService.isLogin.value
|
||||
? msgBadge(_mainController)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
msgBadge(_mainController),
|
||||
IconButton(
|
||||
tooltip: '搜索',
|
||||
icon: const Icon(
|
||||
|
||||
Reference in New Issue
Block a user