Skip to content

Commit

Permalink
TF-3260 Load & Display App Grid Linagora Ecosystem
Browse files Browse the repository at this point in the history
  • Loading branch information
dab246 committed Dec 9, 2024
1 parent 3f9f16e commit e38afd9
Show file tree
Hide file tree
Showing 49 changed files with 857 additions and 439 deletions.
2 changes: 0 additions & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
<uses-sdk tools:overrideLibrary="io.flutter.plugins.webviewflutter, com.pichillilorenzo.flutter_inappwebview" />

<queries>
<package android:name="com.linagora.android.linshare" />

<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
Expand Down
1 change: 1 addition & 0 deletions core/lib/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export 'presentation/views/container/tmail_container_widget.dart';
export 'presentation/views/clipper/side_arrow_clipper.dart';
export 'presentation/views/avatar/gradient_circle_avatar_icon.dart';
export 'presentation/views/loading/cupertino_loading_widget.dart';
export 'presentation/views/image/image_loader_mixin.dart';

// Resources
export 'presentation/resources/assets_paths.dart';
Expand Down
22 changes: 12 additions & 10 deletions core/lib/data/constants/constant.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
class Constant {
static const acceptHeaderDefault = 'application/json';
static const contentTypeHeaderDefault = 'application/json';
static const pdfMimeType = 'application/pdf';
static const base64Charset = 'base64';
static const textHtmlMimeType = 'text/html';
static const octetStreamMimeType = 'application/octet-stream';
static const pdfExtension = '.pdf';
static const imageType = 'image';
static const textVCardMimeType = 'text/x-vcard';
static const textPlainMimeType = 'text/plain';
static const String acceptHeaderDefault = 'application/json';
static const String contentTypeHeaderDefault = 'application/json';
static const String pdfMimeType = 'application/pdf';
static const String base64Charset = 'base64';
static const String textHtmlMimeType = 'text/html';
static const String octetStreamMimeType = 'application/octet-stream';
static const String pdfExtension = '.pdf';
static const String imageType = 'image';
static const String textVCardMimeType = 'text/x-vcard';
static const String textPlainMimeType = 'text/plain';
static const String slashCharacter = '/';
static const String andCharacter = '&';
}
48 changes: 48 additions & 0 deletions core/lib/presentation/views/image/image_loader_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

mixin ImageLoaderMixin {

Widget buildImage({
required String imagePath,
double? imageSize
}) {
if (isImageNetworkLink(imagePath)) {
return Image.network(
imagePath,
fit: BoxFit.fill,
width: imageSize ?? 150,
height: imageSize ?? 150,
errorBuilder: (_, __, ___) {
return Container(
width: imageSize ?? 150,
height: imageSize ?? 150,
color: AppColor.textFieldHintColor,
);
},
);
} else if (isImageSVG(imagePath)) {
return SvgPicture.asset(
imagePath,
width: imageSize ?? 150,
height: imageSize ?? 150,
);
} else {
return Image.asset(
imagePath,
fit: BoxFit.fill,
width: imageSize ?? 150,
height: imageSize ?? 150,
);
}
}

bool isImageNetworkLink(String imagePath) {
return imagePath.startsWith('http') == true ||
imagePath.startsWith('https') == true;
}

bool isImageSVG(String imagePath) => imagePath.endsWith('svg') == true;
}
128 changes: 53 additions & 75 deletions core/lib/presentation/views/text/slogan_builder.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/style_utils.dart';
import 'package:core/presentation/views/image/image_loader_mixin.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

/// A builder which builds a reusable slogan widget.
/// This contains the logo and the slogan text.
/// The elements are arranged in a column or row.
typedef OnTapCallback = void Function();

class SloganBuilder extends StatelessWidget {
class SloganBuilder extends StatelessWidget with ImageLoaderMixin {

final bool arrangedByHorizontal;
final String? text;
final TextStyle? textStyle;
final TextAlign? textAlign;
final String? logo;
final Uri? publicLogoUri;
final double? sizeLogo;
final OnTapCallback? onTapCallback;
final EdgeInsetsGeometry? paddingText;
Expand All @@ -33,7 +30,6 @@ class SloganBuilder extends StatelessWidget {
this.textStyle,
this.textAlign,
this.logo,
this.publicLogoUri,
this.sizeLogo,
this.onTapCallback,
this.padding,
Expand All @@ -45,82 +41,64 @@ class SloganBuilder extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (!arrangedByHorizontal) {
return InkWell(
onTap: onTapCallback,
hoverColor: hoverColor,
borderRadius: BorderRadius.all(Radius.circular(hoverRadius ?? 8)),
child: Padding(
padding: padding ?? EdgeInsets.zero,
child: Column(children: [
_logoApp(),
Padding(
padding: paddingText ?? const EdgeInsetsDirectional.only(top: 16, start: 16, end: 16),
child: Text(
text ?? '',
style: textStyle,
textAlign: textAlign,
overflow: enableOverflow ? CommonTextStyle.defaultTextOverFlow : null,
softWrap: enableOverflow ? CommonTextStyle.defaultSoftWrap : null,
maxLines: enableOverflow ? 1 : null,
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: onTapCallback,
hoverColor: hoverColor,
borderRadius: BorderRadius.all(Radius.circular(hoverRadius ?? 8)),
child: Padding(
padding: padding ?? EdgeInsets.zero,
child: Column(children: [
if (logo != null)
buildImage(
imagePath: logo!,
imageSize: sizeLogo,
),
Padding(
padding: paddingText ?? const EdgeInsetsDirectional.only(top: 16, start: 16, end: 16),
child: Text(
text ?? '',
style: textStyle,
textAlign: textAlign,
overflow: enableOverflow ? TextOverflow.ellipsis : null,
maxLines: enableOverflow ? 1 : null,
),
),
),
]),
]),
),
),
);
} else {
return InkWell(
onTap: onTapCallback,
hoverColor: hoverColor,
radius: hoverRadius ?? 8,
borderRadius: BorderRadius.all(Radius.circular(hoverRadius ?? 8)),
child: Padding(
padding: padding ?? EdgeInsets.zero,
child: Row(children: [
_logoApp(),
Padding(
padding: paddingText ?? const EdgeInsets.symmetric(horizontal: 10),
child: Text(
text ?? '',
style: textStyle,
textAlign: textAlign,
overflow: enableOverflow ? CommonTextStyle.defaultTextOverFlow : null,
softWrap: enableOverflow ? CommonTextStyle.defaultSoftWrap : null,
maxLines: enableOverflow ? 1 : null,
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: onTapCallback,
hoverColor: hoverColor,
radius: hoverRadius ?? 8,
borderRadius: BorderRadius.all(Radius.circular(hoverRadius ?? 8)),
child: Padding(
padding: padding ?? EdgeInsets.zero,
child: Row(children: [
if (logo != null)
buildImage(
imagePath: logo!,
imageSize: sizeLogo,
),
Padding(
padding: paddingText ?? const EdgeInsets.symmetric(horizontal: 10),
child: Text(
text ?? '',
style: textStyle,
textAlign: textAlign,
overflow: enableOverflow ? TextOverflow.ellipsis : null,
maxLines: enableOverflow ? 1 : null,
),
),
),
]),
]),
),
),
);
}
}

Widget _logoApp() {
if (logo != null && logo!.endsWith('svg')) {
return SvgPicture.asset(
logo!,
width: sizeLogo ?? 150,
height: sizeLogo ?? 150);
} else if (logo != null) {
return Image(
image: AssetImage(logo!),
fit: BoxFit.fill,
width: sizeLogo ?? 150,
height: sizeLogo ?? 150);
} else if (publicLogoUri != null) {
return Image.network(
publicLogoUri.toString(),
fit: BoxFit.fill,
width: sizeLogo ?? 150,
height: sizeLogo ?? 150,
errorBuilder: (_, error, stackTrace) {
return Container(
width: sizeLogo ?? 150,
height: sizeLogo ?? 150,
color: AppColor.textFieldHintColor,
);
});
} else {
return const SizedBox.shrink();
}
}
}
8 changes: 6 additions & 2 deletions core/lib/utils/string_convert.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
class StringConvert {
static String? writeEmptyToNull(String text) {
static String? writeEmptyToNull(String text) {
if (text.isEmpty) return null;
return text;
}

static String writeNullToEmpty(String? text) {
static String writeNullToEmpty(String? text) {
return text ?? '';
}

static String toUrlScheme(String hotScheme) {
return '$hotScheme://';
}
}
1 change: 1 addition & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<string>sms</string>
<string>tel</string>
<string>linshare.mobile</string>
<string>twake.chat</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
Expand Down
53 changes: 53 additions & 0 deletions lib/features/base/mixin/launcher_application_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

import 'package:core/utils/platform_info.dart';
import 'package:core/utils/string_convert.dart';
import 'package:external_app_launcher/external_app_launcher.dart';
import 'package:url_launcher/url_launcher.dart' as launcher;

mixin LauncherApplicationMixin {

Future<void> launchApplication({
String? androidPackageId,
String? iosScheme,
String? iosStoreLink,
Uri? uri,
}) async {
if (PlatformInfo.isWeb && uri != null) {
await openWebApplication(uri);
} else if (PlatformInfo.isAndroid && androidPackageId != null) {
await openAndroidApplication(androidPackageId);
} else if (PlatformInfo.isIOS &&
(iosScheme != null || iosStoreLink != null)) {
await openIOSApplication(
iosScheme,
iosStoreLink,
);
} else if (uri != null) {
await openOtherApplication(uri);
}
}

Future<void> openAndroidApplication(String androidPackageId) async {
await LaunchApp.openApp(androidPackageName: androidPackageId);
}

Future<void> openIOSApplication(String? iosScheme, String? iosStoreLink) async {
await LaunchApp.openApp(
iosUrlScheme: iosScheme != null
? StringConvert.toUrlScheme(iosScheme)
: null,
appStoreLink: iosStoreLink,
);
}

Future<void> openWebApplication(Uri uri) async {
await launcher.launchUrl(uri);
}

Future<void> openOtherApplication(Uri uri) async {
await launcher.launchUrl(
uri,
mode: launcher.LaunchMode.externalApplication,
);
}
}
23 changes: 16 additions & 7 deletions lib/features/login/data/extensions/service_path_extension.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

import 'package:core/data/constants/constant.dart';
import 'package:core/data/model/query/query_parameter.dart';
import 'package:core/data/network/config/service_path.dart';

Expand All @@ -7,24 +8,32 @@ extension ServicePathExtension on ServicePath {
return path;
}

ServicePath generateOIDCPath(Uri baseUrl) {
return ServicePath(baseUrl.toString() + path);
ServicePath usingBaseUrl(String baseUrl) {
String normalizedBaseUrl = baseUrl.endsWith(Constant.slashCharacter)
? baseUrl.substring(0, baseUrl.length - 1)
: baseUrl;

String normalizedPath = path.startsWith(Constant.slashCharacter)
? path.substring(1)
: path;

return ServicePath('$normalizedBaseUrl${Constant.slashCharacter}$normalizedPath');
}

ServicePath withQueryParameters(List<QueryParameter> queryParameters) {
if (queryParameters.isEmpty) {
return this;
}
if (path.lastIndexOf('/') == path.length - 1) {
if (path.lastIndexOf(Constant.slashCharacter) == path.length - 1) {
final newPath = path.substring(0, path.length - 1);

return ServicePath('$newPath?${queryParameters
.map((query) => '${query.queryName}=${query.queryValue}')
.join('&')}');
.join(Constant.andCharacter)}');
} else {
return ServicePath('$path?${queryParameters
.map((query) => '${query.queryName}=${query.queryValue}')
.join('&')}');
.join(Constant.andCharacter)}');
}
}

Expand All @@ -33,10 +42,10 @@ extension ServicePathExtension on ServicePath {
return this;
}

if (path.lastIndexOf('/') == path.length - 1) {
if (path.lastIndexOf(Constant.slashCharacter) == path.length - 1) {
return ServicePath('$path$pathParameter');
} else {
return ServicePath('$path/$pathParameter');
return ServicePath('$path${Constant.slashCharacter}$pathParameter');
}
}
}
Loading

0 comments on commit e38afd9

Please sign in to comment.