🐛 Fix bugs again
This commit is contained in:
@@ -309,25 +309,6 @@ class FeaturedPostCard extends HookConsumerWidget {
|
||||
children: [
|
||||
const Icon(Symbols.highlight),
|
||||
Text('highlightPost').tr(),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
visualDensity: VisualDensity.compact,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
// Navigation to previous post
|
||||
},
|
||||
icon: const Icon(Symbols.arrow_left),
|
||||
),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
visualDensity: VisualDensity.compact,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
// Navigation to next post
|
||||
},
|
||||
icon: const Icon(Symbols.arrow_right),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, vertical: 8),
|
||||
),
|
||||
|
||||
@@ -28,3 +28,13 @@ class OidcAuthCallbackEvent {
|
||||
class CommandPaletteTriggerEvent {
|
||||
const CommandPaletteTriggerEvent();
|
||||
}
|
||||
|
||||
/// Event fired to show the compose post sheet
|
||||
class ShowComposeSheetEvent {
|
||||
const ShowComposeSheetEvent();
|
||||
}
|
||||
|
||||
/// Event fired to show the notification sheet
|
||||
class ShowNotificationSheetEvent {
|
||||
const ShowNotificationSheetEvent();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ import 'package:island/services/sharing_intent.dart';
|
||||
import 'package:island/services/update_service.dart';
|
||||
import 'package:island/widgets/content/network_status_sheet.dart';
|
||||
import 'package:island/widgets/tour/tour.dart';
|
||||
import 'package:island/widgets/post/compose_sheet.dart';
|
||||
import 'package:island/screens/notification.dart';
|
||||
import 'package:island/services/event_bus.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
@@ -33,6 +36,9 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
StreamSubscription? ntySubs;
|
||||
bool networkStateShowing = false;
|
||||
|
||||
StreamSubscription? composeSheetSubs;
|
||||
StreamSubscription? notificationSheetSubs;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -49,6 +55,21 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
ref.read(rpcServerStateProvider.notifier).start();
|
||||
ref.read(webAuthServerStateProvider.notifier).start();
|
||||
|
||||
// Listen to special action events
|
||||
composeSheetSubs = eventBus.on<ShowComposeSheetEvent>().listen((event) {
|
||||
if (mounted) {
|
||||
_showComposeSheet();
|
||||
}
|
||||
});
|
||||
|
||||
notificationSheetSubs = eventBus.on<ShowNotificationSheetEvent>().listen((
|
||||
event,
|
||||
) {
|
||||
if (mounted) {
|
||||
_showNotificationSheet();
|
||||
}
|
||||
});
|
||||
|
||||
final initialUrl = await protocolHandler.getInitialUrl();
|
||||
if (initialUrl != null && mounted) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
@@ -64,6 +85,8 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
ref.read(rpcServerProvider).stop();
|
||||
TrayService.instance.dispose(this);
|
||||
ntySubs?.cancel();
|
||||
composeSheetSubs?.cancel();
|
||||
notificationSheetSubs?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -80,9 +103,8 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
isDismissible: false,
|
||||
builder:
|
||||
(context) =>
|
||||
NetworkStatusSheet(onReconnect: () => wsNotifier.connect()),
|
||||
builder: (context) =>
|
||||
NetworkStatusSheet(onReconnect: () => wsNotifier.connect()),
|
||||
).then((_) => setState(() => networkStateShowing = false));
|
||||
});
|
||||
}
|
||||
@@ -119,6 +141,19 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
TrayService.instance.handleAction(menuItem);
|
||||
}
|
||||
|
||||
void _showComposeSheet() {
|
||||
PostComposeSheet.show(context);
|
||||
}
|
||||
|
||||
void _showNotificationSheet() {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => const NotificationSheet(),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleDeepLink(Uri uri, WidgetRef ref) async {
|
||||
String path = '/${uri.host}${uri.path}';
|
||||
|
||||
@@ -153,10 +188,9 @@ class _AppWrapperState extends ConsumerState<AppWrapper>
|
||||
|
||||
final router = ref.read(routerProvider);
|
||||
if (uri.queryParameters.isNotEmpty) {
|
||||
path =
|
||||
Uri.parse(
|
||||
path,
|
||||
).replace(queryParameters: uri.queryParameters).toString();
|
||||
path = Uri.parse(
|
||||
path,
|
||||
).replace(queryParameters: uri.queryParameters).toString();
|
||||
}
|
||||
router.push(path);
|
||||
if (!kIsWeb &&
|
||||
|
||||
@@ -18,6 +18,21 @@ import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:relative_time/relative_time.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/services/event_bus.dart';
|
||||
|
||||
class SpecialAction {
|
||||
final String name;
|
||||
final String description;
|
||||
final IconData icon;
|
||||
final VoidCallback action;
|
||||
|
||||
const SpecialAction({
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.icon,
|
||||
required this.action,
|
||||
});
|
||||
}
|
||||
|
||||
class CommandPattleWidget extends HookConsumerWidget {
|
||||
final VoidCallback onDismiss;
|
||||
@@ -189,6 +204,27 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
),
|
||||
];
|
||||
|
||||
static List<SpecialAction> _getSpecialActions(BuildContext context) {
|
||||
return [
|
||||
SpecialAction(
|
||||
name: 'Compose Post',
|
||||
description: 'Create a new post',
|
||||
icon: Symbols.edit,
|
||||
action: () {
|
||||
eventBus.fire(const ShowComposeSheetEvent());
|
||||
},
|
||||
),
|
||||
SpecialAction(
|
||||
name: 'Notifications',
|
||||
description: 'View your notifications',
|
||||
icon: Symbols.notifications,
|
||||
action: () {
|
||||
eventBus.fire(const ShowNotificationSheetEvent());
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final textController = useTextEditingController();
|
||||
@@ -269,8 +305,23 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
.take(5) // Limit to 5 results
|
||||
.toList();
|
||||
|
||||
// Combine results: chats first, then routes
|
||||
final allResults = [...filteredChats, ...filteredRoutes];
|
||||
final filteredSpecialActions = searchQuery.value.isEmpty
|
||||
? <SpecialAction>[]
|
||||
: _getSpecialActions(context)
|
||||
.where((action) {
|
||||
final query = searchQuery.value.toLowerCase();
|
||||
return action.name.toLowerCase().contains(query) ||
|
||||
action.description.toLowerCase().contains(query);
|
||||
})
|
||||
.take(5) // Limit to 5 results
|
||||
.toList();
|
||||
|
||||
// Combine results: chats first, then special actions, then routes
|
||||
final allResults = [
|
||||
...filteredChats,
|
||||
...filteredSpecialActions,
|
||||
...filteredRoutes,
|
||||
];
|
||||
|
||||
// Update focused index when results change
|
||||
useEffect(() {
|
||||
@@ -326,6 +377,9 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
final item = allResults[focusedIndex.value ?? 0];
|
||||
if (item is SnChatRoom) {
|
||||
_navigateToChat(context, ref, item);
|
||||
} else if (item is SpecialAction) {
|
||||
onDismiss();
|
||||
item.action();
|
||||
} else if (item is RouteItem) {
|
||||
_navigateToRoute(context, ref, item);
|
||||
}
|
||||
@@ -379,7 +433,7 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
@@ -389,8 +443,9 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
elevation: 0,
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -428,6 +483,16 @@ class CommandPattleWidget extends HookConsumerWidget {
|
||||
item,
|
||||
),
|
||||
);
|
||||
} else if (item is SpecialAction) {
|
||||
return _SpecialActionSearchResult(
|
||||
action: item,
|
||||
isFocused:
|
||||
index == focusedIndex.value,
|
||||
onTap: () {
|
||||
onDismiss();
|
||||
item.action();
|
||||
},
|
||||
);
|
||||
} else if (item is RouteItem) {
|
||||
return _RouteSearchResult(
|
||||
route: item,
|
||||
@@ -497,7 +562,7 @@ class _RouteSearchResult extends StatelessWidget {
|
||||
color: isFocused
|
||||
? Theme.of(context).colorScheme.surfaceContainerHighest
|
||||
: null,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(24)),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(28)),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
@@ -513,6 +578,40 @@ class _RouteSearchResult extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SpecialActionSearchResult extends StatelessWidget {
|
||||
final SpecialAction action;
|
||||
final bool isFocused;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _SpecialActionSearchResult({
|
||||
required this.action,
|
||||
required this.isFocused,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isFocused
|
||||
? Theme.of(context).colorScheme.surfaceContainerHighest
|
||||
: null,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(24)),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
|
||||
foregroundColor: Theme.of(context).colorScheme.onTertiaryContainer,
|
||||
child: Icon(action.icon),
|
||||
),
|
||||
title: Text(action.name),
|
||||
subtitle: Text(action.description),
|
||||
onTap: onTap,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ChatRoomSearchResult extends HookConsumerWidget {
|
||||
final SnChatRoom room;
|
||||
final bool isFocused;
|
||||
|
||||
@@ -179,7 +179,7 @@ class PostComposeSheet extends HookConsumerWidget {
|
||||
final isTablet =
|
||||
isWideScreen(context) &&
|
||||
!kIsWeb &&
|
||||
(Platform.isAndroid || Platform.isAndroid);
|
||||
(Platform.isAndroid || Platform.isIOS);
|
||||
|
||||
return SheetScaffold(
|
||||
heightFactor: isTablet ? 0.95 : 0.8,
|
||||
|
||||
24
pubspec.lock
24
pubspec.lock
@@ -2430,6 +2430,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
sensors_plus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sensors_plus
|
||||
sha256: "89e2bfc3d883743539ce5774a2b93df61effde40ff958ecad78cd66b1a8b8d52"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
sensors_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sensors_plus_platform_interface
|
||||
sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
shake:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shake
|
||||
sha256: "7bb2bd14e9cd23a0d569f8a286b2b63ba1552ac348914d2d41ec757117ddda4e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -173,6 +173,7 @@ dependencies:
|
||||
skeletonizer: ^2.1.2
|
||||
permission_handler: ^12.0.1
|
||||
hotkey_manager: ^0.2.3
|
||||
shake: ^3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user