diff --git a/core/lib/utils/string_convert.dart b/core/lib/utils/string_convert.dart
index 51d9700b5..158c7d0fb 100644
--- a/core/lib/utils/string_convert.dart
+++ b/core/lib/utils/string_convert.dart
@@ -258,8 +258,8 @@ class StringConvert {
}
static String convertTextContentToHtmlContent(String textContent) {
- final htmlContent = textContent.replaceAll('\n', '
');
-
+ final escapedText = escapeTextContent(textContent);
+ final htmlContent = escapedText.replaceAll('\n', '
');
return '
$htmlContent
';
}
}
\ No newline at end of file
diff --git a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart
index 37d764d2c..b70c718e0 100644
--- a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart
+++ b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart
@@ -23,7 +23,10 @@ class RichTextMobileTabletController extends GetxController {
try {
await htmlEditorApi?.webViewController.evaluateJavascript(source: '''
(() => {
- document.getElementById('editor').focus();
+ const editor = document.getElementById('editor');
+ if (editor && typeof editor.focus === 'function') {
+ editor.focus();
+ }
})();''');
} catch (e) {
logWarning('RichTextMobileTabletController::focus:Exception: $e');
diff --git a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
index 2c817cf01..c4c2377cc 100644
--- a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
+++ b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
@@ -100,17 +100,17 @@ extension HandleAiScribeInComposerExtension on ComposerController {
HtmlUtils.saveSelection.name,
hasReturnValue: true,
);
- return result;
+ return result?.toString() ?? '';
} else {
final result = await richTextMobileTabletController?.htmlEditorApi?.webViewController
.evaluateJavascript(
source: HtmlUtils.saveSelection.script,
);
- return result;
+ return result?.toString() ?? '';
}
} catch (e) {
logWarning('$runtimeType::saveSelection:Exception = $e');
- return "";
+ return '';
}
}
@@ -121,17 +121,17 @@ extension HandleAiScribeInComposerExtension on ComposerController {
HtmlUtils.restoreSelection.name,
hasReturnValue: true,
);
- return result;
+ return result?.toString() ?? '';
} else {
final result = await richTextMobileTabletController?.htmlEditorApi?.webViewController
.evaluateJavascript(
source: HtmlUtils.restoreSelection.script,
);
- return result;
+ return result?.toString() ?? '';
}
} catch (e) {
logWarning('$runtimeType::restoreSelection:Exception = $e');
- return "";
+ return '';
}
}
@@ -142,17 +142,17 @@ extension HandleAiScribeInComposerExtension on ComposerController {
HtmlUtils.getSavedSelection.name,
hasReturnValue: true,
);
- return result;
+ return result?.toString() ?? '';
} else {
final result = await richTextMobileTabletController?.htmlEditorApi?.webViewController
.evaluateJavascript(
source: HtmlUtils.getSavedSelection.script,
);
- return result;
+ return result?.toString() ?? '';
}
} catch (e) {
logWarning('$runtimeType::getSavedSelection:Exception = $e');
- return "";
+ return '';
}
}
@@ -176,12 +176,16 @@ extension HandleAiScribeInComposerExtension on ComposerController {
}
Future unfocusEditor() async {
- final editorApi = richTextMobileTabletController?.htmlEditorApi;
- if (PlatformInfo.isIOS) {
- await editorApi?.unfocus();
- } else if (PlatformInfo.isAndroid) {
- await editorApi?.hideKeyboard();
- await editorApi?.unfocus();
+ try {
+ final editorApi = richTextMobileTabletController?.htmlEditorApi;
+ if (PlatformInfo.isIOS) {
+ await editorApi?.unfocus();
+ } else if (PlatformInfo.isAndroid) {
+ await editorApi?.hideKeyboard();
+ await editorApi?.unfocus();
+ }
+ } catch (e) {
+ logWarning('$runtimeType::unfocusEditor:Exception = $e');
}
}
@@ -239,7 +243,8 @@ extension HandleAiScribeInComposerExtension on ComposerController {
clearFocusRecipients();
clearFocusSubject();
- if (isScribeMobile) {
+ final scribeMobile = isScribeMobile;
+ if (scribeMobile) {
await saveAndUnfocusForModal();
}
@@ -254,7 +259,7 @@ extension HandleAiScribeInComposerExtension on ComposerController {
preferredPlacement: ModalPlacement.top,
crossAxisAlignment: ModalCrossAxisAlignment.start,
onSelectAiScribeSuggestionAction: handleAiScribeSuggestionAction,
- isScribeMobile: isScribeMobile,
+ isScribeMobile: scribeMobile,
);
}
diff --git a/lib/features/mailbox_dashboard/domain/state/get_linagora_ecosystem_state.dart b/lib/features/mailbox_dashboard/domain/state/get_linagora_ecosystem_state.dart
index eb5a039f5..27736c1a0 100644
--- a/lib/features/mailbox_dashboard/domain/state/get_linagora_ecosystem_state.dart
+++ b/lib/features/mailbox_dashboard/domain/state/get_linagora_ecosystem_state.dart
@@ -12,7 +12,7 @@ class GetLinagoraEcosystemSuccess extends Success {
}
class GetLinagoraEcosystemFailure extends Failure {
- final dynamic exception;
+ final Object exception;
GetLinagoraEcosystemFailure(this.exception);
diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart
index e0d83c39e..5608f3ab0 100644
--- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart
+++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart
@@ -3470,6 +3470,7 @@ class MailboxDashBoardController extends ReloadableController
twakeAppManager.setHasComposer(false);
paywallController?.onClose();
paywallController = null;
+ cachedLinagoraEcosystem = null;
_disposeWorkerObxVariables();
super.onClose();
}
diff --git a/lib/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart
index 4221c9f63..16e055966 100644
--- a/lib/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart
+++ b/lib/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart
@@ -20,10 +20,10 @@ extension SetupScribePromptUrlExtension on MailboxDashBoardController {
if (baseUrl != null && baseUrl.isNotEmpty) {
consumeState(interactor.execute(baseUrl));
} else {
- logError('SetupScribePromptUrlExtension::loadLinagoraEcosystem: jmapUrl is null or empty');
+ logWarning('SetupScribePromptUrlExtension::loadLinagoraEcosystem: jmapUrl is null or empty');
}
} else {
- logError('SetupScribePromptUrlExtension::loadLinagoraEcosystem: GetLinagoraEcosystemInteractor not found');
+ logWarning('SetupScribePromptUrlExtension::loadLinagoraEcosystem: GetLinagoraEcosystemInteractor not found');
}
}
@@ -33,7 +33,8 @@ extension SetupScribePromptUrlExtension on MailboxDashBoardController {
}
void handleGetLinagoraEcosystemFailure(GetLinagoraEcosystemFailure failure) {
- logError('SetupScribePromptUrlExtension::handleGetLinagoraEcosystemFailure: GetScribePromptUrl failed - ${failure.exception}');
+ logWarning('SetupScribePromptUrlExtension::handleGetLinagoraEcosystemFailure: GetScribePromptUrl failed - ${failure.exception}');
+ cachedLinagoraEcosystem = null;
_applyScribePromptUrl(null);
}
diff --git a/model/lib/extensions/session_extension.dart b/model/lib/extensions/session_extension.dart
index 1617f8287..7cf3a831b 100644
--- a/model/lib/extensions/session_extension.dart
+++ b/model/lib/extensions/session_extension.dart
@@ -177,7 +177,7 @@ extension SessionExtension on Session {
try {
return personalAccount.accountId;
} catch (e) {
- logError('SessionExtension::safeAccountId:Exception: $e');
+ logWarning('SessionExtension::safeAccountId:Exception: $e');
return null;
}
}
diff --git a/scribe/lib/scribe/ai/data/datasource/ai_datasource.dart b/scribe/lib/scribe/ai/data/datasource/ai_datasource.dart
index ef60dc6ab..4284b1279 100644
--- a/scribe/lib/scribe/ai/data/datasource/ai_datasource.dart
+++ b/scribe/lib/scribe/ai/data/datasource/ai_datasource.dart
@@ -1,4 +1,4 @@
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
import 'package:scribe/scribe/ai/domain/model/ai_response.dart';
abstract class AIDataSource {
diff --git a/scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart b/scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart
index d8fbfa9c6..d679acbcb 100644
--- a/scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart
+++ b/scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart
@@ -1,6 +1,6 @@
import 'package:dio/dio.dart';
import 'package:scribe/scribe/ai/data/datasource/ai_datasource.dart';
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
import 'package:scribe/scribe/ai/data/network/ai_api.dart';
import 'package:scribe/scribe/ai/domain/model/ai_response.dart';
diff --git a/scribe/lib/scribe/ai/data/model/ai_api_request.dart b/scribe/lib/scribe/ai/data/model/ai_api_request.dart
index 822f2b2ae..e6e0469d4 100644
--- a/scribe/lib/scribe/ai/data/model/ai_api_request.dart
+++ b/scribe/lib/scribe/ai/data/model/ai_api_request.dart
@@ -1,4 +1,4 @@
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
class AIAPIRequest {
final List messages;
diff --git a/scribe/lib/scribe/ai/data/network/ai_api.dart b/scribe/lib/scribe/ai/data/network/ai_api.dart
index d972e5dfe..a722ad480 100644
--- a/scribe/lib/scribe/ai/data/network/ai_api.dart
+++ b/scribe/lib/scribe/ai/data/network/ai_api.dart
@@ -1,7 +1,7 @@
import 'package:core/data/network/dio_client.dart';
import 'package:scribe/scribe/ai/data/model/ai_api_request.dart';
import 'package:scribe/scribe/ai/data/model/ai_api_response.dart';
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
class AIApi {
final DioClient _dioClient;
diff --git a/scribe/lib/scribe/ai/data/repository/ai_repository_impl.dart b/scribe/lib/scribe/ai/data/repository/ai_repository_impl.dart
index 68200d42f..a8d15a7b7 100644
--- a/scribe/lib/scribe/ai/data/repository/ai_repository_impl.dart
+++ b/scribe/lib/scribe/ai/data/repository/ai_repository_impl.dart
@@ -1,5 +1,5 @@
import 'package:scribe/scribe/ai/data/datasource/ai_datasource.dart';
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
import 'package:scribe/scribe/ai/domain/model/ai_response.dart';
import 'package:scribe/scribe/ai/domain/repository/ai_scribe_repository.dart';
diff --git a/scribe/lib/scribe/ai/data/service/prompt_service.dart b/scribe/lib/scribe/ai/data/service/prompt_service.dart
index 91337bf63..4f213618f 100644
--- a/scribe/lib/scribe/ai/data/service/prompt_service.dart
+++ b/scribe/lib/scribe/ai/data/service/prompt_service.dart
@@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'package:core/utils/app_logger.dart';
import 'package:dio/dio.dart';
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
import 'package:scribe/scribe/ai/domain/model/prompt_data.dart';
import 'package:flutter/services.dart' show rootBundle;
@@ -59,8 +59,9 @@ class PromptService {
}
Future _fetchPromptsFromUrl(String url) async {
- log('PromptService::_fetchPromptsFromUrl: Fetching from $url');
-
+ final sanitizedUrl =
+ Uri.tryParse(url)?.replace(queryParameters: {}).toString() ?? url;
+ log('PromptService::_fetchPromptsFromUrl: Fetching from $sanitizedUrl');
try {
final response = await _dio.get(url);
final data = response.data;
@@ -87,11 +88,11 @@ class PromptService {
Future getPromptByName(String name) async {
final promptData = await loadPrompts();
- try {
- return promptData.prompts.firstWhere((prompt) => prompt.name == name);
- } catch (_) {
+ final prompt = promptData.prompts.where((p) => p.name == name).firstOrNull;
+ if (prompt == null) {
throw Exception('Prompt not found: $name');
}
+ return prompt;
}
Future> buildPromptByName(String name, String inputText, {String? task}) async {
diff --git a/scribe/lib/scribe/ai/domain/constants/ai_prompts.dart b/scribe/lib/scribe/ai/domain/constants/ai_prompts.dart
index 721e69e67..f9524bcf3 100644
--- a/scribe/lib/scribe/ai/domain/constants/ai_prompts.dart
+++ b/scribe/lib/scribe/ai/domain/constants/ai_prompts.dart
@@ -1,11 +1,19 @@
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
import 'package:scribe/scribe/ai/presentation/model/ai_action.dart';
import 'package:scribe/scribe/ai/presentation/model/ai_scribe_menu_action.dart';
import 'package:scribe/scribe/ai/data/service/prompt_service.dart';
import 'package:get/get.dart';
class AIPrompts {
- static final PromptService _promptService = Get.find();
+ static PromptService? _promptServiceInstance;
+
+ static PromptService get _promptService {
+ if (!Get.isRegistered()) {
+ throw StateError(
+ 'PromptService not registered. Ensure NetworkBindings.dependencies() has been called.');
+ }
+ return _promptServiceInstance ??= Get.find();
+ }
static Future> buildPrompt(AIAction action, String? text) async {
return switch (action) {
@@ -23,7 +31,17 @@ class AIPrompts {
return await _promptService.buildPromptByName(menuAction.promptId, text);
}
- static Future> buildCustomPrompt(String customPrompt, String? text) async {
- return await _promptService.buildPromptByName(CustomPromptAction.promptId, text ?? '', task: customPrompt);
+ static Future> buildCustomPrompt(
+ String customPrompt,
+ String? text,
+ ) async {
+ if (customPrompt.trim().isEmpty) {
+ throw ArgumentError('Custom prompt cannot be empty');
+ }
+ return await _promptService.buildPromptByName(
+ CustomPromptAction.promptId,
+ text ?? '',
+ task: customPrompt,
+ );
}
}
diff --git a/scribe/lib/scribe/ai/data/model/ai_message.dart b/scribe/lib/scribe/ai/domain/model/ai_message.dart
similarity index 100%
rename from scribe/lib/scribe/ai/data/model/ai_message.dart
rename to scribe/lib/scribe/ai/domain/model/ai_message.dart
diff --git a/scribe/lib/scribe/ai/domain/model/prompt_data.dart b/scribe/lib/scribe/ai/domain/model/prompt_data.dart
index 8b54a70d8..9b0205485 100644
--- a/scribe/lib/scribe/ai/domain/model/prompt_data.dart
+++ b/scribe/lib/scribe/ai/domain/model/prompt_data.dart
@@ -1,4 +1,4 @@
-import 'package:scribe/scribe/ai/data/model/ai_message.dart';
+import 'package:scribe/scribe/ai/domain/model/ai_message.dart';
class PromptData {
final List prompts;
@@ -9,13 +9,13 @@ class PromptData {
factory PromptData.fromJson(Map json) {
final promptsJson = json['prompts'] as List?;
-
+
return PromptData(
prompts: promptsJson
?.whereType