diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 4a7f17f794..061bd8ff5c 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -244,6 +244,7 @@ extension AppColor on Color { static const blue100 = Color(0xFFDFEEFF); static const blue400 = Color(0xFF80BDFF); static const m3Tertiary = Color(0xFF8C9CAF); + static const m3Tertiary70 = Color(0xFFE5ECF3); static const m3Neutral70 = Color(0xFFAEAAAE); static const grayBackgroundColor = Color(0xFFF3F6F9); static const m3SurfaceBackground = Color(0xFF1C1B1F); diff --git a/core/lib/presentation/views/quick_search/quick_search_input_form.dart b/core/lib/presentation/views/quick_search/quick_search_input_form.dart index 092ec37068..b91a2e6d98 100644 --- a/core/lib/presentation/views/quick_search/quick_search_input_form.dart +++ b/core/lib/presentation/views/quick_search/quick_search_input_form.dart @@ -1,3 +1,4 @@ +import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/quick_search/quick_search_action_define.dart'; import 'package:core/presentation/views/quick_search/quick_search_suggestion_box_controller.dart'; import 'package:core/presentation/views/quick_search/quick_search_suggestion_box_decoration.dart'; @@ -69,6 +70,7 @@ class QuickSearchInputForm extends FormField { ItemBuilder

? contactItemBuilder, SuggestionsCallback

? contactSuggestionsCallback, SuggestionSelectionCallback

? onContactSuggestionSelected, + Color backgroundColor = AppColor.colorBgDesktop, }) : assert( initialValue == null || textFieldConfiguration.controller == null), assert(minCharsForSuggestions >= 0), @@ -138,6 +140,7 @@ class QuickSearchInputForm extends FormField { contactItemBuilder: contactItemBuilder, contactSuggestionsCallback: contactSuggestionsCallback, onContactSuggestionSelected: onContactSuggestionSelected, + backgroundColor: backgroundColor, ); }, ); diff --git a/core/lib/presentation/views/quick_search/type_ahead_field_quick_search.dart b/core/lib/presentation/views/quick_search/type_ahead_field_quick_search.dart index f6f16fe5b5..6e71e790ba 100644 --- a/core/lib/presentation/views/quick_search/type_ahead_field_quick_search.dart +++ b/core/lib/presentation/views/quick_search/type_ahead_field_quick_search.dart @@ -318,6 +318,8 @@ class TypeAheadFieldQuickSearch extends StatefulWidget { /// Min input length to start autocomplete final int? minInputLengthAutocomplete; + final Color backgroundColor; + /// Creates a [TypeAheadFieldQuickSearch] const TypeAheadFieldQuickSearch({ Key? key, @@ -364,6 +366,7 @@ class TypeAheadFieldQuickSearch extends StatefulWidget { this.contactItemBuilder, this.contactSuggestionsCallback, this.onContactSuggestionSelected, + this.backgroundColor = AppColor.colorBgDesktop, }) : assert(animationStart >= 0.0 && animationStart <= 1.0), assert( direction == AxisDirection.down || direction == AxisDirection.up), @@ -658,9 +661,9 @@ class _TypeAheadFieldQuickSearchState ], color: Colors.white, ) - : const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(12)), - color: AppColor.colorBgDesktop, + : BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(12)), + color: widget.backgroundColor, ), height: widget.maxHeight, child: Row( diff --git a/cozy/.gitignore b/cozy/.gitignore new file mode 100644 index 0000000000..29a3a5017f --- /dev/null +++ b/cozy/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/cozy/README.md b/cozy/README.md new file mode 100644 index 0000000000..741a383bf7 --- /dev/null +++ b/cozy/README.md @@ -0,0 +1,3 @@ +# cozy + +Cozy config for Cozy integration diff --git a/cozy/analysis_options.yaml b/cozy/analysis_options.yaml new file mode 100644 index 0000000000..f9b303465f --- /dev/null +++ b/cozy/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/cozy/lib/cozy_config/cozy_config.dart b/cozy/lib/cozy_config/cozy_config.dart new file mode 100644 index 0000000000..bacfec40b8 --- /dev/null +++ b/cozy/lib/cozy_config/cozy_config.dart @@ -0,0 +1 @@ +export 'cozy_config_stub.dart' if (dart.library.html) 'cozy_config_web.dart'; \ No newline at end of file diff --git a/cozy/lib/cozy_config/cozy_config_stub.dart b/cozy/lib/cozy_config/cozy_config_stub.dart new file mode 100644 index 0000000000..6be89c45be --- /dev/null +++ b/cozy/lib/cozy_config/cozy_config_stub.dart @@ -0,0 +1,25 @@ +class _CozyConfigManagerStub { + Future injectCozyScript() async { + throw UnimplementedError(); + } + + Future initialize() async { + throw UnimplementedError(); + } +} + +class CozyConfig { + static final CozyConfig _instance = CozyConfig._internal(); + + factory CozyConfig() { + return _instance; + } + + CozyConfig._internal(); + + final manager = _CozyConfigManagerStub(); + + Future get isInsideCozy async { + return false; + } +} diff --git a/cozy/lib/cozy_config/cozy_config_web.dart b/cozy/lib/cozy_config/cozy_config_web.dart new file mode 100644 index 0000000000..e9837beeab --- /dev/null +++ b/cozy/lib/cozy_config/cozy_config_web.dart @@ -0,0 +1,21 @@ +import 'dart:async'; + +import 'package:linagora_design_flutter/cozy_config_manager/cozy_config_manager.dart'; + +class CozyConfig { + static final CozyConfig _instance = CozyConfig._internal(); + + factory CozyConfig() { + return _instance; + } + + CozyConfig._internal(); + + final manager = CozyConfigManager(); + + bool? _isInsideCozy; + + Future get isInsideCozy async { + return _isInsideCozy ??= await manager.isInsideCozy; + } +} diff --git a/cozy/pubspec.lock b/cozy/pubspec.lock new file mode 100644 index 0000000000..2f4d003477 --- /dev/null +++ b/cozy/pubspec.lock @@ -0,0 +1,262 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + auto_size_text: + dependency: transitive + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + url: "https://pub.dev" + source: hosted + version: "2.0.7" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + linagora_design_flutter: + dependency: "direct main" + description: + path: "." + ref: cozy-integration + resolved-ref: "59f30e4c5d21fbab49670a81bbe0d37804795d1b" + url: "https://github.com/linagora/linagora-design-flutter.git" + source: git + version: "0.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4" + url: "https://pub.dev" + source: hosted + version: "3.12.0" + photo_manager: + dependency: transitive + description: + name: photo_manager + sha256: "0bc7548fd3111eb93a3b0abf1c57364e40aeda32512c100085a48dade60e574f" + url: "https://pub.dev" + source: hosted + version: "3.6.4" + photo_manager_image_provider: + dependency: transitive + description: + name: photo_manager_image_provider + sha256: b6015b67b32f345f57cf32c126f871bced2501236c405aafaefa885f7c821e4f + url: "https://pub.dev" + source: hosted + version: "2.2.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" +sdks: + dart: ">=3.5.4 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/cozy/pubspec.yaml b/cozy/pubspec.yaml new file mode 100644 index 0000000000..c8a8b2d851 --- /dev/null +++ b/cozy/pubspec.yaml @@ -0,0 +1,24 @@ +name: cozy +description: "Cozy integration module" +publish_to: 'none' +version: 0.1.0 + +environment: + sdk: ^3.5.4 + +dependencies: + flutter: + sdk: flutter + + linagora_design_flutter: + git: + url: https://github.com/linagora/linagora-design-flutter.git + ref: cozy-integration + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^4.0.0 + +flutter: + uses-material-design: true diff --git a/cozy/web/favicon.png b/cozy/web/favicon.png new file mode 100644 index 0000000000..8aaa46ac1a Binary files /dev/null and b/cozy/web/favicon.png differ diff --git a/cozy/web/icons/Icon-192.png b/cozy/web/icons/Icon-192.png new file mode 100644 index 0000000000..b749bfef07 Binary files /dev/null and b/cozy/web/icons/Icon-192.png differ diff --git a/cozy/web/icons/Icon-512.png b/cozy/web/icons/Icon-512.png new file mode 100644 index 0000000000..88cfd48dff Binary files /dev/null and b/cozy/web/icons/Icon-512.png differ diff --git a/cozy/web/icons/Icon-maskable-192.png b/cozy/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000..eb9b4d76e5 Binary files /dev/null and b/cozy/web/icons/Icon-maskable-192.png differ diff --git a/cozy/web/icons/Icon-maskable-512.png b/cozy/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000..d69c56691f Binary files /dev/null and b/cozy/web/icons/Icon-maskable-512.png differ diff --git a/cozy/web/index.html b/cozy/web/index.html new file mode 100644 index 0000000000..3d38c992c7 --- /dev/null +++ b/cozy/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + cozy + + + + + + diff --git a/cozy/web/manifest.json b/cozy/web/manifest.json new file mode 100644 index 0000000000..c469eaedfb --- /dev/null +++ b/cozy/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "cozy", + "short_name": "cozy", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/docs/adr/0060-cozy-integration-env.md b/docs/adr/0060-cozy-integration-env.md new file mode 100644 index 0000000000..8c0c291ee5 --- /dev/null +++ b/docs/adr/0060-cozy-integration-env.md @@ -0,0 +1,21 @@ +# 60. Cozy integration env + +Date: 2025-04-15 + +## Status + +Accepted + +## Context + +- Cozy script needs to be loaded optionally + +## Decision + +- `COZY_INTEGRATION` is added to env + - Set it to `true` if you want to load cozy script + - Set it to `false` or left it as is if you don't want to load cozy script + +## Consequences + +- Cozy script can be loaded optionally diff --git a/docs/adr/0061-cozy-integration-set-up.md b/docs/adr/0061-cozy-integration-set-up.md new file mode 100644 index 0000000000..28d8684ead --- /dev/null +++ b/docs/adr/0061-cozy-integration-set-up.md @@ -0,0 +1,71 @@ +# 61. Cozy integration set up + +Date: 2025-04-21 + +## Status + +Accepted + +## Context + +- How to run Cozy locally? + +## Steps +### Install cozy-stack CLI + +1. Install CouchDB +```bash +docker run -d \ + --name cozy-stack-couch \ + -p 5984:5984 \ + -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password \ + -v $HOME/.cozy-stack-couch:/opt/couchdb/data \ + couchdb:3.3 +curl -X PUT http://admin:password@127.0.0.1:5984/{_users,_replicator} +``` +2. Install cozy-stack CLI +- Clone cozy-stack +```bash +git clone git@github.com:cozy/cozy-stack.git +cd cozy-stack +make +``` +- Install Go and add to path +- Create cozy configuration file +```bash +cp cozy.example.yaml $HOME/.cozy/cozy.yml +``` +- Find CouchDB config inside `cozy.yml` and edit as follow: +```yaml +couchdb: + url: +``` +3. Run cozy-stack +- Start cozy-stack +```bash +cozy-stack serve +``` +- Create an instance +```bash +cozy-stack instances add tmail.localhost:8080 --passphrase cozy --apps home,store,drive,photos,settings,contacts,notes,passwords --email tmail@cozy.localhost --locale en --public-name Tmail --context-name dev +``` +- The created instance will be available at http://tmail.localhost:8080/ +- The password is `cozy` + +### Run Cozy locally +1. On the cozy-twakemail side +- Clone `https://github.com/cozy/cozy-twakemail` +- `yarn install` +- In `src/components/AppLayout.jsx`, replace `flag('mail.embedded-app-url')` with `http://localhost:2023` +- `yarn build` +- `cozy-stack serve --appdir tmail:build/ --disable-csp` + +2. On the tmail side +- Config tmail to run on basic auth +- isInsideCozy will be `false` if run on localhost, so in cozy_config_web.dart, return true on isInsideCozy +- in `env.file`, COZY_INTEGRATION=true +- `flutter run -d chrome --web-port 2023 --web-browser-flag "--disable-web-security" --profile` + +3. Access Cozy +- tmail cozy: http://tmail.localhost:8080/ +- The password is `cozy` \ No newline at end of file diff --git a/docs/configuration/cozy_integration_configuration.md b/docs/configuration/cozy_integration_configuration.md new file mode 100644 index 0000000000..627f8e7f8a --- /dev/null +++ b/docs/configuration/cozy_integration_configuration.md @@ -0,0 +1,12 @@ +## Configuration Cozy Integration + +### Context +- Cozy script load is optional +### How to config +In [env.file]: +- If you want to load Cozy script: +```COZY_INTEGRATION=true``` +- If you don't want to load Cozy script: +```COZY_INTEGRATION=false``` + or +```COZY_INTEGRATION=``` \ No newline at end of file diff --git a/env.file b/env.file index a072f68967..77b6626116 100644 --- a/env.file +++ b/env.file @@ -7,4 +7,5 @@ FCM_AVAILABLE=supported IOS_FCM=supported FORWARD_WARNING_MESSAGE= PLATFORM=other -WS_ECHO_PING= \ No newline at end of file +WS_ECHO_PING= +COZY_INTEGRATION= \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 6a30400e16..17672f510b 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -1,4 +1,5 @@ import 'package:core/core.dart'; +import 'package:cozy/cozy_config/cozy_config.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; @@ -60,31 +61,48 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { child: Container( color: AppColor.colorBgDesktop, child: Column(children: [ - Obx(() { - final accountId = controller.accountId.value; + FutureBuilder( + future: CozyConfig().isInsideCozy, + builder: (context, snapshot) { + if (snapshot.data == true) { + return const SizedBox.shrink(); + } - return NavigationBarWidget( - imagePaths: controller.imagePaths, - accountId: accountId, - avatarUserName: controller.getOwnEmailAddress().firstCharacterToUpperCase, - contactSupportCapability: accountId != null - ? controller.sessionCurrent?.getContactSupportCapability(accountId) - : null, - searchForm: SearchInputFormWidget(), - appGridController: controller.appGridDashboardController, - onTapApplicationLogoAction: controller.redirectToInboxAction, - onTapAvatarAction: (position) => - controller.handleClickAvatarAction(context, position), - onTapContactSupportAction: (contactSupport) => - controller.onGetHelpOrReportBug(contactSupport), - ); - }), + return Obx(() { + final accountId = controller.accountId.value; + + return NavigationBarWidget( + imagePaths: controller.imagePaths, + accountId: accountId, + avatarUserName: controller.getOwnEmailAddress().firstCharacterToUpperCase, + contactSupportCapability: accountId != null + ? controller.sessionCurrent?.getContactSupportCapability(accountId) + : null, + searchForm: SearchInputFormWidget(), + appGridController: controller.appGridDashboardController, + onTapApplicationLogoAction: controller.redirectToInboxAction, + onTapAvatarAction: (position) => + controller.handleClickAvatarAction(context, position), + onTapContactSupportAction: (contactSupport) => + controller.onGetHelpOrReportBug(contactSupport), + ); + }); + } + ), Expanded(child: Row(children: [ Column(children: [ - ComposeButtonWidget( - imagePaths: controller.imagePaths, - onTapAction: () => - controller.openComposer(ComposerArguments()), + FutureBuilder( + future: CozyConfig().isInsideCozy, + builder: (context, snapshot) { + return ComposeButtonWidget( + imagePaths: controller.imagePaths, + onTapAction: () => + controller.openComposer(ComposerArguments()), + buttonPadding: snapshot.data == true + ? const EdgeInsetsDirectional.symmetric(vertical: 10) + : const EdgeInsetsDirectional.symmetric(vertical: 8), + ); + } ), Expanded(child: SizedBox( width: ResponsiveUtils.defaultSizeMenu, @@ -101,6 +119,44 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { ]), Expanded(child: Column(children: [ const SizedBox(height: 16), + FutureBuilder( + future: CozyConfig().isInsideCozy, + builder: (context, snapshot) { + if (snapshot.data != true) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Row( + children: [ + SizedBox( + width: MediaQuery.sizeOf(context).width * 0.4, + height: 44, + child: SearchInputFormWidget( + backgroundColor: AppColor.m3Tertiary70, + fontSize: 15, + contentPadding: const EdgeInsets.only(bottom: 4), + ), + ), + const Spacer(), + TMailButtonWidget.fromIcon( + icon: controller.imagePaths.icSetting, + iconColor: AppColor.steelGrayA540, + backgroundColor: Colors.transparent, + onTapActionAtPositionCallback: (position) { + controller.handleClickAvatarAction( + context, + position, + ); + }, + margin: const EdgeInsets.only(right: 16), + ), + ], + ), + ); + } + ), Obx(() => RecoverDeletedMessageLoadingBannerWidget( isLoading: controller.isRecoveringDeletedMessage.value, horizontalLoadingWidget: horizontalLoadingWidget, diff --git a/lib/features/mailbox_dashboard/presentation/widgets/compose_button_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/compose_button_widget.dart index f6d7bf8217..11d0062600 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/compose_button_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/compose_button_widget.dart @@ -11,11 +11,13 @@ class ComposeButtonWidget extends StatelessWidget { final ImagePaths imagePaths; final VoidCallback onTapAction; + final EdgeInsetsGeometry buttonPadding; const ComposeButtonWidget({ super.key, required this.imagePaths, required this.onTapAction, + this.buttonPadding = const EdgeInsets.symmetric(vertical: 8), }); @override @@ -36,7 +38,7 @@ class ComposeButtonWidget extends StatelessWidget { borderRadius: 10, iconSize: 24, iconColor: Colors.white, - padding: const EdgeInsetsDirectional.symmetric(vertical: 8), + padding: buttonPadding, backgroundColor: AppColor.blue700, textStyle: ThemeUtils.textStyleBodyBody2(color: Colors.white), onTapActionCallback: onTapAction, diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart index f7ea4651a6..9a685f0233 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart @@ -38,7 +38,16 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { final _imagePaths = Get.find(); final _responsiveUtils = Get.find(); - SearchInputFormWidget({Key? key}) : super(key: key); + SearchInputFormWidget({ + super.key, + this.backgroundColor = AppColor.colorBgDesktop, + this.fontSize = 16, + this.contentPadding = EdgeInsets.zero, + }); + + final Color backgroundColor; + final double fontSize; + final EdgeInsetsGeometry contentPadding; @override Widget build(BuildContext context) { @@ -130,6 +139,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { contactItemBuilder: (context, emailAddress) => ContactQuickSearchItem(emailAddress: emailAddress), contactSuggestionsCallback: _dashBoardController.getContactSuggestion, onContactSuggestionSelected: _invokeSelectContactSuggestion, + backgroundColor: backgroundColor, ) ), ); @@ -203,6 +213,9 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { return QuickSearchTextFieldConfiguration( controller: _searchController.searchInputController, focusNode: _searchController.searchFocus, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + fontSize: fontSize, + ), textInputAction: TextInputAction.done, cursorColor: AppColor.primaryColor, textDirection: DirectionUtils.getDirectionByLanguage(context), @@ -211,10 +224,16 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { border: InputBorder.none, focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, - contentPadding: EdgeInsets.zero, + contentPadding: contentPadding, hintText: AppLocalizations.of(context).search_emails, - hintStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 16.0), - labelStyle: const TextStyle(color: Colors.black, fontSize: 16.0) + hintStyle: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppColor.colorHintSearchBar, + fontSize: fontSize, + ), + labelStyle: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.black, + fontSize: fontSize, + ), ), leftButton: Padding( padding: const EdgeInsetsDirectional.only(start: 8), diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart index 2dfafaf998..5cf36f5c9c 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_view.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/string_extension.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/responsive/responsive_widget.dart'; +import 'package:cozy/cozy_config/cozy_config.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/navigation_bar/navigation_bar_widget.dart'; @@ -35,15 +36,22 @@ class ManageAccountDashBoardView extends GetWidget NavigationBarWidget( - imagePaths: controller.imagePaths, - accountId: controller.accountId.value, - avatarUserName: controller.getOwnEmailAddress().firstCharacterToUpperCase, - onTapApplicationLogoAction: () => - controller.backToMailboxDashBoard(context: context), - onTapAvatarAction: (position) => - controller.handleClickAvatarAction(context, position), - )), + FutureBuilder( + future: CozyConfig().isInsideCozy, + builder: (context, snapshot) { + if (snapshot.data == true) return const SizedBox.shrink(); + + return Obx(() => NavigationBarWidget( + imagePaths: controller.imagePaths, + accountId: controller.accountId.value, + avatarUserName: controller.getOwnEmailAddress().firstCharacterToUpperCase, + onTapApplicationLogoAction: () => + controller.backToMailboxDashBoard(context: context), + onTapAvatarAction: (position) => + controller.handleClickAvatarAction(context, position), + )); + } + ), Expanded(child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/main.dart b/lib/main.dart index af3d00786e..490b5f3577 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/utils/theme_utils.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/build_utils.dart'; import 'package:core/utils/platform_info.dart'; +import 'package:cozy/cozy_config/cozy_config.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -15,6 +16,7 @@ import 'package:tmail_ui_user/main/localizations/localization_service.dart'; import 'package:tmail_ui_user/main/pages/app_pages.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'package:tmail_ui_user/main/utils/app_config.dart'; import 'package:tmail_ui_user/main/utils/app_utils.dart'; import 'package:url_strategy/url_strategy.dart'; import 'package:worker_manager/worker_manager.dart'; @@ -59,6 +61,15 @@ class _TMailAppState extends State { if (PlatformInfo.isMobile) { _deepLinksManager = getBinding(); _deepLinksManager?.registerDeepLinkStreamListener(); + } else if (AppConfig.isCozyIntegrationEnabled) { + final cozyConfig = CozyConfig(); + + cozyConfig.manager.injectCozyScript().then((_) async { + final isInsideCozy = await cozyConfig.isInsideCozy; + if (!isInsideCozy) return; + + await cozyConfig.manager.initialize(); + }); } } diff --git a/lib/main/utils/app_config.dart b/lib/main/utils/app_config.dart index d93afa7473..f2c0f7e6fd 100644 --- a/lib/main/utils/app_config.dart +++ b/lib/main/utils/app_config.dart @@ -71,4 +71,6 @@ class AppConfig { static bool get isSaasPlatForm => _platformEnv.toLowerCase() == saasPlatform; static bool get isWebSocketEchoPingEnabled => dotenv.get('WS_ECHO_PING', fallback: 'false') == 'true'; + + static bool get isCozyIntegrationEnabled => dotenv.get('COZY_INTEGRATION', fallback: 'false') == 'true'; } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index dbcd8237b0..985fd60c3b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -312,6 +312,13 @@ packages: relative: true source: path version: "1.0.0+1" + cozy: + dependency: "direct main" + description: + path: cozy + relative: true + source: path + version: "0.1.0" cross_file: dependency: transitive description: @@ -1381,8 +1388,8 @@ packages: dependency: "direct main" description: path: "." - ref: master - resolved-ref: "0f666ca14fd4f0710775ca3de03cde73b21de7d6" + ref: cozy-integration + resolved-ref: "59f30e4c5d21fbab49670a81bbe0d37804795d1b" url: "https://github.com/linagora/linagora-design-flutter.git" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index 56ead9dd58..7bccd9f063 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,9 @@ dependencies: server_settings: path: server_settings + cozy: + path: cozy + ### Dependencies from git ### rich_text_composer: git: @@ -97,7 +100,7 @@ dependencies: linagora_design_flutter: git: url: https://github.com/linagora/linagora-design-flutter.git - ref: master + ref: cozy-integration # TODO: Fix bug where apps cannot be launched on iOS 18. We will change it when the PR in upstream repository will be merged # https://github.com/GeekyAnts/external_app_launcher/pull/42 diff --git a/scripts/prebuild.sh b/scripts/prebuild.sh index d8ed0dde05..f7d32bee45 100755 --- a/scripts/prebuild.sh +++ b/scripts/prebuild.sh @@ -15,6 +15,11 @@ for mod in "${modules[@]}"; do ) done +# For Cozy +cd cozy +flutter pub get +cd ../ + # For the parent module flutter pub get dart run build_runner build --delete-conflicting-outputs &&