diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a4058486b..211d34df2 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -108,6 +108,19 @@
+
+
+
+
+
+
+
+
+
+
+
????
CFBundleURLTypes
+
+ CFBundleURLSchemes
+
+ pangea
+
+ CFBundleURLName
+ com.talktolearn.chat
+
CFBundleTypeRole
Editor
@@ -113,5 +121,7 @@
io.flutter.embedded_views_preview
+ FlutterDeepLinkingEnabled
+
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
index 2b2a88dd1..91e1a0719 100644
--- a/ios/Runner/Runner.entitlements
+++ b/ios/Runner/Runner.entitlements
@@ -1,18 +1,16 @@
-
- aps-environment
- development
- com.apple.developer.associated-domains
-
- applinks:example.com
-
- com.apple.security.application-groups
-
-
- group.com.talktolearn.chat
-
-
-
-
\ No newline at end of file
+
+ aps-environment
+ development
+ com.apple.developer.associated-domains
+
+ applinks:app.pangea.chat
+
+ com.apple.security.application-groups
+
+ group.com.talktolearn.chat
+
+
+
diff --git a/lib/config/routes.dart b/lib/config/routes.dart
index e7fb1d376..d2a3efc5e 100644
--- a/lib/config/routes.dart
+++ b/lib/config/routes.dart
@@ -31,9 +31,9 @@ import 'package:fluffychat/pages/settings_security/settings_security.dart';
import 'package:fluffychat/pages/settings_style/settings_style.dart';
import 'package:fluffychat/pangea/activity_generator/activity_generator.dart';
import 'package:fluffychat/pangea/activity_planner/activity_planner_page.dart';
-import 'package:fluffychat/pangea/activity_suggestions/suggestions_page.dart';
+import 'package:fluffychat/pangea/analytics_page/analytics_page.dart';
+import 'package:fluffychat/pangea/common/widgets/pangea_side_view.dart';
import 'package:fluffychat/pangea/find_your_people/find_your_people.dart';
-import 'package:fluffychat/pangea/find_your_people/find_your_people_side_view.dart';
import 'package:fluffychat/pangea/guard/p_vguard.dart';
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
import 'package:fluffychat/pangea/login/pages/login_or_signup_view.dart';
@@ -196,7 +196,8 @@ abstract class AppRoutes {
// state.fullPath?.startsWith('/rooms/settings') == false
FluffyThemes.isColumnMode(context) &&
state.fullPath?.startsWith('/rooms/settings') == false &&
- state.fullPath?.startsWith('/rooms/communities') == false
+ state.fullPath?.startsWith('/rooms/communities') == false &&
+ state.fullPath?.startsWith('/rooms/analytics') == false
// Pangea#
? TwoColumnLayout(
mainView: ChatList(
@@ -309,7 +310,7 @@ abstract class AppRoutes {
state,
FluffyThemes.isColumnMode(context)
? TwoColumnLayout(
- mainView: const FindYourPeopleSideView(),
+ mainView: PangeaSideView(path: state.fullPath),
sideView: child,
dividerColor: Colors.transparent,
)
@@ -325,37 +326,14 @@ abstract class AppRoutes {
const FindYourPeople(),
),
),
- ],
- ),
- GoRoute(
- path: 'homepage',
- redirect: loggedOutRedirect,
- pageBuilder: (context, state) => defaultPageBuilder(
- context,
- state,
- const SuggestionsPage(),
- ),
- routes: [
- ...newRoomRoutes,
GoRoute(
- path: '/planner',
+ path: 'analytics',
+ redirect: loggedOutRedirect,
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
- const ActivityPlannerPage(),
+ const AnalyticsPage(),
),
- redirect: loggedOutRedirect,
- routes: [
- GoRoute(
- path: '/generator',
- redirect: loggedOutRedirect,
- pageBuilder: (context, state) => defaultPageBuilder(
- context,
- state,
- const ActivityGenerator(),
- ),
- ),
- ],
),
],
),
diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb
index 0ed36c50c..e3be07db2 100644
--- a/lib/l10n/intl_en.arb
+++ b/lib/l10n/intl_en.arb
@@ -4631,9 +4631,9 @@
"meaningSectionHeader": "Meaning:",
"formSectionHeader": "Forms used in chats:",
"noEmojiSelectedTooltip": "No emoji selected",
- "writingExercisesTooltip": "Writing practice",
- "listeningExercisesTooltip": "Listening practice",
- "readingExercisesTooltip": "Reading practice",
+ "writingExercisesTooltip": "Writing",
+ "listeningExercisesTooltip": "Listening",
+ "readingExercisesTooltip": "Reading",
"meaningNotFound": "Meaning could not be found.",
"formsNotFound": "Forms could not be found.",
"chooseBaseForm": "Choose the base form",
@@ -5002,6 +5002,7 @@
"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",
+ "youHaveLeveledUp": "You have leveled up!",
"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!",
@@ -5016,7 +5017,7 @@
"groupChat": "Group Chat",
"directMessage": "Direct Message",
"newDirectMessage": "New direct message",
- "speakingExercisesTooltip": "Speaking practice",
+ "speakingExercisesTooltip": "Speaking",
"noChatsFoundHereYet": "No chats found here yet",
"duration": "Duration",
"transcriptionFailed": "Failed to transcribe audio",
@@ -5032,4 +5033,4 @@
},
"failedToFetchTranscription": "Failed to fetch transcription",
"deleteEmptySpaceDesc": "The space will be deleted for all participants. This action cannot be undone."
-}
\ No newline at end of file
+}
diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart
index 3b2a0dedf..bc820b81a 100644
--- a/lib/pages/chat/chat.dart
+++ b/lib/pages/chat/chat.dart
@@ -33,7 +33,7 @@ import 'package:fluffychat/pages/chat_details/chat_details.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart';
-import 'package:fluffychat/pangea/analytics_misc/level_up.dart';
+import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_banner.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/utils/unlocked_morphs_snackbar.dart';
diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart
index a07aecc36..105b393c3 100644
--- a/lib/pages/chat/events/html_message.dart
+++ b/lib/pages/chat/events/html_message.dart
@@ -5,7 +5,6 @@ import 'package:fluffychat/pangea/common/utils/any_state_holder.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/message_token_text/message_token_button.dart';
-import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/utils/token_rendering_util.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
@@ -203,12 +202,14 @@ class HtmlMessage extends StatelessWidget {
}
}
+ int position = 0;
for (final PangeaToken token in tokens ?? []) {
final String tokenText = token.text.content;
final substringIndex = result.indexWhere(
(string) =>
string.contains(tokenText) &&
!(string.startsWith('<') && string.endsWith('>')),
+ position,
);
if (substringIndex == -1) continue;
@@ -228,9 +229,68 @@ class HtmlMessage extends StatelessWidget {
'$tokenText',
if (after.isNotEmpty) after,
]);
+
+ position = substringIndex;
}
- return result.join();
+ if (pangeaMessageEvent?.textDirection == TextDirection.rtl) {
+ for (int i = 0; i < result.length; i++) {
+ final tag = result[i];
+ if (blockHtmlTags.contains(tag.htmlTagName) ||
+ fullLineHtmlTag.contains(tag.htmlTagName)) {
+ if (i > 0 && result[i - 1] == ", ") {
+ result[i - 1] = "";
+ }
+ result[i] = ", ";
+ }
+ }
+ result.removeWhere((element) => element == "");
+ if (result[0] == ", ") result[0] = "";
+ if (result.last == ", ") result.last = "";
+ final inverted = _invertTags(result);
+ return inverted.join().trim();
+ }
+ return result.join().trim();
+ }
+
+ List _invertTags(List tags) {
+ final List<(String, int)> stack = [];
+ final List<(int, int)> invertedTags = [];
+ for (int i = 0; i < tags.length; i++) {
+ final tag = tags[i];
+ if (!tag.contains('<') || tag.contains("
+ element.$1.htmlTagName == tag.htmlTagName &&
+ !element.$1.contains(""),
+ );
+ }
+
+ if (match != -1) {
+ // If the tag is already in the stack, we remove it
+ final (matchTag, matchIndex) = stack.removeAt(match);
+ invertedTags.add((matchIndex, i));
+ } else {
+ // If the tag is not in the stack, we add it
+ stack.insert(0, (tag, i));
+ }
+ }
+
+ for (final (start, end) in invertedTags) {
+ final startTag = tags[start];
+ final endTag = tags[end];
+
+ tags[start] = endTag;
+ tags[end] = startTag;
+ }
+
+ final inverted = tags.reversed.toList();
+ return inverted;
}
// Pangea#
@@ -337,6 +397,9 @@ class HtmlMessage extends StatelessWidget {
);
return WidgetSpan(
+ alignment: readingAssistanceMode == ReadingAssistanceMode.practiceMode
+ ? PlaceholderAlignment.bottom
+ : PlaceholderAlignment.middle,
child: CompositedTransformTarget(
link: token != null && renderer.assignTokenKey
? MatrixState.pAnyState
@@ -364,18 +427,6 @@ class HtmlMessage extends StatelessWidget {
),
width: tokenWidth,
animateIn: isTransitionAnimation,
- practiceTargetForToken:
- overlayController?.toolbarMode.associatedActivityType !=
- null
- ? overlayController?.practiceSelection
- ?.activities(
- overlayController!
- .toolbarMode.associatedActivityType!,
- )
- .firstWhereOrNull(
- (a) => a.tokens.contains(token),
- )
- : null,
),
MouseRegion(
cursor: SystemMouseCursors.click,
@@ -385,6 +436,7 @@ class HtmlMessage extends StatelessWidget {
? () => onClick?.call(token)
: null,
child: RichText(
+ textDirection: pangeaMessageEvent?.textDirection,
text: TextSpan(
children: [
LinkifySpan(
@@ -1013,3 +1065,8 @@ extension on String {
extension on dom.Element {
dom.Element get rootElement => parent?.rootElement ?? this;
}
+
+extension on String {
+ String get htmlTagName =>
+ replaceAll('<', '').replaceAll('>', '').replaceAll('/', '').split(' ')[0];
+}
diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart
index 06509fae9..4929e27a9 100644
--- a/lib/pages/invitation_selection/invitation_selection.dart
+++ b/lib/pages/invitation_selection/invitation_selection.dart
@@ -35,35 +35,6 @@ class InvitationSelectionController extends State {
String? get roomId => widget.roomId;
// #Pangea
- final viewportKey = GlobalKey();
-
- final participantListItemHeight = 72.0;
- final goToChatButtonHeight = 50.0;
- final shareButtonsHeight = 150.0;
- final padding = 16.0 * 2;
- final fixedParticipantHeight = 72.0;
-
- double? viewportHeight;
- double get availableHeight =>
- (viewportHeight ?? 0) -
- goToChatButtonHeight -
- shareButtonsHeight -
- padding;
-
- bool showShareButtons(int numParticipants) =>
- (fixedParticipantHeight * numParticipants) < availableHeight;
-
- @override
- initState() {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- final context = viewportKey.currentContext;
- if (context == null) return;
- final renderBox = context.findRenderObject() as RenderBox;
- final size = renderBox.size;
- setState(() => viewportHeight = size.height);
- });
- super.initState();
- }
List? get participants {
final room = Matrix.of(context).client.getRoomById(roomId!);
diff --git a/lib/pages/invitation_selection/invitation_selection_view.dart b/lib/pages/invitation_selection/invitation_selection_view.dart
index 59c6f6ad0..2df3b6a56 100644
--- a/lib/pages/invitation_selection/invitation_selection_view.dart
+++ b/lib/pages/invitation_selection/invitation_selection_view.dart
@@ -8,12 +8,10 @@ import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/config/app_config.dart';
-import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/invitation_selection/invitation_selection.dart';
import 'package:fluffychat/pangea/analytics_misc/level_display_name.dart';
import 'package:fluffychat/pangea/chat_settings/constants/room_settings_constants.dart';
-import 'package:fluffychat/pangea/chat_settings/widgets/space_invite_buttons.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
@@ -107,165 +105,153 @@ class InvitationSelectionView extends StatelessWidget {
// #Pangea
withScrolling: false,
// Pangea#
- child: Stack(
- alignment: Alignment.bottomCenter,
+ child: Column(
children: [
Padding(
- padding: const EdgeInsets.all(16.0),
- child: SizedBox(
- width: 450,
- child: CachedNetworkImage(
- imageUrl:
- "${AppConfig.assetsBaseURL}/${RoomSettingsConstants.referFriendAsset}",
- errorWidget: (context, url, error) => const SizedBox(),
- placeholder: (context, url) => const Center(
- child: CircularProgressIndicator.adaptive(),
+ // #Pangea
+ // padding: const EdgeInsets.all(16.0),
+ padding: const EdgeInsets.only(
+ bottom: 16.0,
+ left: 16.0,
+ right: 16.0,
+ ),
+ // Pangea#
+ child: TextField(
+ textInputAction: TextInputAction.search,
+ decoration: InputDecoration(
+ filled: true,
+ fillColor: theme.colorScheme.secondaryContainer,
+ border: OutlineInputBorder(
+ borderSide: BorderSide.none,
+ borderRadius: BorderRadius.circular(99),
),
+ hintStyle: TextStyle(
+ color: theme.colorScheme.onPrimaryContainer,
+ fontWeight: FontWeight.normal,
+ ),
+ // #Pangea
+ hintText: L10n.of(context).inviteStudentByUserName,
+ // hintText: L10n.of(context).inviteContactToGroup(groupName),
+ // Pangea#
+ prefixIcon: controller.loading
+ ? const Padding(
+ padding: EdgeInsets.symmetric(
+ vertical: 10.0,
+ horizontal: 12,
+ ),
+ child: SizedBox.square(
+ dimension: 24,
+ child: CircularProgressIndicator.adaptive(
+ strokeWidth: 2,
+ ),
+ ),
+ )
+ : const Icon(Icons.search_outlined),
),
+ onChanged: controller.searchUserWithCoolDown,
),
),
- Column(
- children: [
- Padding(
- // #Pangea
- // padding: const EdgeInsets.all(16.0),
- padding: const EdgeInsets.only(
- bottom: 16.0,
- left: 16.0,
- right: 16.0,
- ),
- // Pangea#
- child: TextField(
- textInputAction: TextInputAction.search,
- decoration: InputDecoration(
- filled: true,
- fillColor: theme.colorScheme.secondaryContainer,
- border: OutlineInputBorder(
- borderSide: BorderSide.none,
- borderRadius: BorderRadius.circular(99),
- ),
- hintStyle: TextStyle(
- color: theme.colorScheme.onPrimaryContainer,
- fontWeight: FontWeight.normal,
- ),
- // #Pangea
- hintText: L10n.of(context).inviteStudentByUserName,
- // hintText: L10n.of(context).inviteContactToGroup(groupName),
- // Pangea#
- prefixIcon: controller.loading
- ? const Padding(
- padding: EdgeInsets.symmetric(
- vertical: 10.0,
- horizontal: 12,
- ),
- child: SizedBox.square(
- dimension: 24,
+ // #Pangea
+ // StreamBuilder