Skip to content

Commit

Permalink
Finish share intent, parsing images/text, sharing to calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
nickwu241 committed Apr 5, 2020
1 parent 0f0b7e8 commit 6e120df
Show file tree
Hide file tree
Showing 30 changed files with 646 additions and 43 deletions.
17 changes: 3 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
# app
# Save The Date

A new Flutter project.
Add events to your calendar from screenshots!

## Getting Started

This project is a starting point for a Flutter application.

A few resources to get you started if this is your first Flutter project:

- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)

For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
Icons are from [Icons8](https://icons8.com/).
5 changes: 4 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ if (flutterVersionName == null) {

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
// Firebase
apply plugin: 'com.google.gms.google-services'

apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
Expand All @@ -38,7 +41,7 @@ android {

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.app"
applicationId "wu.nick.savethedate"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
Expand Down
40 changes: 40 additions & 0 deletions android/app/google-services.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"project_info": {
"project_number": "122686998141",
"firebase_url": "https://save-the-date-tech.firebaseio.com",
"project_id": "save-the-date-tech",
"storage_bucket": "save-the-date-tech.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:122686998141:android:1c7209af80c9506a989314",
"android_client_info": {
"package_name": "wu.nick.savethedate"
}
},
"oauth_client": [
{
"client_id": "122686998141-c63hi59h3lrbfob0qq1daoo0leo5v5d9.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBHtVkpn2UEA2KrTwmDxoovAR58r6w6ZYM"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "122686998141-c63hi59h3lrbfob0qq1daoo0leo5v5d9.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
2 changes: 1 addition & 1 deletion android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
package="wu.nick.savethedate">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
18 changes: 17 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
package="wu.nick.savethedate">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
Expand All @@ -20,11 +20,27 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />

<!-- For Google OCR -->
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr" />

</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.app
package wu.nick.savethedate

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/profile/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
package="wu.nick.savethedate">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
2 changes: 2 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// Firebase
classpath 'com.google.gms:google-services:4.3.3'
}
}

Expand Down
1 change: 1 addition & 0 deletions android/settings_aar.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ':app'
Binary file added assets/calendar-24px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/calendar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/event-screenshot-original.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/event-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/event.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshot-100px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshot-26px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/share-100px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/share-24px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ end
target 'Runner' do
use_frameworks!
use_modular_headers!

# Flutter Pod

copied_flutter_dir = File.join(__dir__, 'Flutter')
Expand Down Expand Up @@ -65,6 +65,8 @@ target 'Runner' do
pod 'Flutter', :path => 'Flutter'

# Plugin Pods
# For Goolge OCR
pod 'Firebase/MLVisionTextModel'

# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
Expand Down
13 changes: 6 additions & 7 deletions lib/add_to_calendar.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'package:add_2_calendar/add_2_calendar.dart';
import 'package:save_the_date/models.dart';

Future<bool> addToCalendar(String title, DateTime startDate, DateTime endDate,
{String description: '', String location: ''}) {
Future<bool> addToCalendar(CalendarEvent calendarEvent) {
final event = Event(
title: title,
description: description,
location: location,
startDate: startDate,
endDate: endDate,
title: calendarEvent.title,
startDate: calendarEvent.startDate,
endDate: calendarEvent.endDate,
timeZone: DateTime.now().timeZoneName,
);

return Add2Calendar.addEvent2Cal(event);
Expand Down
19 changes: 19 additions & 0 deletions lib/handle_share_intent.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'dart:io';

import 'package:receive_sharing_intent/receive_sharing_intent.dart';

Future<void> handleTextShare() {
return ReceiveSharingIntent.getInitialText().then((data) {
print(data);
});
}

Future<File> handleImageShare() {
return ReceiveSharingIntent.getInitialMedia().then((data) {
if (data == null) {
throw 'no image file shared';
}
final f = File(data[0].path);
return f;
});
}
111 changes: 100 additions & 11 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,133 @@
import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:save_the_date/add_to_calendar.dart';
import 'package:save_the_date/handle_share_intent.dart';
import 'package:save_the_date/models.dart';
import 'package:save_the_date/parse_image_file.dart';
import 'package:save_the_date/widgets/onboarding_widget.dart';
import 'package:save_the_date/widgets/text_detector_painter.dart';

void main() => runApp(MyApp());

StreamController<bool> _shouldOnboardStreamController =
StreamController.broadcast();
Stream<bool> shouldOnboardStream = _shouldOnboardStreamController.stream;
Sink<bool> shouldOnboardSink = _shouldOnboardStreamController.sink;

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
bool eventAdded = false;
final _shouldOnboardStream = shouldOnboardStream;
bool _eventAdded = false;
bool _shouldShowTextDetectOverlay = false;
ParsedImageResult _parsedImageResult;
File _imageFile;

@override
void initState() {
super.initState();

// addToCalendar('test', DateTime(2020, 4, 7, 12), DateTime(2020, 4, 7, 13))
// .then(handleAddToCalendar);
handleImageShare()
.then(handleImageFile)
.then(handleParsedImageResult)
.then(handleEventAdded)
.catchError(handleError);
}

void handleAddToCalendar(bool eventAdded) {
Future<ParsedImageResult> handleImageFile(File imageFile) {
print('handleImageFile: got image: image.path=${imageFile.path}');
setState(() {
this.eventAdded = eventAdded;
_imageFile = imageFile;
shouldOnboardSink.add(false);
});
return parseImageFile(imageFile);
}

Future<bool> handleParsedImageResult(ParsedImageResult result) {
print('handleParsedImageResult: parsing results');
setState(() => _parsedImageResult = result);
if (result.calendarEvent == null) {
throw 'failed to parse calendarEvent';
}
return addToCalendar(result.calendarEvent);
}

Future<void> handleEventAdded(bool eventAdded) {
print('handleEventAdded: eventAdded=$eventAdded');
setState(() => this._eventAdded = eventAdded);
return Future.value(null);
}

void handleError(dynamic error) {
print('handelError: $error');
}

Widget _buildImage() {
if (_imageFile == null) {
return Container();
}

return Container(
constraints: const BoxConstraints.expand(),
decoration: BoxDecoration(
image: DecorationImage(
image: Image.file(_imageFile).image,
fit: BoxFit.fill,
),
),
child: _shouldShowTextDetectOverlay && _parsedImageResult != null
? CustomPaint(
painter: TextDetectorPainter(
_parsedImageResult.imageSize,
_parsedImageResult.visionText,
),
)
: Container(),
);
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Save The Date',
theme: ThemeData(
primarySwatch: Colors.blue,
primarySwatch: Colors.deepPurple,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text('Save The Date'),
actions: <Widget>[
if (_parsedImageResult != null)
IconButton(
icon: Icon(
_shouldShowTextDetectOverlay
? Icons.visibility_off
: Icons.visibility,
color: Colors.white,
),
onPressed: () {
setState(() {
_shouldShowTextDetectOverlay =
!_shouldShowTextDetectOverlay;
});
},
)
],
),
body: Center(
child: eventAdded
? Text('Event successfully added to calendar!')
: Text('Event failed to add to calendar.'),
body: StreamBuilder<bool>(
stream: _shouldOnboardStream,
initialData: true,
builder: (context, snapshot) {
if (snapshot.data) {
return OnboardingWidget();
}
return _buildImage();
},
),
),
);
Expand Down
19 changes: 19 additions & 0 deletions lib/models.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'dart:ui';

import 'package:firebase_ml_vision/firebase_ml_vision.dart';

class ParsedImageResult {
Size imageSize;
VisionText visionText;
CalendarEvent calendarEvent;

ParsedImageResult({this.imageSize, this.visionText, this.calendarEvent});
}

class CalendarEvent {
String title;
DateTime startDate;
DateTime endDate;

CalendarEvent({this.title, this.startDate, this.endDate});
}
Loading

0 comments on commit 6e120df

Please sign in to comment.