diff --git a/android/app/build.gradle b/android/app/build.gradle index 254e43d..e09710b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -13,7 +13,7 @@ if (flutterRoot == null) { def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { - flutterVersionCode = '1' + flutterVersionCode = '3' } def flutterVersionName = localProperties.getProperty('flutter.versionName') @@ -26,8 +26,15 @@ apply plugin: 'com.google.gms.google-services' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +rootProject.ext { + set('FlutterFire', [ + FirebaseSDKVersion: '25.12.0' + ]) +} + android { - compileSdkVersion 28 + compileSdkVersion 30 + buildToolsVersion '29.0.0' sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -44,6 +51,7 @@ android { targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } buildTypes { @@ -61,6 +69,8 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.google.firebase:firebase-dynamic-links' implementation platform('com.google.firebase:firebase-bom:26.6.0') implementation 'com.google.firebase:firebase-analytics' + implementation 'com.android.support:multidex:1.0.3' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d098a2f..82f2b00 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,12 +5,12 @@ In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + + + + + + + + + diff --git a/android/build.gradle b/android/build.gradle index c212aa0..fb488d5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath 'com.google.gms:google-services:4.3.5' - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 296b146..939efa2 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index d3b6a40..121d30d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,15 +1,15 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - include ':app' -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} \ No newline at end of file diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/lib/main.dart b/lib/main.dart index 952733d..760fb23 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -27,7 +27,7 @@ class MyApp extends StatelessWidget { routes: { '/dashboard': (BuildContext context) => Dashboard(), }, - home: Splash(), + home: Splash(initLink: true), ); } } diff --git a/lib/services/dynamicLink.dart b/lib/services/dynamicLink.dart new file mode 100644 index 0000000..769c812 --- /dev/null +++ b/lib/services/dynamicLink.dart @@ -0,0 +1,36 @@ +import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; +import 'package:flutter/material.dart'; + +class DynamicLinkService { + static Future createDynamicLink( + {int height, + String text, + String owner, + String image, + String seller, + String amount, + bool isProduct = false}) async { + final DynamicLinkParameters parameters = DynamicLinkParameters( + uriPrefix: 'https://relicbazaar.page.link', + // text: text, + // owner: owner, + // image: image, + // prodHeight: height, + // seller: seller, + // amount: amount, + link: isProduct + ? Uri.parse( + 'https://relicbazaar.page.link.com/?isProduct=$isProduct&text=$text&height=$height&image=$image&seller=$seller&amount=$amount&owner=$owner') + : Uri.parse( + 'https://relicbazaar.page.link.com/?isProduct=$isProduct'), + androidParameters: AndroidParameters( + packageName: 'com.example.retro_shopping', + ), + ); + Uri url; + final ShortDynamicLink shortLink = await parameters.buildShortLink(); + url = shortLink.shortUrl; + print(url); + return url; + } +} diff --git a/lib/widgets/product/product_page.dart b/lib/widgets/product/product_page.dart index bdfccf2..ffb591d 100644 --- a/lib/widgets/product/product_page.dart +++ b/lib/widgets/product/product_page.dart @@ -1,7 +1,13 @@ +import 'dart:io'; + +import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:retro_shopping/helpers/constants.dart'; import '../../helpers/app_icons.dart'; +import 'package:retro_shopping/services/dynamicLink.dart'; import '../retro_button.dart'; // ignore: must_be_immutable @@ -25,6 +31,36 @@ class ProductPage extends StatefulWidget { } class _ProductPageState extends State { + Uri uri; + @override + void initState() { + super.initState(); + _getUrl(); + } + + Future _getUrl() async { + uri = await DynamicLinkService.createDynamicLink( + isProduct: true, + text: widget.text, + image: widget.image, + owner: widget.owner, + seller: widget.seller, + height: widget.prodHeight, + amount: widget.amount); + } + + Future _shareWithImage() async { + try { + var bytes = await rootBundle.load(widget.image); + await Share.file('${widget.text}', '${widget.text}.png', + bytes.buffer.asUint8List(), 'image/png', + text: + 'Checkout this amazing product ${widget.text} on ${uri.toString()}'); + } catch (err) { + print(err); + } + } + @override Widget build(BuildContext context) { final double height = MediaQuery.of(context).size.height; @@ -329,7 +365,7 @@ class _ProductPageState extends State { ), ), Transform.translate( - offset: const Offset(145, 375), + offset: Offset(80, 375), child: Row( children: [ RetroButton( @@ -338,13 +374,30 @@ class _ProductPageState extends State { width: width * 0.12, height: height * 0.05, borderColor: Colors.white, - child: const Center( - child: Icon( - Icons.favorite, - color: RelicColors.primaryColor, + ), + ], + ), + ), + Transform.translate( + offset: Offset(145, 375), + child: Row( + children: [ + InkWell( + onTap: _shareWithImage, + child: RetroButton( + child: Center( + child: Icon( + Icons.share, + color: RelicColors.primaryColor, + ), ), + upperColor: Colors.white, + lowerColor: Colors.black, + width: width * 0.12, + height: height * 0.05, + borderColor: Colors.white, ), - ) + ), ], ), ), diff --git a/lib/widgets/splash.dart b/lib/widgets/splash.dart index f905bfb..37d4b10 100644 --- a/lib/widgets/splash.dart +++ b/lib/widgets/splash.dart @@ -1,7 +1,13 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; +import 'package:retro_shopping/helpers/slide_route.dart'; +import 'package:retro_shopping/widgets/product/product_page.dart'; +import 'package:firebase_core/firebase_core.dart'; class Splash extends StatefulWidget { + final bool initLink; + Splash({this.initLink}); @override _SplashState createState() => _SplashState(); } @@ -10,16 +16,66 @@ class _SplashState extends State { @override void initState() { super.initState(); - startTime(); + _initLink(); } - Future startTime() async { - const Duration _duration = Duration(seconds: 3); - return Timer(_duration, navigationPage); + @override + void dispose() { + super.dispose(); + } + + Future initDynamicLinks() async { + final PendingDynamicLinkData data = + await FirebaseDynamicLinks.instance.getInitialLink(); + if (data == null) { + Navigator.of(context).pushReplacementNamed('/dashboard'); + } + + await _handleDeepLink(data); + + // Register a link callback to fire if the app is opened up from the background + // using a dynamic link. + FirebaseDynamicLinks.instance.onLink( + onSuccess: (PendingDynamicLinkData dynamicLink) async { + // handle link that has been retrieved + await _handleDeepLink(dynamicLink); + }, onError: (OnLinkErrorException e) async { + print('Link Failed: ${e.message}'); + }); + } + + Future _handleDeepLink(PendingDynamicLinkData data) async { + final Uri deepLink = data?.link; + if (deepLink != null) { + if (deepLink.queryParameters['isProduct'] == 'true') { + Navigator.of(context).pushReplacementNamed('/dashboard'); + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => ProductPage( + text: deepLink.queryParameters['text'], + owner: deepLink.queryParameters['owner'], + image: deepLink.queryParameters['image'], + prodHeight: + int.tryParse(deepLink.queryParameters['height']), + seller: deepLink.queryParameters['seller'], + amount: deepLink.queryParameters['amount'], + ))); + } + } } - void navigationPage() { - Navigator.of(context).pushReplacementNamed('/dashboard'); + _initLink() async { + Future.delayed( + Duration(milliseconds: 300), + () async { + if (widget.initLink) + await initDynamicLinks(); + else { + Navigator.of(context).pushReplacementNamed('/dashboard'); + } + }, + ); } @override diff --git a/pubspec.yaml b/pubspec.yaml index d33be2d..6e51dab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,13 +29,17 @@ dependencies: adobe_xd: ^1.1.0+1 cupertino_icons: ^0.1.3 fluttertoast: ^7.1.8 - firebase_core: ^1.0.0 + firebase_dynamic_links: ^0.6.3 + esys_flutter_share: ^1.0.2 + + + firebase_core: ^0.5.3 google_fonts: ^1.1.0 razorpay_flutter: 1.1.0 dependency_overrides: - flutter_svg: ^0.20.0-nullsafety.3 + flutter_svg: 0.19.3 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index dca3efe..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:retro_shopping/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}