Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic link #173

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions ecommers/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"selectCreditCard": "Select credit card",
"addingShippingAddress": "Adding Shipping Address",
"fullName": "Full Name",
"messageToSeller" : "Message to seller (optional)",
"messageToSeller": "Message to seller (optional)",
"address": "Address",
"city": "City",
"stateProvinceRegion": "State/Province/Region",
Expand All @@ -93,7 +93,7 @@
"addShippingAddress": "ADD SHIPPING ADDRESS",
"notShippingAddress": "You don't have any shipping addresses",
"selectAddress": "Select address",
"errorMessageShippingAddress" : "Please enter this field",
"errorMessageShippingAddress": "Please enter this field",
"enter_sms_code_dialog": {
"title": "Enter SMS Code",
"primary_button": "Done"
Expand Down Expand Up @@ -122,5 +122,13 @@
"description": "Password restore link sent",
"primary_button": "OK"
},
"share_image": "Share image",
"share_image_with_text": "Share image with text",
"share_text": "Share text",
"share_dynamic_link": "Share link",
"title": "Title",
"price": "Price",
"rate": "Rate",
"e_commerce": "E-commerce",
"empty": ""
}
52 changes: 52 additions & 0 deletions ecommers/lib/core/app_services/dynamic_link_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'package:ecommers/core/models/data_models/index.dart';
import 'package:ecommers/ui/utils/index.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:ecommers/shared/dependency_service.dart';
import 'package:ecommers/core/common/index.dart';

class DynamicLinkService {
Future handleDynamicLinks() async {
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();

_handleDeepLink(data);

FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
_handleDeepLink(dynamicLink);
}, onError: (OnLinkErrorException e) async {
logger.ex(e);
});
}

Future _handleDeepLink(PendingDynamicLinkData data) async {
final Uri deepLink = data?.link;

if (deepLink != null && membershipService.isNotExpired) {
final productId = int.parse(deepLink.queryParameters['id']);
final Product product = await productService.fetchProductById(productId);
navigationService.navigateTo(Pages.product, arguments: product);
}
}

Future<String> createDynamicLink(Product product) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://ecommers.page.link',
link: Uri.parse('https://ecommers.page.link/product-id?id=${product.id}'),
androidParameters: AndroidParameters(
packageName: 'com.ecommers.sample',
),
iosParameters: IosParameters(
bundleId: 'com.ecommers.sample',
),
itunesConnectAnalyticsParameters: ItunesConnectAnalyticsParameters(),
socialMetaTagParameters: SocialMetaTagParameters(
title: '${product.details.brand} ${Formatter.getCost(product?.price)}',
description: localization.e_commerce
),
);

final Uri dynamicUrl = await parameters.buildUrl();
return dynamicUrl.toString();
}
}
2 changes: 2 additions & 0 deletions ecommers/lib/core/app_services/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ export 'app_service.dart';
export 'auth_response.dart';
export 'authorization_service.dart';
export 'category_service.dart';
export 'dynamic_link_service.dart';
export 'note_service.dart';
export 'paginator.dart';
export 'payment_method_service.dart';
export 'product_service.dart';
export 'share_product_service.dart';
export 'shipping_address_service.dart';
12 changes: 12 additions & 0 deletions ecommers/lib/core/app_services/product_service.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:chopper/chopper.dart';
import 'package:ecommers/shared/dependency_service.dart';
import 'package:enum_to_string/enum_to_string.dart';

Expand Down Expand Up @@ -30,6 +31,17 @@ class ProductService {
return null;
}

Future<Product> fetchProductById(int productId) async {
final Response<Product> response =
await apiService.productId(id: productId);

if (response.isSuccessful) {
return response.body;
}

return null;
}

Future<List<Product>> fetchLatestProducts(int from, int to) async {
final response = await apiService.productsLatest(from, to);

Expand Down
57 changes: 57 additions & 0 deletions ecommers/lib/core/app_services/share_product_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:ecommers/core/models/data_models/index.dart';
import 'package:ecommers/shared/dependency_service.dart';
import 'package:ecommers/ui/utils/index.dart';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:flutter/foundation.dart';

class ShareProductService {
Future shareDynamicLinkText(Product product) async {
try {
final String dynamicLink =
await dynamicLinkService.createDynamicLink(product);
Share.text('${product.title}', '$dynamicLink', 'text/plain');
} catch (ex) {
logger.ex(ex);
}
}

Future shareImageWithText(Product product) async {
try {
final request =
await HttpClient().getUrl(Uri.parse(product?.previewImage));
final response = await request.close();
final Uint8List bytes =
await consolidateHttpClientResponseBytes(response);
await Share.file('${product.title}', '${product.title}.png', bytes, '*/*',
text: Formatter.getShareText(product));
} catch (ex) {
logger.ex(ex);
}
}

Future shareImage(Product product) async {
try {
final request =
await HttpClient().getUrl(Uri.parse(product?.previewImage));
final response = await request.close();
final Uint8List bytes =
await consolidateHttpClientResponseBytes(response);
await Share.file(
'${product.title}', '${product.title}.png', bytes, 'image/png');
} catch (ex) {
logger.ex(ex);
}
}

Future shareText(Product product) async {
try {
Share.text(
'${product.title}', Formatter.getShareText(product), 'text/plain');
} catch (ex) {
logger.ex(ex);
}
}
}
2 changes: 2 additions & 0 deletions ecommers/lib/core/common/api_defines.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ class ApiDefines {
static const String login = '/login';
static const String auth = '/auth';

static const String productIdPathSegment = 'productId';
static const String productId = '/productId/{id}';
static const String products = '/products';
static const String productsLatest = '/products/latest';
static const String productsRecent = '/products/recent';
Expand Down
1 change: 1 addition & 0 deletions ecommers/lib/core/provider_models/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export 'product_tab_provider_model.dart';
export 'products_grid_provder_model.dart';
export 'search_page_provider_model.dart';
export 'search_query_provider_model.dart';
export 'share_product_provider.dart';
export 'shell_provider_model.dart';
export 'shipping_address_provider_model.dart';
21 changes: 21 additions & 0 deletions ecommers/lib/core/provider_models/share_product_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:ecommers/core/models/data_models/index.dart';
import 'package:ecommers/shared/dependency_service.dart';
import 'package:flutter/material.dart';

class ShareProductProviderModel extends ChangeNotifier {
Future shareDynamicLink(Product product) async {
await shareProductService.shareDynamicLinkText(product);
}

Future shareImage(Product product) async {
await shareProductService.shareImage(product);
}

Future shareText(Product product) async {
await shareProductService.shareText(product);
}

Future shareTextImage(Product product) async {
await shareProductService.shareImageWithText(product);
}
}
5 changes: 5 additions & 0 deletions ecommers/lib/core/services/api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ abstract class ApiService extends ChopperService {

@Get(path: ApiDefines.notes)
Future<Response<List<Note>>> notes();

@Get(path: ApiDefines.productId)
Future<Response<Product>> productId({
@Path('id') int id,
});
}
2 changes: 2 additions & 0 deletions ecommers/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class _MainAppState extends State<MainApp> with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
dynamicLinkService.handleDynamicLinks();
LocalServer.setup();
super.initState();
}
Expand Down Expand Up @@ -64,6 +65,7 @@ class _MainAppState extends State<MainApp> with WidgetsBindingObserver {
ChangeNotifierProvider(create: (_) => PaymentMethodProviderModel()),
ChangeNotifierProvider(create: (_) => ShippingAddressProviderModel()),
ChangeNotifierProvider(create: (_) => CartProvider()),
ChangeNotifierProvider(create: (_) => ShareProductProviderModel()),
],
child: MaterialApp(
title: 'ecommers',
Expand Down
4 changes: 4 additions & 0 deletions ecommers/lib/shared/dependency_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ CacheDatabase get cacheDatabase => _ioc.get<CacheDatabase>();
CartRepository get cartRepository => _ioc.get<CartRepository>();
Paginator createPaginator() => _ioc.get<Paginator>();
DialogService get dialogService => _ioc.get<DialogService>();
ShareProductService get shareProductService => _ioc.get<ShareProductService>();
DynamicLinkService get dynamicLinkService => _ioc.get<DynamicLinkService>();
FirebaseAuthRepository get authRepository => _ioc.get<FirebaseAuthRepository>();
Logger get logger => _ioc.get<Logger>();
ShippingAddressService get shippingAddressService => _ioc.get<ShippingAddressService>();
Expand All @@ -61,7 +63,9 @@ class DependencyService {
..registerLazySingleton(() => Logger())
..registerLazySingleton(() => CategoryService())
..registerLazySingleton(() => PaymentMethodService())
..registerLazySingleton(() => DynamicLinkService())
..registerLazySingleton(() => ShippingAddressService())
..registerLazySingleton(() => ShareProductService())
..registerLazySingleton(() => NoteService())
..registerSingletonAsync(
() async {
Expand Down
16 changes: 16 additions & 0 deletions ecommers/lib/shared/i18n.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,22 @@ class I18n implements WidgetsLocalizations {
String get password_restoration_dialogDescription => "Password restore link sent";
/// "OK"
String get password_restoration_dialogPrimary_button => "OK";
/// "Share image"
String get share_image => "Share image";
/// "Share image with text"
String get share_image_with_text => "Share image with text";
/// "Share text"
String get share_text => "Share text";
/// "Share link"
String get share_dynamic_link => "Share link";
/// "Title"
String get title => "Title";
/// "Price"
String get price => "Price";
/// "Rate"
String get rate => "Rate";
/// "E-commerce"
String get e_commerce => "E-commerce";
/// ""
String get empty => "";
}
Expand Down
30 changes: 20 additions & 10 deletions ecommers/lib/ui/pages/product_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import 'package:ecommers/core/provider_models/index.dart';
class ProductPage extends StatelessWidget {
final Product productModel;
final bool withHeroAniamtion;
const ProductPage({@required this.productModel, this.withHeroAniamtion = true, Key key}) : super(key: key);
const ProductPage(
{@required this.productModel, this.withHeroAniamtion = true, Key key})
: super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -43,14 +45,14 @@ class ProductPage extends StatelessWidget {
Selector<CartProvider, int>(
builder: (context, data, child) {
return IconButton(
icon: IconWithBadge(
badgeValue: cartProvider.orderCount,
badgeTextStyle: textTheme.overline,
icon: const Icon(
Icons.shopping_cart,
color: BrandingColors.primaryText,
),
icon: IconWithBadge(
badgeValue: cartProvider.orderCount,
badgeTextStyle: textTheme.overline,
icon: const Icon(
Icons.shopping_cart,
color: BrandingColors.primaryText,
),
),
onPressed: model.navigateToCart,
);
},
Expand All @@ -72,7 +74,9 @@ class ProductPage extends StatelessWidget {
leading: const SizedBox(height: 0),
flexibleSpace: FlexibleSpaceBar(
background: CarouselWidget(
tag: withHeroAniamtion ? model.heroImageTag : ProductPageProviderModel.undefineTagValue,
tag: withHeroAniamtion
? model.heroImageTag
: ProductPageProviderModel.undefineTagValue,
images: model.images,
currentPageNotifier: valueNotifier,
currentPageController: pageController,
Expand Down Expand Up @@ -163,9 +167,15 @@ class ProductPage extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.all(Insets.x5),
child: ProductPageBottomView(
sharedFunction: () {
showDialog(
context: context,
builder: (BuildContext context) {
return ShareDialog(productModel);
});
},
addToCartFunction: () {
cartProvider.add(OrderModel.fromProduct(
product: productModel,
color: model.selectColor,
size: model.selectSize,
));
Expand Down
6 changes: 6 additions & 0 deletions ecommers/lib/ui/utils/formatter.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:ecommers/core/models/data_models/index.dart';
import 'package:ecommers/shared/dependency_service.dart';
import 'package:intl/intl.dart';

class Formatter {
Expand Down Expand Up @@ -32,4 +34,8 @@ class Formatter {
? '$firstName $lastName'
: 'No Name';
}

static String getShareText(Product product) {
return '${localization.title}: ${product?.title}\n${localization.price}: ${Formatter.getCost(product?.price)}\n${localization.rate}: ${product?.rate}\n${product?.details?.brand}, ${product?.details?.category}';
}
}
1 change: 1 addition & 0 deletions ecommers/lib/ui/widgets/product_page/index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export 'header.dart';
export 'product_page_bottom_view.dart';
export 'product_tab.dart';
export 'reviews_tab.dart';
export 'share_dialog.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import 'package:flutter/material.dart';

class ProductPageBottomView extends StatelessWidget {
final Function() addToCartFunction;
final Function() sharedFunction;

const ProductPageBottomView({@required this.addToCartFunction});
const ProductPageBottomView(
{@required this.addToCartFunction, this.sharedFunction});

@override
Widget build(BuildContext context) {
Expand All @@ -19,7 +21,7 @@ class ProductPageBottomView extends StatelessWidget {
Flexible(
child: SecondaryButtonWidget(
text: localization.shareThis,
onPressedFunction: () => {},
onPressedFunction: sharedFunction,
assetIcon: Assets.shareArrowIcon,
),
),
Expand Down
Loading