feat: getting started page

pull/2245/head
ggurdin 5 months ago
parent 4fccaa92f2
commit f3922bece9
No known key found for this signature in database
GPG Key ID: A01CB41737CBB478

@ -4998,5 +4998,15 @@
"canBeFoundViaKnock": "\u2022 request to join and admin approval",
"anyoneCanJoin": "Anyone can join! However, admin can kick and ban whoever misbehaves. Those who are banned may not return!",
"createYourSpace": "Create your space",
"sendActivities": "Send activities"
"sendActivities": "Send activities",
"getStarted": "Get Started",
"getStartedBotChatDesc": "Chatting with AI is a great place to start and Pangea reading, writing, listening and speaking tools make it easy!",
"getStartedCommunitiesDesc": "Learning with a community is where Pangea Chat shines!\nYou can join your class, find a school, or even make your own!",
"getStartedFriendsDesc": "Do you have a friend that wants to learn with you?",
"getStartedBotChatComplete": "Well-done! You're chatting with the bot!",
"getStartedCommunitiesComplete": "Great, you have joined a space!",
"getStartedComplete": "You've completed this section!\nKeep exploring our amazing features by chatting with friends!",
"getStartedFriendsComplete": "Woohoo! You've got friends! 😉",
"getStartedBotChatButton": "Start chatting!",
"getStartedFriendsButton": "Invite a friend"
}

@ -40,6 +40,7 @@ import 'package:fluffychat/pangea/login/pages/login_or_signup_view.dart';
import 'package:fluffychat/pangea/login/pages/signup.dart';
import 'package:fluffychat/pangea/login/pages/space_code_onboarding.dart';
import 'package:fluffychat/pangea/login/pages/user_settings.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
import 'package:fluffychat/pangea/spaces/utils/join_with_alias.dart';
import 'package:fluffychat/pangea/spaces/utils/join_with_link.dart';
@ -238,7 +239,7 @@ abstract class AppRoutes {
FluffyThemes.isColumnMode(context)
// #Pangea
// ? const EmptyPage()
? const SuggestionsPage()
? const Onboarding()
// Pangea#
: ChatList(
activeChat: state.pathParameters['roomid'],

@ -11,6 +11,7 @@ import 'package:fluffychat/pages/chat_list/dummy_chat_list_item.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pages/chat_list/space_view.dart';
import 'package:fluffychat/pangea/chat_list/widgets/pangea_chat_list_header.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/user_dialog.dart';
@ -287,6 +288,16 @@ class ChatListViewBody extends StatelessWidget {
);
},
),
// #Pangea
const SliverPadding(padding: EdgeInsets.all(12.0)),
if (!FluffyThemes.isColumnMode(context))
SliverList.builder(
itemCount: 1,
itemBuilder: (context, _) {
return const Onboarding();
},
),
// Pangea#
],
),
);

@ -7,6 +7,8 @@ import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_steps_enum.dart';
import 'package:fluffychat/widgets/navigation_rail.dart';
class ChatListView extends StatelessWidget {
@ -59,9 +61,14 @@ class ChatListView extends StatelessWidget {
// #Pangea
// body: ChatListViewBody(controller),
body: ChatListViewBodyWrapper(controller: controller),
// Pangea#
// floatingActionButton: !controller.isSearchMode &&
// controller.activeSpaceId == null
floatingActionButton: !controller.isSearchMode &&
controller.activeSpaceId == null
controller.activeSpaceId == null &&
OnboardingController.complete(
OnboardingStepsEnum.chatWithBot,
)
// Pangea#
? FloatingActionButton.extended(
onPressed: () => context.go('/rooms/newprivatechat'),
icon: const Icon(Icons.add_outlined),

@ -116,8 +116,12 @@ class NaviRailItem extends StatelessWidget {
: UnreadRoomsBadge(
filter: unreadBadgeFilter,
badgePosition: BadgePosition.topEnd(
top: -12,
end: -8,
// #Pangea
// top: -12,
// end: -8,
top: -20,
end: -16,
// Pangea#
),
child: icon,
),

@ -17,6 +17,7 @@ import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart';
@ -952,6 +953,16 @@ class _SpaceViewState extends State<SpaceView> {
);
},
),
// #Pangea
const SliverPadding(padding: EdgeInsets.all(12.0)),
if (!FluffyThemes.isColumnMode(context))
SliverList.builder(
itemCount: 1,
itemBuilder: (context, _) {
return const Onboarding();
},
),
// Pangea#
const SliverPadding(padding: EdgeInsets.only(top: 32)),
],
);

@ -2,8 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_steps_enum.dart';
class PangeaChatListHeader extends StatelessWidget
implements PreferredSizeWidget {
@ -33,43 +36,51 @@ class PangeaChatListHeader extends StatelessWidget
child: Column(
children: [
const LearningProgressIndicators(),
TextField(
controller: controller.searchController,
focusNode: controller.searchFocusNode,
textInputAction: TextInputAction.search,
onChanged: (text) => controller.onSearchEnter(
text,
globalSearch: globalSearch,
),
decoration: InputDecoration(
filled: true,
fillColor: theme.colorScheme.secondaryContainer,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(99),
),
contentPadding: EdgeInsets.zero,
hintText: L10n.of(context).search,
hintStyle: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
prefixIcon: controller.isSearchMode
? IconButton(
tooltip: L10n.of(context).cancel,
icon: const Icon(Icons.close_outlined),
onPressed: controller.cancelSearch,
color: theme.colorScheme.onPrimaryContainer,
)
: IconButton(
onPressed: controller.startSearch,
icon: Icon(
Icons.search_outlined,
AnimatedSize(
duration: FluffyThemes.animationDuration,
child: OnboardingController.complete(
OnboardingStepsEnum.joinSpace,
)
? TextField(
controller: controller.searchController,
focusNode: controller.searchFocusNode,
textInputAction: TextInputAction.search,
onChanged: (text) => controller.onSearchEnter(
text,
globalSearch: globalSearch,
),
decoration: InputDecoration(
filled: true,
fillColor: theme.colorScheme.secondaryContainer,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(99),
),
contentPadding: EdgeInsets.zero,
hintText: L10n.of(context).search,
hintStyle: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
prefixIcon: controller.isSearchMode
? IconButton(
tooltip: L10n.of(context).cancel,
icon: const Icon(Icons.close_outlined),
onPressed: controller.cancelSearch,
color: theme.colorScheme.onPrimaryContainer,
)
: IconButton(
onPressed: controller.startSearch,
icon: Icon(
Icons.search_outlined,
color:
theme.colorScheme.onPrimaryContainer,
),
),
),
),
)
: const SizedBox.shrink(),
),
],
),

@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:developer';
import 'dart:math';
import 'package:flutter/foundation.dart';
@ -10,13 +9,8 @@ import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/chat_settings/constants/bot_mode.dart';
import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart';
import 'package:fluffychat/pangea/choreographer/controllers/contextual_definition_controller.dart';
import 'package:fluffychat/pangea/choreographer/controllers/word_net_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/events/controllers/message_data_controller.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
@ -81,10 +75,7 @@ class PangeaController {
putAnalytics.initialize();
getAnalytics.initialize();
subscriptionController.initialize();
startChatWithBotIfNotPresent();
setPangeaPushRules();
// joinSupportSpace();
}
/// Initialize controllers
@ -203,158 +194,6 @@ class PangeaController {
await getAnalytics.initialize();
}
void startChatWithBotIfNotPresent() {
Future.delayed(const Duration(milliseconds: 10000), () async {
// check if user is logged in
if (!matrixState.client.isLogged() ||
matrixState.client.userID == null ||
matrixState.client.userID == BotName.byEnvironment) {
return;
}
final List<Room> botDMs = [];
for (final room in matrixState.client.rooms) {
if (await room.isBotDM) {
botDMs.add(room);
}
}
if (botDMs.isEmpty) {
try {
// Copied from client.dart.startDirectChat
final directChatRoomId =
matrixState.client.getDirectChatFromUserId(BotName.byEnvironment);
if (directChatRoomId != null) {
final room = matrixState.client.getRoomById(directChatRoomId);
if (room != null) {
if (room.membership == Membership.join) {
return null;
} else if (room.membership == Membership.invite) {
// we might already have an invite into a DM room. If that is the case, we should try to join. If the room is
// unjoinable, that will automatically leave the room, so in that case we need to continue creating a new
// room. (This implicitly also prevents the room from being returned as a DM room by getDirectChatFromUserId,
// because it only returns joined or invited rooms atm.)
await room.join();
if (room.membership != Membership.leave) {
if (room.membership != Membership.join) {
// Wait for room actually appears in sync with the right membership
await matrixState.client
.waitForRoomInSync(directChatRoomId, join: true);
}
return null;
}
}
}
}
// enableEncryption ??=
// encryptionEnabled && await userOwnsEncryptionKeys(mxid);
// if (enableEncryption) {
// initialState ??= [];
// if (!initialState.any((s) => s.type == EventTypes.Encryption)) {
// initialState.add(
// StateEvent(
// content: {
// 'algorithm': supportedGroupEncryptionAlgorithms.first,
// },
// type: EventTypes.Encryption,
// ),
// );
// }
// }
// Start a new direct chat
final roomId = await matrixState.client.createRoom(
invite: [], // intentionally not invite bot yet
isDirect: true,
preset: CreateRoomPreset.trustedPrivateChat,
initialState: [
BotOptionsModel(mode: BotMode.directChat).toStateEvent,
RoomDefaults.defaultPowerLevels(
matrixState.client.userID!,
),
],
);
Room? room = matrixState.client.getRoomById(roomId);
if (room == null || room.membership != Membership.join) {
// Wait for room actually appears in sync
await matrixState.client.waitForRoomInSync(roomId, join: true);
room = matrixState.client.getRoomById(roomId);
if (room == null) {
ErrorHandler.logError(
e: "Bot chat null after waiting for room in sync",
data: {
"roomId": roomId,
},
);
return null;
}
}
final botOptions = room.getState(PangeaEventTypes.botOptions);
if (botOptions == null) {
await matrixState.client.setRoomStateWithKey(
roomId,
PangeaEventTypes.botOptions,
"",
BotOptionsModel(mode: BotMode.directChat).toJson(),
);
await matrixState.client
.getRoomStateWithKey(roomId, PangeaEventTypes.botOptions, "");
}
// invite bot to direct chat
await matrixState.client.setRoomStateWithKey(
roomId, EventTypes.RoomMember, BotName.byEnvironment, {
"membership": Membership.invite.name,
"is_direct": true,
});
await room.addToDirectChat(BotName.byEnvironment);
return null;
} catch (err, stack) {
debugger(when: kDebugMode);
ErrorHandler.logError(
e: err,
s: stack,
data: {
"directChatRoomId": matrixState.client
.getDirectChatFromUserId(BotName.byEnvironment),
},
);
}
}
final Room botDMWithLatestActivity = botDMs.reduce((a, b) {
if (a.timeline == null ||
b.timeline == null ||
a.timeline!.events.isEmpty ||
b.timeline!.events.isEmpty) {
return a;
}
final aLastEvent = a.timeline!.events.last;
final bLastEvent = b.timeline!.events.last;
return aLastEvent.originServerTs.isAfter(bLastEvent.originServerTs)
? a
: b;
});
for (final room in botDMs) {
if (room.id != botDMWithLatestActivity.id) {
await room.leave();
continue;
}
}
final participants = await botDMWithLatestActivity.requestParticipants();
final joinedParticipants =
participants.where((e) => e.membership == Membership.join).toList();
if (joinedParticipants.length < 2) {
await botDMWithLatestActivity.invite(BotName.byEnvironment);
}
});
}
void _subscribeToStreams() {
matrixState.client.onLoginStateChanged.stream
.listen(_handleLoginStateChange);

@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/chat_settings/constants/bot_mode.dart';
import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_steps_enum.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_view.dart';
import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
class Onboarding extends StatefulWidget {
const Onboarding({super.key});
@override
OnboardingController createState() => OnboardingController();
}
class OnboardingController extends State<Onboarding> {
static final GetStorage _onboardingStorage = GetStorage('onboarding_storage');
static bool get isClosed => _onboardingStorage.read('closed') ?? false;
static bool get isComplete => OnboardingStepsEnum.values.every(
(step) => complete(step),
);
static bool complete(OnboardingStepsEnum step) {
switch (step) {
case OnboardingStepsEnum.chatWithBot:
return hasBotDM;
case OnboardingStepsEnum.joinSpace:
return MatrixState.pangeaController.matrixState.client.rooms.any(
(r) => r.isSpace,
);
case OnboardingStepsEnum.inviteFriends:
return hasInvitedFriends;
}
}
static bool get hasInvitedFriends =>
_onboardingStorage.read('invite_friends') ?? false;
static bool get hasBotDM =>
MatrixState.pangeaController.matrixState.client.rooms.any((room) {
if (room.isDirectChat &&
room.directChatMatrixID == BotName.byEnvironment) {
return true;
}
if (room.botOptions?.mode == BotMode.directChat) {
return true;
}
return false;
});
Future<void> closeCompletedMessage() async {
await _onboardingStorage.write('closed', true);
if (mounted) setState(() {});
}
Future<void> inviteFriends() async {
FluffyShare.shareInviteLink(context);
await _onboardingStorage.write('invite_friends', true);
if (mounted) setState(() {});
}
Future<void> startChatWithBot() async {
final resp = await showFutureLoadingDialog<String>(
context: context,
future: () => Matrix.of(context).client.createRoom(
invite: [BotName.byEnvironment],
isDirect: true,
preset: CreateRoomPreset.trustedPrivateChat,
initialState: [
BotOptionsModel(mode: BotMode.directChat).toStateEvent,
RoomDefaults.defaultPowerLevels(
Matrix.of(context).client.userID!,
),
],
),
);
if (resp.isError) return;
context.go("/rooms/${resp.result}");
}
void joinCommunities() {
context.go('/rooms/communities');
}
Future<void> onPressed(OnboardingStepsEnum step) async {
switch (step) {
case OnboardingStepsEnum.chatWithBot:
return startChatWithBot();
case OnboardingStepsEnum.joinSpace:
return joinCommunities();
case OnboardingStepsEnum.inviteFriends:
return inviteFriends();
}
}
@override
Widget build(BuildContext context) => OnboardingView(controller: this);
}

@ -0,0 +1,71 @@
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/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_constants.dart';
class OnboardingComplete extends StatelessWidget {
final OnboardingController controller;
const OnboardingComplete({super.key, required this.controller});
@override
Widget build(BuildContext context) {
return FluffyThemes.isColumnMode(context)
? Text(
L10n.of(context).getStartedComplete,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 32.0,
),
)
: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.onSurface.withAlpha(20),
borderRadius: BorderRadius.circular(
10.0,
),
),
margin: const EdgeInsets.all(12.0),
padding: const EdgeInsets.fromLTRB(
48.0,
8.0,
48.0,
0.0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 24.0,
children: [
Text(
L10n.of(context).getStartedComplete,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14.0,
),
),
CachedNetworkImage(
imageUrl:
"${AppConfig.assetsBaseURL}/${OnboardingConstants.onboardingImageFileName}",
fit: BoxFit.cover,
),
],
),
),
Positioned(
right: 16.0,
top: 16.0,
child: IconButton(
icon: const Icon(Icons.close),
onPressed: controller.closeCompletedMessage,
),
),
],
);
}
}

@ -0,0 +1,3 @@
class OnboardingConstants {
static String onboardingImageFileName = "Getting+Started.png";
}

@ -0,0 +1,104 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_steps_enum.dart';
class OnboardingStep extends StatelessWidget {
final OnboardingStepsEnum step;
final bool isComplete;
final VoidCallback onPressed;
const OnboardingStep({
super.key,
required this.step,
this.isComplete = false,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
final isColumnMode = FluffyThemes.isColumnMode(context);
return Container(
padding: EdgeInsets.symmetric(
horizontal: isColumnMode ? 20.0 : 8.0,
vertical: isColumnMode ? 24.0 : 8.0,
),
margin: isColumnMode
? const EdgeInsets.only(
bottom: 10.0,
)
: const EdgeInsets.all(0.0),
decoration: isColumnMode && isComplete
? ShapeDecoration(
shape: RoundedRectangleBorder(
side: const BorderSide(
width: 1,
color: AppConfig.success,
),
borderRadius: BorderRadius.circular(
24,
),
),
)
: null,
child: Row(
spacing: isColumnMode ? 24.0 : 12.0,
children: [
Icon(
Icons.task_alt,
size: isColumnMode ? 30.0 : 18.0,
color: isComplete
? AppConfig.success
: Theme.of(context).colorScheme.primary,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: isColumnMode ? 16.0 : 8.0,
children: [
Text(
isComplete
? step.completeMessage(
L10n.of(context),
)
: step.description(
L10n.of(context),
),
style: TextStyle(
fontSize: isColumnMode ? 20.0 : 12.0,
),
),
if (!isComplete)
ElevatedButton(
onPressed: onPressed,
child: Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.center,
children: [
step.icon(18.0),
Text(
step.buttonText(
L10n.of(
context,
),
),
style: const TextStyle(
fontSize: 14.0,
),
),
],
),
),
],
),
),
],
),
);
}
}

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/bot/widgets/bot_face_svg.dart';
enum OnboardingStepsEnum {
chatWithBot,
joinSpace,
inviteFriends;
String description(L10n l10n) {
switch (this) {
case OnboardingStepsEnum.chatWithBot:
return l10n.getStartedBotChatDesc;
case OnboardingStepsEnum.joinSpace:
return l10n.getStartedCommunitiesDesc;
case OnboardingStepsEnum.inviteFriends:
return l10n.getStartedFriendsDesc;
}
}
String completeMessage(L10n l10n) {
switch (this) {
case OnboardingStepsEnum.chatWithBot:
return l10n.getStartedBotChatComplete;
case OnboardingStepsEnum.joinSpace:
return l10n.getStartedCommunitiesComplete;
case OnboardingStepsEnum.inviteFriends:
return l10n.getStartedFriendsComplete;
}
}
Widget icon(double size) {
switch (this) {
case OnboardingStepsEnum.chatWithBot:
return BotFace(expression: BotExpression.gold, width: size);
case OnboardingStepsEnum.joinSpace:
return Icon(Icons.groups_outlined, size: size);
case OnboardingStepsEnum.inviteFriends:
return Icon(Icons.share, size: size);
}
}
String buttonText(L10n l10n) {
switch (this) {
case OnboardingStepsEnum.chatWithBot:
return l10n.getStartedBotChatButton;
case OnboardingStepsEnum.joinSpace:
return l10n.findYourPeople;
case OnboardingStepsEnum.inviteFriends:
return l10n.getStartedFriendsButton;
}
}
}

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/onboarding/onboarding.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_complete.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_constants.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_step.dart';
import 'package:fluffychat/pangea/onboarding/onboarding_steps_enum.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
class OnboardingView extends StatelessWidget {
final OnboardingController controller;
const OnboardingView({
super.key,
required this.controller,
});
@override
Widget build(BuildContext context) {
final client = Matrix.of(context).client;
final isColumnMode = FluffyThemes.isColumnMode(context);
final screenheight = MediaQuery.of(context).size.height;
return Material(
child: StreamBuilder(
key: ValueKey(
client.userID.toString(),
),
stream: client.onSync.stream
.where((s) => s.hasRoomUpdate)
.rateLimit(const Duration(seconds: 1)),
builder: (context, _) {
return Stack(
alignment: Alignment.topCenter,
children: [
if (isColumnMode && !OnboardingController.isClosed)
Positioned(
bottom: 0.0,
child: AnimatedOpacity(
duration: FluffyThemes.animationDuration,
opacity: OnboardingController.isComplete ? 1.0 : 0.3,
child: CachedNetworkImage(
imageUrl:
"${AppConfig.assetsBaseURL}/${OnboardingConstants.onboardingImageFileName}",
fit: BoxFit.cover,
),
),
),
AnimatedContainer(
duration: FluffyThemes.animationDuration,
height: OnboardingController.isClosed ? 0 : screenheight,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 12.0,
horizontal: isColumnMode ? 20.0 : 8.0,
),
child: MaxWidthBody(
showBorder: false,
maxWidth: 850.0,
child: Column(
children: [
Text(
L10n.of(context).getStarted,
style: TextStyle(
fontSize: isColumnMode ? 32.0 : 16.0,
height: isColumnMode ? 1.2 : 1.5,
),
),
Padding(
padding: EdgeInsets.all(
isColumnMode ? 40.0 : 12.0,
),
child: Row(
spacing: 8.0,
mainAxisSize: MainAxisSize.min,
children: OnboardingStepsEnum.values.map((step) {
final complete =
OnboardingController.complete(step);
return CircleAvatar(
radius: 6.0,
backgroundColor: complete
? AppConfig.success
: Theme.of(context).colorScheme.primary,
child: CircleAvatar(
radius: 3.0,
backgroundColor:
Theme.of(context).colorScheme.surface,
),
);
}).toList(),
),
),
OnboardingController.isComplete
? OnboardingComplete(
controller: controller,
)
: Column(
spacing: 12.0,
children: [
for (final step in OnboardingStepsEnum.values)
OnboardingStep(
step: step,
isComplete:
OnboardingController.complete(step),
onPressed: () =>
controller.onPressed(step),
),
],
),
],
),
),
),
),
],
);
},
),
);
}
}

@ -88,18 +88,10 @@ class SpacesNavigationRail extends StatelessWidget {
// #Pangea
if (i == 0) {
return NaviRailItem(
isSelected: isColumnMode
? activeSpaceId == null &&
!isSettings &&
!isCommunities
: isHomepage,
isSelected: isHomepage,
onTap: () {
if (isColumnMode) {
onGoToChats();
} else {
clearActiveSpace?.call();
context.go("/rooms/homepage");
}
clearActiveSpace?.call();
context.go("/rooms/homepage");
},
backgroundColor: Colors.transparent,
icon: FutureBuilder<Profile>(
@ -127,32 +119,30 @@ class SpacesNavigationRail extends StatelessWidget {
i--;
// Pangea#
if (i == 0) {
return isColumnMode
? const SizedBox()
: NaviRailItem(
// #Pangea
// isSelected: activeSpaceId == null && !isSettings,
isSelected: activeSpaceId == null &&
!isSettings &&
!isHomepage &&
!isCommunities,
// Pangea#
onTap: onGoToChats,
// #Pangea
// icon: const Padding(
// padding: EdgeInsets.all(10.0),
// child: Icon(Icons.forum_outlined),
// ),
// selectedIcon: const Padding(
// padding: EdgeInsets.all(10.0),
// child: Icon(Icons.forum),
// ),
icon: const Icon(Icons.forum_outlined),
selectedIcon: const Icon(Icons.forum),
// Pangea#
toolTip: L10n.of(context).chats,
unreadBadgeFilter: (room) => true,
);
return NaviRailItem(
// #Pangea
// isSelected: activeSpaceId == null && !isSettings,
isSelected: activeSpaceId == null &&
!isSettings &&
!isHomepage &&
!isCommunities,
// Pangea#
onTap: onGoToChats,
// #Pangea
// icon: const Padding(
// padding: EdgeInsets.all(10.0),
// child: Icon(Icons.forum_outlined),
// ),
// selectedIcon: const Padding(
// padding: EdgeInsets.all(10.0),
// child: Icon(Icons.forum),
// ),
icon: const Icon(Icons.forum_outlined),
selectedIcon: const Icon(Icons.forum),
// Pangea#
toolTip: L10n.of(context).chats,
unreadBadgeFilter: (room) => true,
);
}
i--;
if (i == rootSpaces.length) {

Loading…
Cancel
Save