route avatar crop and profile view through AppRoutes
This commit is contained in:
@@ -37,8 +37,10 @@ import '../view/pages/talk/talk_navigator.dart';
|
|||||||
import '../view/pages/ticker/ticker_page_view.dart';
|
import '../view/pages/ticker/ticker_page_view.dart';
|
||||||
import '../view/pages/timetable/custom_events/custom_events_view.dart';
|
import '../view/pages/timetable/custom_events/custom_events_view.dart';
|
||||||
import '../view/pages/timetable/subject_colors/subject_colors_view.dart';
|
import '../view/pages/timetable/subject_colors/subject_colors_view.dart';
|
||||||
|
import '../widget/avatar_crop_page.dart';
|
||||||
import '../widget/debug/cache_view.dart';
|
import '../widget/debug/cache_view.dart';
|
||||||
import '../widget/file_viewer.dart';
|
import '../widget/file_viewer.dart';
|
||||||
|
import '../widget/large_profile_picture_view.dart';
|
||||||
import '../widget/user_avatar.dart';
|
import '../widget/user_avatar.dart';
|
||||||
|
|
||||||
/// Single entry point for full-page navigations. Dialogs and bottom sheets
|
/// Single entry point for full-page navigations. Dialogs and bottom sheets
|
||||||
@@ -95,6 +97,30 @@ class AppRoutes {
|
|||||||
pushScreen(context, withNavBar: false, screen: const SubjectColorsView());
|
pushScreen(context, withNavBar: false, screen: const SubjectColorsView());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens the full-screen cropper on [imageBytes] and resolves to the cropped
|
||||||
|
/// bytes (or null if cancelled). [aspectRatio] defaults to 1:1 for avatars;
|
||||||
|
/// pass null for a free-form crop (e.g. chat backgrounds).
|
||||||
|
static Future<Uint8List?> openAvatarCrop(
|
||||||
|
BuildContext context, {
|
||||||
|
required Uint8List imageBytes,
|
||||||
|
double? aspectRatio = 1,
|
||||||
|
}) {
|
||||||
|
return Navigator.of(context).push<Uint8List>(
|
||||||
|
MaterialPageRoute(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (_) =>
|
||||||
|
AvatarCropPage(imageBytes: imageBytes, aspectRatio: aspectRatio),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Opens the tappable, zoomable profile-picture viewer for [id].
|
||||||
|
static void openLargeProfilePicture(BuildContext context, String id) {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute<void>(builder: (_) => LargeProfilePictureView(id: id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens the picker for choosing a foreign timetable element and resolves to
|
/// Opens the picker for choosing a foreign timetable element and resolves to
|
||||||
/// the selected element (or null if dismissed). The timetable view renders
|
/// the selected element (or null if dismissed). The timetable view renders
|
||||||
/// the chosen plan inline. Gated behind the `viewForeignTimetables`
|
/// the chosen plan inline. Gated behind the `viewForeignTimetables`
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import '../../../../api/marianumcloud/cloud_users/cloud_users_actions.dart';
|
|||||||
import '../../../../api/marianumconnect/queries/auth_logout/auth_logout.dart';
|
import '../../../../api/marianumconnect/queries/auth_logout/auth_logout.dart';
|
||||||
import '../../../../model/account_data.dart';
|
import '../../../../model/account_data.dart';
|
||||||
import '../../../../push/push_registration.dart';
|
import '../../../../push/push_registration.dart';
|
||||||
|
import '../../../../routing/app_routes.dart';
|
||||||
import '../../../../state/app/modules/account/bloc/account_bloc.dart';
|
import '../../../../state/app/modules/account/bloc/account_bloc.dart';
|
||||||
import '../../../../state/app/modules/account/bloc/account_state.dart';
|
import '../../../../state/app/modules/account/bloc/account_state.dart';
|
||||||
import '../../../../widget/app_progress_indicator.dart';
|
import '../../../../widget/app_progress_indicator.dart';
|
||||||
@@ -12,7 +13,6 @@ import '../../../../widget/async_action_button.dart';
|
|||||||
import '../../../../widget/avatar_actions_sheet.dart';
|
import '../../../../widget/avatar_actions_sheet.dart';
|
||||||
import '../../../../widget/confirm_dialog.dart';
|
import '../../../../widget/confirm_dialog.dart';
|
||||||
import '../../../../widget/demo_restricted.dart';
|
import '../../../../widget/demo_restricted.dart';
|
||||||
import '../../../../widget/large_profile_picture_view.dart';
|
|
||||||
import '../../../../widget/user_avatar.dart';
|
import '../../../../widget/user_avatar.dart';
|
||||||
|
|
||||||
// Display-name is process-wide stable until the user logs out; cache it so
|
// Display-name is process-wide stable until the user logs out; cache it so
|
||||||
@@ -107,12 +107,8 @@ class _AccountSectionState extends State<AccountSection> {
|
|||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => Navigator.of(context).push(
|
onTap: () =>
|
||||||
MaterialPageRoute<void>(
|
AppRoutes.openLargeProfilePicture(context, username),
|
||||||
builder: (_) =>
|
|
||||||
LargeProfilePictureView(id: username),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: UserAvatar(
|
child: UserAvatar(
|
||||||
key: ValueKey(_avatarVersion),
|
key: ValueKey(_avatarVersion),
|
||||||
id: username,
|
id: username,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'dart:typed_data';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
import 'avatar_crop_page.dart';
|
import '../routing/app_routes.dart';
|
||||||
import 'file_pick.dart';
|
import 'file_pick.dart';
|
||||||
|
|
||||||
/// Result of the user's choice inside [showAvatarActionsSheet]. The sheet
|
/// Result of the user's choice inside [showAvatarActionsSheet]. The sheet
|
||||||
@@ -107,10 +107,5 @@ Future<Uint8List?> _pickAndCrop(
|
|||||||
if (picked == null) return null;
|
if (picked == null) return null;
|
||||||
final bytes = await picked.readAsBytes();
|
final bytes = await picked.readAsBytes();
|
||||||
if (!context.mounted) return null;
|
if (!context.mounted) return null;
|
||||||
return Navigator.of(context).push<Uint8List>(
|
return AppRoutes.openAvatarCrop(context, imageBytes: bytes);
|
||||||
MaterialPageRoute(
|
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (_) => AvatarCropPage(imageBytes: bytes),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'dart:typed_data';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
import 'avatar_crop_page.dart';
|
import '../routing/app_routes.dart';
|
||||||
import 'file_pick.dart';
|
import 'file_pick.dart';
|
||||||
|
|
||||||
/// Bottom sheet with "from gallery" and "take photo" actions for choosing a
|
/// Bottom sheet with "from gallery" and "take photo" actions for choosing a
|
||||||
@@ -61,12 +61,7 @@ Future<Uint8List?> showChatBackgroundPickerSheet(BuildContext context) async {
|
|||||||
Future<Uint8List?> cropChatBackgroundImage(
|
Future<Uint8List?> cropChatBackgroundImage(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Uint8List bytes,
|
Uint8List bytes,
|
||||||
) => Navigator.of(context).push<Uint8List>(
|
) => AppRoutes.openAvatarCrop(context, imageBytes: bytes, aspectRatio: null);
|
||||||
MaterialPageRoute(
|
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (_) => AvatarCropPage(imageBytes: bytes, aspectRatio: null),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<Uint8List?> _pickRaw(Future<XFile?> Function() pick) async {
|
Future<Uint8List?> _pickRaw(Future<XFile?> Function() pick) async {
|
||||||
final picked = await pick();
|
final picked = await pick();
|
||||||
|
|||||||
Reference in New Issue
Block a user