2253 activity planner feedback (#2256)
* chore: UI / UX updates to activity launching * chore: launch generated activities into existing chat if available
This commit is contained in:
parent
12e8e19932
commit
dd8ec30712
17 changed files with 516 additions and 353 deletions
|
|
@ -4826,7 +4826,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"startChatting": "Start chatting",
|
||||
"referFriends": "Refer friends",
|
||||
"referFriendDialogTitle": "Invite a friend to your conversation",
|
||||
"referFriendDialogDesc": "Do you have a friend who is excited to learn a new language with you? Then copy and send this invitation link to join and start chatting with you today.",
|
||||
|
|
@ -4835,12 +4834,14 @@
|
|||
"resetInstructionTooltipsDesc": "Click to show instruction tooltips like for a brand new user.",
|
||||
"selectForGrammar": "Select a grammar icon for activities and details.",
|
||||
"newChatActivityTitle": "Add a fun activity",
|
||||
"newChatActivityDesc": "Make every group chat an adventure with Activity Planner! Set captivating topics and objectives for the group, and bring conversations to life with stunning images. Spark imaginative discussions and keep the fun flowing effortlessly!",
|
||||
"newChatActivityDesc": "Choose one of the activities below to add to your chat or skip this step and create an activity later.",
|
||||
"exploreMore": "Explore more",
|
||||
"randomize": "Randomize",
|
||||
"clear": "Clear",
|
||||
"makeYourOwnActivity": "Make your own activity",
|
||||
"makeYourOwn": "Make your own",
|
||||
"featuredActivities": "Featured activities",
|
||||
"yourBookmarks": "Your bookmarks"
|
||||
"yourBookmarks": "Your bookmarks",
|
||||
"goToChat": "Go to chat",
|
||||
"save": "Save",
|
||||
"selectActivity": "Select activity"
|
||||
}
|
||||
|
|
@ -574,6 +574,19 @@ abstract class AppRoutes {
|
|||
),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/generator',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
ActivityGenerator(
|
||||
roomID: state.pathParameters['roomid']!,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// GoRoute(
|
||||
// path: 'encryption',
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
color: DefaultTextStyle.of(context).style.color,
|
||||
),
|
||||
Text(
|
||||
L10n.of(context).startChatting,
|
||||
L10n.of(context).goToChat,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@ class NewGroupController extends State<NewGroup> {
|
|||
TextEditingController nameController = TextEditingController();
|
||||
|
||||
// #Pangea
|
||||
ActivityPlanModel? _selectedActivity;
|
||||
ActivityPlanModel? selectedActivity;
|
||||
Uint8List? selectedActivityImage;
|
||||
String? selectedActivityImageFilename;
|
||||
|
||||
bool requiredCodeToJoin = false;
|
||||
// bool publicGroup = false;
|
||||
// Pangea#
|
||||
|
|
@ -64,8 +67,23 @@ class NewGroupController extends State<NewGroup> {
|
|||
// setState(() => publicGroup = groupCanBeFound = b);
|
||||
void setRequireCode(bool b) => setState(() => requiredCodeToJoin = b);
|
||||
|
||||
void setSelectedActivity(ActivityPlanModel? activity) =>
|
||||
setState(() => _selectedActivity = activity);
|
||||
void setSelectedActivity(
|
||||
ActivityPlanModel? activity,
|
||||
Uint8List? image,
|
||||
String? imageFilename,
|
||||
) {
|
||||
setState(() {
|
||||
selectedActivity = activity;
|
||||
selectedActivityImage = image;
|
||||
selectedActivityImageFilename = imageFilename;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
nameController.addListener(() => setState(() {}));
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
void setGroupCanBeFound(bool b) => setState(() => groupCanBeFound = b);
|
||||
|
|
@ -118,14 +136,18 @@ class NewGroupController extends State<NewGroup> {
|
|||
);
|
||||
if (!mounted) return;
|
||||
// #Pangea
|
||||
if (_selectedActivity != null) {
|
||||
if (selectedActivity != null) {
|
||||
Room? room = Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) {
|
||||
await Matrix.of(context).client.waitForRoomInSync(roomId);
|
||||
room = Matrix.of(context).client.getRoomById(roomId);
|
||||
}
|
||||
if (room == null) return;
|
||||
await room.sendActivityPlan(_selectedActivity!);
|
||||
await room.sendActivityPlan(
|
||||
selectedActivity!,
|
||||
avatar: selectedActivityImage,
|
||||
filename: selectedActivityImageFilename,
|
||||
);
|
||||
}
|
||||
// if a timeout happened, don't redirect to the chat
|
||||
if (error != null) return;
|
||||
|
|
@ -230,8 +252,11 @@ class NewGroupController extends State<NewGroup> {
|
|||
final client = Matrix.of(context).client;
|
||||
|
||||
try {
|
||||
if (nameController.text.trim().isEmpty &&
|
||||
createGroupType == CreateGroupType.space) {
|
||||
// #Pangea
|
||||
// if (nameController.text.trim().isEmpty &&
|
||||
// createGroupType == CreateGroupType.space) {
|
||||
if (nameController.text.trim().isEmpty) {
|
||||
// Pangea#
|
||||
setState(() => error = L10n.of(context).pleaseFillOut);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ class NewGroupView extends StatelessWidget {
|
|||
body: MaxWidthBody(
|
||||
// #Pangea
|
||||
showBorder: false,
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32.0,
|
||||
right: 32.0,
|
||||
bottom: 32.0,
|
||||
),
|
||||
// Pangea#
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -180,6 +185,9 @@ class NewGroupView extends StatelessWidget {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: ActivitySuggestionCarousel(
|
||||
onActivitySelected: controller.setSelectedActivity,
|
||||
enabled: controller.nameController.text.isNotEmpty,
|
||||
selectedActivity: controller.selectedActivity,
|
||||
selectedActivityImage: controller.selectedActivityImage,
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/activity_generator/activity_generator_view.dart';
|
||||
|
|
@ -21,7 +22,11 @@ import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_en
|
|||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ActivityGenerator extends StatefulWidget {
|
||||
const ActivityGenerator({super.key});
|
||||
final String? roomID;
|
||||
const ActivityGenerator({
|
||||
this.roomID,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ActivityGeneratorState createState() => ActivityGeneratorState();
|
||||
|
|
@ -93,6 +98,10 @@ class ActivityGeneratorState extends State<ActivityGenerator> {
|
|||
Future<List<ActivitySettingResponseSchema>> get objectiveItems =>
|
||||
LearningObjectiveListRepo.get(req);
|
||||
|
||||
Room? get room => widget.roomID != null
|
||||
? Matrix.of(context).client.getRoomById(widget.roomID!)
|
||||
: null;
|
||||
|
||||
String? validateNotNull(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return L10n.of(context).interactiveTranslatorRequired;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class ActivityGeneratorView extends StatelessWidget {
|
|||
itemBuilder: (context, index) {
|
||||
return ActivityPlanCard(
|
||||
activity: controller.activities![index],
|
||||
room: null,
|
||||
room: controller.room,
|
||||
onEdit: (updatedActivity) =>
|
||||
controller.onEdit(index, updatedActivity),
|
||||
onChange: controller.update,
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
|
|||
filename: _filename,
|
||||
);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
context.go("/rooms/${widget.room?.id}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ class ActivityPlanCardState extends State<ActivityPlanCard> {
|
|||
filename: _filename,
|
||||
);
|
||||
|
||||
context.go("/rooms/$roomId");
|
||||
context.go("/rooms/$roomId/invite");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_planner_page_appbar.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/bookmarked_activity_list.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/activity_suggestions_area.dart';
|
||||
|
|
@ -43,11 +41,12 @@ class ActivityPlannerPageState extends State<ActivityPlannerPage> {
|
|||
);
|
||||
break;
|
||||
case PageMode.featuredActivities:
|
||||
body = const Expanded(
|
||||
body = Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: ActivitySuggestionsArea(
|
||||
scrollDirection: Axis.vertical,
|
||||
includeCustomCards: false,
|
||||
showCreateChatCard: false,
|
||||
room: room,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -90,28 +89,6 @@ class ActivityPlannerPageState extends State<ActivityPlannerPage> {
|
|||
],
|
||||
),
|
||||
body,
|
||||
if (!FluffyThemes.isColumnMode(context))
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () => context.go("/rooms/planner"),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 0.0,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context).makeYourOwn,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_planner_page.dart';
|
||||
|
||||
class ActivityPlannerPageAppBar extends StatelessWidget
|
||||
|
|
@ -23,14 +21,9 @@ class ActivityPlannerPageAppBar extends StatelessWidget
|
|||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
return AppBar(
|
||||
leadingWidth: FluffyThemes.isColumnMode(context) ? 150.0 : 50.0,
|
||||
leading: Container(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
title: pageMode == PageMode.savedActivities
|
||||
? Center(
|
||||
|
|
@ -60,27 +53,6 @@ class ActivityPlannerPageAppBar extends StatelessWidget
|
|||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
FluffyThemes.isColumnMode(context)
|
||||
? Container(
|
||||
width: 150.0,
|
||||
alignment: Alignment.centerRight,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => context.go("/rooms/planner"),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 0.0,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
L10n.of(context).makeYourOwn,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(width: 50.0),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_planner_page.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/bookmarked_activities_repo.dart';
|
||||
import 'activity_plan_card.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_card.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_dialog.dart';
|
||||
|
||||
class BookmarkedActivitiesList extends StatefulWidget {
|
||||
final Room? room;
|
||||
|
|
@ -28,6 +30,12 @@ class BookmarkedActivitiesListState extends State<BookmarkedActivitiesList> {
|
|||
List<ActivityPlanModel> get _bookmarkedActivities =>
|
||||
BookmarkedActivitiesRepo.get();
|
||||
|
||||
bool get _isColumnMode => FluffyThemes.isColumnMode(context);
|
||||
|
||||
final double cardHeight = 250.0;
|
||||
double get cardPadding => _isColumnMode ? 8.0 : 0.0;
|
||||
double get cardWidth => _isColumnMode ? 225.0 : 150.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
|
|
@ -44,22 +52,36 @@ class BookmarkedActivitiesListState extends State<BookmarkedActivitiesList> {
|
|||
}
|
||||
|
||||
return Expanded(
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.all(16),
|
||||
itemCount: _bookmarkedActivities.length,
|
||||
itemBuilder: (context, index) {
|
||||
final activity = _bookmarkedActivities[index];
|
||||
return ActivityPlanCard(
|
||||
activity: activity,
|
||||
room: widget.room,
|
||||
onEdit: (updatedActivity) async {
|
||||
await BookmarkedActivitiesRepo.remove(activity.bookmarkId);
|
||||
await BookmarkedActivitiesRepo.save(updatedActivity);
|
||||
setState(() {});
|
||||
},
|
||||
onChange: () => setState(() {}),
|
||||
);
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 800.0,
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.spaceEvenly,
|
||||
runSpacing: 16.0,
|
||||
spacing: 4.0,
|
||||
children: _bookmarkedActivities.map((activity) {
|
||||
return ActivitySuggestionCard(
|
||||
activity: activity,
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ActivitySuggestionDialog(
|
||||
activity: activity,
|
||||
buttonText: L10n.of(context).inviteAndLaunch,
|
||||
room: widget.room,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
padding: cardPadding,
|
||||
onChange: () => setState(() {}),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
|
|
@ -9,11 +12,13 @@ import 'package:fluffychat/pangea/common/widgets/pressable_button.dart';
|
|||
|
||||
class ActivitySuggestionCard extends StatelessWidget {
|
||||
final ActivityPlanModel activity;
|
||||
final VoidCallback onPressed;
|
||||
final Uint8List? image;
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final double padding;
|
||||
final bool selected;
|
||||
|
||||
final VoidCallback onChange;
|
||||
|
||||
|
|
@ -25,6 +30,8 @@ class ActivitySuggestionCard extends StatelessWidget {
|
|||
required this.height,
|
||||
required this.padding,
|
||||
required this.onChange,
|
||||
this.selected = false,
|
||||
this.image,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -35,10 +42,19 @@ class ActivitySuggestionCard extends StatelessWidget {
|
|||
return Padding(
|
||||
padding: EdgeInsets.all(padding),
|
||||
child: PressableButton(
|
||||
depressed: selected || onPressed == null,
|
||||
onPressed: onPressed,
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
color: theme.colorScheme.primary,
|
||||
child: SizedBox(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: selected
|
||||
? Border.all(
|
||||
color: theme.colorScheme.primary,
|
||||
)
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
),
|
||||
height: height,
|
||||
width: width,
|
||||
child: Stack(
|
||||
|
|
@ -58,13 +74,25 @@ class ActivitySuggestionCard extends StatelessWidget {
|
|||
height: 100,
|
||||
width: width,
|
||||
decoration: BoxDecoration(
|
||||
image: activity.imageURL != null
|
||||
? DecorationImage(
|
||||
image: NetworkImage(activity.imageURL!),
|
||||
)
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: image != null
|
||||
? Image.memory(image!)
|
||||
: activity.imageURL != null
|
||||
? CachedNetworkImage(
|
||||
imageUrl: activity.imageURL!,
|
||||
placeholder: (context, url) => const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
errorWidget: (context, url, error) => Icon(
|
||||
Icons.error,
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
|
|
@ -144,11 +172,13 @@ class ActivitySuggestionCard extends StatelessWidget {
|
|||
icon: Icon(
|
||||
isBookmarked ? Icons.bookmark : Icons.bookmark_border,
|
||||
),
|
||||
onPressed: () => isBookmarked
|
||||
? BookmarkedActivitiesRepo.remove(activity.bookmarkId)
|
||||
.then((_) => onChange())
|
||||
: BookmarkedActivitiesRepo.save(activity)
|
||||
.then((_) => onChange()),
|
||||
onPressed: onPressed != null
|
||||
? () => isBookmarked
|
||||
? BookmarkedActivitiesRepo.remove(activity.bookmarkId)
|
||||
.then((_) => onChange())
|
||||
: BookmarkedActivitiesRepo.save(activity)
|
||||
.then((_) => onChange())
|
||||
: null,
|
||||
iconSize: 24.0,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -5,7 +6,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
|
|
@ -20,9 +20,20 @@ import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_en
|
|||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ActivitySuggestionCarousel extends StatefulWidget {
|
||||
final Function(ActivityPlanModel?) onActivitySelected;
|
||||
final Function(
|
||||
ActivityPlanModel?,
|
||||
Uint8List? avatar,
|
||||
String? filename,
|
||||
) onActivitySelected;
|
||||
final ActivityPlanModel? selectedActivity;
|
||||
final Uint8List? selectedActivityImage;
|
||||
final bool enabled;
|
||||
|
||||
const ActivitySuggestionCarousel({
|
||||
required this.onActivitySelected,
|
||||
required this.selectedActivity,
|
||||
required this.selectedActivityImage,
|
||||
this.enabled = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -84,10 +95,13 @@ class ActivitySuggestionCarouselState
|
|||
return index == -1 ? null : index;
|
||||
}
|
||||
|
||||
bool get _canMoveLeft => _currentIndex != null && _currentIndex! > 0;
|
||||
bool get _canMoveLeft =>
|
||||
widget.enabled && _currentIndex != null && _currentIndex! > 0;
|
||||
|
||||
bool get _canMoveRight =>
|
||||
_currentIndex != null && _currentIndex! < _activityItems.length - 1;
|
||||
widget.enabled &&
|
||||
_currentIndex != null &&
|
||||
_currentIndex! < _activityItems.length - 1;
|
||||
|
||||
void _moveLeft() {
|
||||
if (!_canMoveLeft) return;
|
||||
|
|
@ -101,17 +115,37 @@ class ActivitySuggestionCarouselState
|
|||
|
||||
void _setActivityByIndex(int index) {
|
||||
if (index < 0 || index >= _activityItems.length) return;
|
||||
widget.onActivitySelected(_activityItems[index]);
|
||||
setState(() {
|
||||
_currentActivity = _activityItems[index];
|
||||
});
|
||||
}
|
||||
|
||||
void _close() {
|
||||
widget.onActivitySelected(null);
|
||||
widget.onActivitySelected(null, null, null);
|
||||
setState(() => _isOpen = false);
|
||||
}
|
||||
|
||||
void _onClickCard() {
|
||||
if (widget.selectedActivity == _currentActivity) {
|
||||
widget.onActivitySelected(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
return;
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ActivitySuggestionDialog(
|
||||
activity: _currentActivity!,
|
||||
buttonText: L10n.of(context).selectActivity,
|
||||
launch: widget.onActivitySelected,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
|
@ -119,168 +153,169 @@ class ActivitySuggestionCarouselState
|
|||
duration: FluffyThemes.animationDuration,
|
||||
child: !_isOpen
|
||||
? const SizedBox.shrink()
|
||||
: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: theme.dividerColor),
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context).newChatActivityTitle,
|
||||
style: theme.textTheme.titleLarge,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: _close,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(L10n.of(context).newChatActivityDesc),
|
||||
Row(
|
||||
spacing: _isColumnMode ? 16.0 : 4.0,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MouseRegion(
|
||||
cursor: _canMoveLeft
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: _canMoveLeft ? _moveLeft : null,
|
||||
child: Icon(
|
||||
Icons.chevron_left_outlined,
|
||||
size: 32.0,
|
||||
color: _canMoveLeft ? null : theme.disabledColor,
|
||||
),
|
||||
: AnimatedOpacity(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
opacity: widget.enabled ? 1.0 : 0.5,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: theme.dividerColor),
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context).newChatActivityTitle,
|
||||
style: theme.textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
constraints:
|
||||
BoxConstraints(maxHeight: _cardHeight + 12.0),
|
||||
child: _error != null ||
|
||||
(_currentActivity == null && !_loading)
|
||||
? const SizedBox.shrink()
|
||||
: _loading
|
||||
? Shimmer.fromColors(
|
||||
baseColor:
|
||||
theme.colorScheme.primary.withAlpha(50),
|
||||
highlightColor: theme.colorScheme.primary
|
||||
.withAlpha(150),
|
||||
child: Container(
|
||||
height: _cardHeight,
|
||||
width: _cardWidth,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
theme.colorScheme.surfaceContainer,
|
||||
borderRadius:
|
||||
BorderRadius.circular(24.0),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ActivitySuggestionCard(
|
||||
activity: _currentActivity!,
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ActivitySuggestionDialog(
|
||||
activity: _currentActivity!,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
width: _cardWidth,
|
||||
height: _cardHeight,
|
||||
padding: 0.0,
|
||||
onChange: () {
|
||||
if (mounted) setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: _canMoveRight
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: _canMoveRight ? _moveRight : null,
|
||||
child: Icon(
|
||||
Icons.chevron_right_outlined,
|
||||
size: 32.0,
|
||||
color: _canMoveRight ? null : theme.disabledColor,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: widget.enabled ? _close : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 16.0,
|
||||
children: _activityItems.mapIndexed((i, activity) {
|
||||
final selected = activity == _currentActivity;
|
||||
return InkWell(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
onTap: () => _setActivityByIndex(i),
|
||||
child: ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(
|
||||
sigmaX: selected ? 0.0 : 0.5,
|
||||
sigmaY: selected ? 0.0 : 0.5,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: selected ? 1.0 : 0.5,
|
||||
child: ClipOval(
|
||||
child: SizedBox.fromSize(
|
||||
size: const Size.fromRadius(12.0),
|
||||
child: activity.imageURL != null
|
||||
? CachedNetworkImage(
|
||||
imageUrl: activity.imageURL!,
|
||||
errorWidget: (context, url, error) {
|
||||
return CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.secondary,
|
||||
radius: 12.0,
|
||||
);
|
||||
},
|
||||
progressIndicatorBuilder:
|
||||
(context, url, progress) {
|
||||
return CircularProgressIndicator(
|
||||
value: progress.progress,
|
||||
);
|
||||
},
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.secondary,
|
||||
radius: 12.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(L10n.of(context).newChatActivityDesc),
|
||||
Row(
|
||||
spacing: _isColumnMode ? 16.0 : 4.0,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MouseRegion(
|
||||
cursor: _canMoveLeft
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: _canMoveLeft ? _moveLeft : null,
|
||||
child: Icon(
|
||||
Icons.chevron_left_outlined,
|
||||
size: 32.0,
|
||||
color: _canMoveLeft ? null : theme.disabledColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => _isColumnMode
|
||||
? context.go("/rooms")
|
||||
: context.go("/rooms/homepage"),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primaryContainer,
|
||||
),
|
||||
child: _loading
|
||||
? const LinearProgressIndicator()
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(L10n.of(context).exploreMore),
|
||||
],
|
||||
Container(
|
||||
constraints:
|
||||
BoxConstraints(maxHeight: _cardHeight + 12.0),
|
||||
child: _error != null ||
|
||||
(_currentActivity == null && !_loading)
|
||||
? const SizedBox.shrink()
|
||||
: _loading
|
||||
? Shimmer.fromColors(
|
||||
baseColor: theme.colorScheme.primary
|
||||
.withAlpha(50),
|
||||
highlightColor: theme.colorScheme.primary
|
||||
.withAlpha(150),
|
||||
child: Container(
|
||||
height: _cardHeight,
|
||||
width: _cardWidth,
|
||||
decoration: BoxDecoration(
|
||||
color: theme
|
||||
.colorScheme.surfaceContainer,
|
||||
borderRadius:
|
||||
BorderRadius.circular(24.0),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ActivitySuggestionCard(
|
||||
selected: widget.selectedActivity ==
|
||||
_currentActivity,
|
||||
activity: _currentActivity!,
|
||||
onPressed:
|
||||
widget.enabled ? _onClickCard : null,
|
||||
width: _cardWidth,
|
||||
height: _cardHeight,
|
||||
padding: 0.0,
|
||||
image: _currentActivity ==
|
||||
widget.selectedActivity
|
||||
? widget.selectedActivityImage
|
||||
: null,
|
||||
onChange: () {
|
||||
if (mounted) setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: _canMoveRight
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
child: GestureDetector(
|
||||
onTap: _canMoveRight ? _moveRight : null,
|
||||
child: Icon(
|
||||
Icons.chevron_right_outlined,
|
||||
size: 32.0,
|
||||
color: _canMoveRight ? null : theme.disabledColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 16.0,
|
||||
children: _activityItems.mapIndexed((i, activity) {
|
||||
final selected = activity == _currentActivity;
|
||||
return InkWell(
|
||||
enableFeedback: widget.enabled,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
onTap: widget.enabled
|
||||
? () => _setActivityByIndex(i)
|
||||
: null,
|
||||
child: ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(
|
||||
sigmaX: selected ? 0.0 : 0.5,
|
||||
sigmaY: selected ? 0.0 : 0.5,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: selected ? 1.0 : 0.5,
|
||||
child: ClipOval(
|
||||
child: SizedBox.fromSize(
|
||||
size: const Size.fromRadius(12.0),
|
||||
child: activity.imageURL != null
|
||||
? CachedNetworkImage(
|
||||
imageUrl: activity.imageURL!,
|
||||
errorWidget: (context, url, error) {
|
||||
return CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.secondary,
|
||||
radius: 12.0,
|
||||
);
|
||||
},
|
||||
progressIndicatorBuilder:
|
||||
(context, url, progress) {
|
||||
return CircularProgressIndicator(
|
||||
value: progress.progress,
|
||||
);
|
||||
},
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundColor:
|
||||
theme.colorScheme.secondary,
|
||||
radius: 12.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: widget.enabled ? _close : null,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primaryContainer,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(L10n.of(context).skip),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:matrix/matrix.dart' as sdk;
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/matrix_api_lite/generated/model.dart' as sdk;
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
|
|
@ -24,8 +24,20 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
|
||||
class ActivitySuggestionDialog extends StatefulWidget {
|
||||
final ActivityPlanModel activity;
|
||||
final String buttonText;
|
||||
final Room? room;
|
||||
|
||||
final Function(
|
||||
ActivityPlanModel,
|
||||
Uint8List? avatar,
|
||||
String? filename,
|
||||
)? launch;
|
||||
|
||||
const ActivitySuggestionDialog({
|
||||
required this.activity,
|
||||
required this.buttonText,
|
||||
this.launch,
|
||||
this.room,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -36,9 +48,8 @@ class ActivitySuggestionDialog extends StatefulWidget {
|
|||
|
||||
class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
||||
bool _isEditing = false;
|
||||
|
||||
Uint8List? _avatar;
|
||||
String? _avatarURL;
|
||||
String? _filename;
|
||||
|
||||
final TextEditingController _titleController = TextEditingController();
|
||||
final TextEditingController _instructionsController = TextEditingController();
|
||||
|
|
@ -62,6 +73,7 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
_participantsController.text =
|
||||
widget.activity.req.numberOfParticipants.toString();
|
||||
_vocab.addAll(widget.activity.vocab);
|
||||
_setAvatarByURL();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -86,20 +98,25 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
allowMultiple: false,
|
||||
);
|
||||
final bytes = await photo.singleOrNull?.readAsBytes();
|
||||
if (mounted) setState(() => _avatar = bytes);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_avatar = bytes;
|
||||
_filename = photo.singleOrNull?.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setAvatarURL() async {
|
||||
if (widget.activity.imageURL == null && _avatar == null) return;
|
||||
Future<void> _setAvatarByURL() async {
|
||||
if (widget.activity.imageURL == null) return;
|
||||
try {
|
||||
if (_avatar == null) {
|
||||
final Response response =
|
||||
await http.get(Uri.parse(widget.activity.imageURL!));
|
||||
_avatar = response.bodyBytes;
|
||||
_filename = Uri.encodeComponent(
|
||||
Uri.parse(widget.activity.imageURL!).pathSegments.last,
|
||||
);
|
||||
}
|
||||
final resp = await Matrix.of(context).client.uploadContent(_avatar!);
|
||||
if (mounted) setState(() => _avatarURL = resp.toString());
|
||||
widget.activity.imageURL = _avatarURL;
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
|
|
@ -113,7 +130,8 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
|
||||
void _clearEdits() {
|
||||
_avatar = null;
|
||||
_avatarURL = null;
|
||||
_filename = null;
|
||||
_setAvatarByURL();
|
||||
_vocab.clear();
|
||||
_vocab.addAll(widget.activity.vocab);
|
||||
if (mounted) setState(() {});
|
||||
|
|
@ -145,47 +163,45 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _launch() async {
|
||||
Future<void> _launchActivity() async {
|
||||
if (widget.room != null) {
|
||||
await widget.room!.sendActivityPlan(
|
||||
widget.activity,
|
||||
avatar: _avatar,
|
||||
filename: _filename,
|
||||
);
|
||||
context.go("/rooms/${widget.room!.id}/invite");
|
||||
return;
|
||||
}
|
||||
|
||||
final client = Matrix.of(context).client;
|
||||
|
||||
final resp = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
await _setAvatarURL();
|
||||
final roomId = await client.createGroupChat(
|
||||
preset: CreateRoomPreset.publicChat,
|
||||
visibility: sdk.Visibility.private,
|
||||
groupName: widget.activity.title,
|
||||
initialState: [
|
||||
if (_avatarURL != null)
|
||||
StateEvent(
|
||||
type: EventTypes.RoomAvatar,
|
||||
content: {'url': _avatarURL.toString()},
|
||||
),
|
||||
StateEvent(
|
||||
type: EventTypes.RoomPowerLevels,
|
||||
stateKey: '',
|
||||
content: defaultPowerLevels(client.userID!),
|
||||
),
|
||||
],
|
||||
enableEncryption: false,
|
||||
);
|
||||
|
||||
Room? room = Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) {
|
||||
await client.waitForRoomInSync(roomId);
|
||||
room = Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) return;
|
||||
}
|
||||
|
||||
await room.sendActivityPlan(widget.activity);
|
||||
context.go("/rooms/$roomId/invite");
|
||||
},
|
||||
final roomId = await client.createGroupChat(
|
||||
preset: CreateRoomPreset.publicChat,
|
||||
visibility: sdk.Visibility.private,
|
||||
groupName: widget.activity.title,
|
||||
initialState: [
|
||||
StateEvent(
|
||||
type: EventTypes.RoomPowerLevels,
|
||||
stateKey: '',
|
||||
content: defaultPowerLevels(client.userID!),
|
||||
),
|
||||
],
|
||||
enableEncryption: false,
|
||||
);
|
||||
|
||||
if (!resp.isError) {
|
||||
Navigator.of(context).pop();
|
||||
Room? room = Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) {
|
||||
await client.waitForRoomInSync(roomId);
|
||||
room = Matrix.of(context).client.getRoomById(roomId);
|
||||
if (room == null) return;
|
||||
}
|
||||
|
||||
await room.sendActivityPlan(
|
||||
widget.activity,
|
||||
avatar: _avatar,
|
||||
filename: _filename,
|
||||
);
|
||||
context.go("/rooms/$roomId/invite");
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -445,17 +461,6 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
child: Row(
|
||||
spacing: 6.0,
|
||||
children: [
|
||||
if (_isEditing)
|
||||
GestureDetector(
|
||||
child: const Icon(Icons.save_outlined, size: 16.0),
|
||||
onTap: () {
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
_updateTextFields();
|
||||
_setEditing(false);
|
||||
},
|
||||
),
|
||||
if (_isEditing)
|
||||
GestureDetector(
|
||||
child: const Icon(Icons.close_outlined, size: 16.0),
|
||||
|
|
@ -464,31 +469,72 @@ class ActivitySuggestionDialogState extends State<ActivitySuggestionDialog> {
|
|||
_setEditing(false);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
_updateTextFields();
|
||||
_launch();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.zero,
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
if (_isEditing)
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
await _updateTextFields();
|
||||
_setEditing(false);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.zero,
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
),
|
||||
child: Text(
|
||||
L10n.of(context).save,
|
||||
style: theme.textTheme.bodyLarge
|
||||
?.copyWith(color: theme.colorScheme.onPrimary),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!_isEditing)
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
final resp = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
if (widget.launch != null) {
|
||||
return widget.launch?.call(
|
||||
widget.activity,
|
||||
_avatar,
|
||||
_filename,
|
||||
);
|
||||
}
|
||||
return _launchActivity();
|
||||
},
|
||||
);
|
||||
|
||||
if (resp.isError) return;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: Size.zero,
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
),
|
||||
child: Text(
|
||||
widget.buttonText,
|
||||
style: theme.textTheme.bodyLarge
|
||||
?.copyWith(color: theme.colorScheme.onPrimary),
|
||||
),
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
),
|
||||
child: Text(
|
||||
L10n.of(context).inviteAndLaunch,
|
||||
style: theme.textTheme.bodyLarge
|
||||
?.copyWith(color: theme.colorScheme.onPrimary),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!_isEditing)
|
||||
IconButton.filled(
|
||||
style: IconButton.styleFrom(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
|
||||
|
|
@ -18,11 +21,17 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
|
||||
class ActivitySuggestionsArea extends StatefulWidget {
|
||||
final Axis? scrollDirection;
|
||||
final bool includeCustomCards;
|
||||
final bool showCreateChatCard;
|
||||
final bool showMakeActivityCard;
|
||||
|
||||
final Room? room;
|
||||
|
||||
const ActivitySuggestionsArea({
|
||||
super.key,
|
||||
this.scrollDirection,
|
||||
this.includeCustomCards = true,
|
||||
this.showCreateChatCard = true,
|
||||
this.showMakeActivityCard = true,
|
||||
this.room,
|
||||
});
|
||||
@override
|
||||
ActivitySuggestionsAreaState createState() => ActivitySuggestionsAreaState();
|
||||
|
|
@ -80,6 +89,8 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
|
|||
builder: (context) {
|
||||
return ActivitySuggestionDialog(
|
||||
activity: activity,
|
||||
buttonText: L10n.of(context).inviteAndLaunch,
|
||||
room: widget.room,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -95,19 +106,22 @@ class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
|
|||
.cast<Widget>()
|
||||
.toList();
|
||||
|
||||
if (widget.includeCustomCards) {
|
||||
if (widget.showMakeActivityCard) {
|
||||
cards.insert(
|
||||
0,
|
||||
CreateChatCard(
|
||||
MakeActivityCard(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
padding: cardPadding,
|
||||
roomID: widget.room?.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.showCreateChatCard) {
|
||||
cards.insert(
|
||||
1,
|
||||
MakeActivityCard(
|
||||
0,
|
||||
CreateChatCard(
|
||||
width: cardWidth,
|
||||
height: cardHeight,
|
||||
padding: cardPadding,
|
||||
|
|
|
|||
|
|
@ -12,11 +12,13 @@ class MakeActivityCard extends StatelessWidget {
|
|||
final double width;
|
||||
final double height;
|
||||
final double padding;
|
||||
final String? roomID;
|
||||
|
||||
const MakeActivityCard({
|
||||
required this.width,
|
||||
required this.height,
|
||||
required this.padding,
|
||||
this.roomID,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -26,7 +28,11 @@ class MakeActivityCard extends StatelessWidget {
|
|||
return Padding(
|
||||
padding: EdgeInsets.all(padding),
|
||||
child: PressableButton(
|
||||
onPressed: () => context.go('/rooms/planner'),
|
||||
onPressed: () {
|
||||
roomID == null
|
||||
? context.go('/rooms/planner')
|
||||
: context.go('/rooms/${roomID!}/planner/generator');
|
||||
},
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
color: theme.colorScheme.primary,
|
||||
child: Container(
|
||||
|
|
@ -55,7 +61,7 @@ class MakeActivityCard extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
L10n.of(context).makeYourOwn,
|
||||
L10n.of(context).makeYourOwnActivity,
|
||||
style: theme.textTheme.bodyLarge
|
||||
?.copyWith(color: theme.colorScheme.secondary),
|
||||
textAlign: TextAlign.center,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class MaxWidthBody extends StatelessWidget {
|
|||
final EdgeInsets? innerPadding;
|
||||
// #Pangea
|
||||
final bool showBorder;
|
||||
final EdgeInsets? padding;
|
||||
// Pangea#
|
||||
|
||||
const MaxWidthBody({
|
||||
|
|
@ -19,6 +20,7 @@ class MaxWidthBody extends StatelessWidget {
|
|||
this.innerPadding,
|
||||
// #Pangea
|
||||
this.showBorder = true,
|
||||
this.padding,
|
||||
// Pangea#
|
||||
super.key,
|
||||
});
|
||||
|
|
@ -34,7 +36,10 @@ class MaxWidthBody extends StatelessWidget {
|
|||
? child
|
||||
: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
padding: const EdgeInsets.all(32),
|
||||
// #Pangea
|
||||
// padding: const EdgeInsets.all(32),
|
||||
padding: padding ?? const EdgeInsets.all(32),
|
||||
// Pangea#
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: FluffyThemes.columnWidth * 1.5,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue