♻️ Rebuilt the context menu
This commit is contained in:
parent
a7d4975e18
commit
1d52b8b5ed
@ -48,7 +48,12 @@ class ExploreScreen extends ConsumerWidget {
|
||||
onFetchData: controller.fetchMore,
|
||||
itemBuilder: (context, index) {
|
||||
final post = controller.posts[index];
|
||||
return PostItem(item: post);
|
||||
return PostItem(
|
||||
item: post,
|
||||
onRefresh: (_) {
|
||||
ref.invalidate(postListProvider);
|
||||
},
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) => const Divider(height: 1),
|
||||
),
|
||||
|
@ -131,7 +131,7 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
attachmentProgress.value = {...attachmentProgress.value, index: 0};
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: attachment,
|
||||
fileData: attachment.data,
|
||||
atk: atk,
|
||||
baseUrl: baseUrl,
|
||||
filename: attachment.data.name ?? 'Post media',
|
||||
|
@ -38,7 +38,7 @@ class PostDetailScreen extends HookConsumerWidget {
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
PostItem(item: post!),
|
||||
PostItem(item: post!, isOpenable: false),
|
||||
const Divider(height: 1),
|
||||
Expanded(child: PostRepliesList(postId: id)),
|
||||
Gap(MediaQuery.of(context).padding.bottom),
|
||||
|
@ -3,11 +3,14 @@ import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
|
||||
class UniversalVideo extends StatefulWidget {
|
||||
class UniversalVideo extends ConsumerStatefulWidget {
|
||||
final String uri;
|
||||
final double aspectRatio;
|
||||
const UniversalVideo({
|
||||
@ -17,10 +20,10 @@ class UniversalVideo extends StatefulWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
State<UniversalVideo> createState() => _UniversalVideoState();
|
||||
ConsumerState<UniversalVideo> createState() => _UniversalVideoState();
|
||||
}
|
||||
|
||||
class _UniversalVideoState extends State<UniversalVideo> {
|
||||
class _UniversalVideoState extends ConsumerState<UniversalVideo> {
|
||||
Player? _player;
|
||||
VideoController? _videoController;
|
||||
|
||||
@ -35,9 +38,18 @@ class _UniversalVideoState extends State<UniversalVideo> {
|
||||
final inCacheInfo = await DefaultCacheManager().getFileFromCache(url);
|
||||
if (inCacheInfo == null) {
|
||||
log('[MediaPlayer] Miss cache: $url');
|
||||
final baseUrl = ref.watch(serverUrlProvider);
|
||||
final atk = await getFreshAtk(
|
||||
ref.watch(tokenPairProvider),
|
||||
baseUrl,
|
||||
onRefreshed: (atk, rtk) {
|
||||
setTokenPair(ref.watch(sharedPreferencesProvider), atk, rtk);
|
||||
ref.invalidate(tokenPairProvider);
|
||||
},
|
||||
);
|
||||
final fileStream = DefaultCacheManager().getFileStream(
|
||||
url,
|
||||
// headers: {'Authorization': 'Bearer ${await ua.atk}'},
|
||||
headers: {'Authorization': 'Bearer $atk'},
|
||||
withProgress: true,
|
||||
);
|
||||
await for (var fileInfo in fileStream) {
|
||||
@ -55,7 +67,7 @@ class _UniversalVideoState extends State<UniversalVideo> {
|
||||
return;
|
||||
}
|
||||
|
||||
_player!.open(Media(uri));
|
||||
_player!.open(Media(uri), play: false);
|
||||
}
|
||||
|
||||
@override
|
||||
|
84
lib/widgets/context_menu.dart
Normal file
84
lib/widgets/context_menu.dart
Normal file
@ -0,0 +1,84 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
||||
typedef ContextMenuBuilder =
|
||||
Widget Function(BuildContext context, Offset offset);
|
||||
|
||||
class ContextMenuRegion extends HookWidget {
|
||||
final Offset? mobileAnchor;
|
||||
final Widget child;
|
||||
final ContextMenuBuilder contextMenuBuilder;
|
||||
const ContextMenuRegion({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.contextMenuBuilder,
|
||||
this.mobileAnchor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final contextMenuController = useMemoized(() => ContextMenuController());
|
||||
final mobileOffset = useState<Offset?>(null);
|
||||
|
||||
bool canBeTouchScreen = switch (defaultTargetPlatform) {
|
||||
TargetPlatform.android || TargetPlatform.iOS => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
void showMenu(Offset position) {
|
||||
contextMenuController.show(
|
||||
context: context,
|
||||
contextMenuBuilder: (BuildContext context) {
|
||||
return contextMenuBuilder(context, position);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void hideMenu() {
|
||||
contextMenuController.remove();
|
||||
}
|
||||
|
||||
void onSecondaryTapUp(TapUpDetails details) {
|
||||
showMenu(details.globalPosition);
|
||||
}
|
||||
|
||||
void onTap() {
|
||||
if (!contextMenuController.isShown) {
|
||||
return;
|
||||
}
|
||||
hideMenu();
|
||||
}
|
||||
|
||||
void onLongPressStart(LongPressStartDetails details) {
|
||||
mobileOffset.value = details.globalPosition;
|
||||
}
|
||||
|
||||
void onLongPress() {
|
||||
assert(mobileOffset.value != null);
|
||||
showMenu(mobileAnchor ?? mobileOffset.value!);
|
||||
mobileOffset.value = null;
|
||||
}
|
||||
|
||||
useEffect(() {
|
||||
return () {
|
||||
hideMenu();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return TapRegion(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onSecondaryTapUp: onSecondaryTapUp,
|
||||
onTap: onTap,
|
||||
onLongPress: canBeTouchScreen ? onLongPress : null,
|
||||
onLongPressStart: canBeTouchScreen ? onLongPressStart : null,
|
||||
child: child,
|
||||
),
|
||||
onTapOutside: (_) {
|
||||
hideMenu();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
@ -6,18 +7,20 @@ import 'package:island/route.gr.dart';
|
||||
import 'package:island/widgets/content/cloud_file_collection.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/markdown.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:island/widgets/context_menu.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class PostItem extends StatelessWidget {
|
||||
final SnPost item;
|
||||
final EdgeInsets? padding;
|
||||
final bool isOpenable;
|
||||
final Function? onRefresh;
|
||||
const PostItem({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.padding,
|
||||
this.isOpenable = true,
|
||||
this.onRefresh,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -25,21 +28,25 @@ class PostItem extends StatelessWidget {
|
||||
final renderingPadding =
|
||||
padding ?? EdgeInsets.symmetric(horizontal: 12, vertical: 16);
|
||||
|
||||
return CupertinoContextMenu.builder(
|
||||
actions: [
|
||||
CupertinoContextMenuAction(
|
||||
trailingIcon: LucideIcons.edit,
|
||||
return ContextMenuRegion(
|
||||
contextMenuBuilder: (_, offset) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: TextSelectionToolbarAnchors(primaryAnchor: offset),
|
||||
buttonItems: <ContextMenuButtonItem>[
|
||||
ContextMenuButtonItem(
|
||||
onPressed: () {
|
||||
context.router.push(PostEditRoute(id: item.id));
|
||||
ContextMenuController.removeAny();
|
||||
context.router.push(PostEditRoute(id: item.id)).then((value) {
|
||||
if (value != null) {
|
||||
onRefresh?.call();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Text('Edit'),
|
||||
label: 'edit'.tr(),
|
||||
),
|
||||
],
|
||||
builder: (context, animation) {
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SingleChildScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: renderingPadding,
|
||||
child: Column(
|
||||
@ -75,9 +82,6 @@ class PostItem extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user