├── iOS ├── Resources │ ├── event.png │ ├── event@2x.png │ ├── event@3x.png │ ├── Images.xcassets │ │ └── AppIcons.appiconset │ │ │ ├── Icon@2x.png │ │ │ ├── Icon@3x.png │ │ │ ├── Icon-Settings.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ ├── Icon-Settings@2x.png │ │ │ ├── Icon-Settings@3x.png │ │ │ └── Contents.json │ └── LaunchScreen.storyboard ├── Entitlements.plist ├── Custom Controls │ ├── NotifyButton.designer.cs │ └── NotifyButton.cs ├── Main.cs ├── packages.config ├── Helpers │ ├── Share.cs │ ├── Utils.cs │ ├── MessageDialog.cs │ ├── ViewExtensions.cs │ └── ReminderService.cs ├── Info.plist ├── PluginsHelp │ └── SettingsReadme.txt ├── AppDelegate.cs ├── BaseViewController.cs ├── ViewController.designer.cs ├── ViewController.cs ├── SaveTheDate.iOS.csproj └── Main.storyboard ├── Screenshots └── SaveTheDate.png ├── Droid ├── Resources │ ├── drawable-hdpi │ │ ├── event.png │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ ├── event.png │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ ├── event.png │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ ├── event.png │ │ └── ic_launcher.png │ ├── drawable-xxxhdpi │ │ └── ic_launcher.png │ ├── values │ │ ├── Strings.xml │ │ ├── colors.xml │ │ └── styles.xml │ ├── values-v21 │ │ └── styles.xml │ ├── AboutResources.txt │ └── layout │ │ └── Main.axml ├── DeviceInfoReadme.txt ├── Helpers │ ├── AndroidUtils.cs │ ├── Share.cs │ ├── MessageDialog.cs │ └── ReminderService.cs ├── Assets │ └── AboutAssets.txt ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs ├── packages.config ├── PluginsHelp │ └── SettingsReadme.txt ├── MainActivity.cs └── SaveTheDate.Droid.csproj ├── UITests ├── packages.config ├── AppInitializer.cs ├── UITests.csproj └── Tests.cs ├── SaveTheDate ├── Interfaces │ ├── IShare.cs │ ├── IMessage.cs │ └── IReminderService.cs ├── DeviceInfoReadme.txt ├── Helpers │ ├── Strings.cs │ ├── Utils.cs │ └── Settings.cs ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── RegexUtils.cs ├── SaveTheDateHelper.cs └── SaveTheDate.csproj ├── README.md ├── SaveTheDate.userprefs ├── LICENSE ├── .gitignore └── SaveTheDate.sln /iOS/Resources/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/event.png -------------------------------------------------------------------------------- /iOS/Resources/event@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/event@2x.png -------------------------------------------------------------------------------- /iOS/Resources/event@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/event@3x.png -------------------------------------------------------------------------------- /Screenshots/SaveTheDate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Screenshots/SaveTheDate.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-hdpi/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-hdpi/event.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-mdpi/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-mdpi/event.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-xhdpi/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-xhdpi/event.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-xxhdpi/event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-xxhdpi/event.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Droid/Resources/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/Droid/Resources/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon@3x.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings@2x.png -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/SaveTheDate/HEAD/iOS/Resources/Images.xcassets/AppIcons.appiconset/Icon-Settings@3x.png -------------------------------------------------------------------------------- /Droid/Resources/values/Strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello World, Click Me! 4 | SaveTheDate.Droid 5 | 6 | -------------------------------------------------------------------------------- /iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /UITests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /SaveTheDate/Interfaces/IShare.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SaveTheDate.Interfaces 4 | { 5 | public interface IShare 6 | { 7 | void ShareText(string text); 8 | string GetEmail(); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Droid/DeviceInfoReadme.txt: -------------------------------------------------------------------------------- 1 | Devic Info Readme 2 | Find the most up to date information at: https://github.com/jamesmontemagno/Xamarin.Plugins 3 | 4 | **IMPORTANT** 5 | 6 | 7 | Windows Phone: 8 | Permissions to add: 9 | ID_CAP_IDENTITY_DEVICE -------------------------------------------------------------------------------- /SaveTheDate/DeviceInfoReadme.txt: -------------------------------------------------------------------------------- 1 | Devic Info Readme 2 | Find the most up to date information at: https://github.com/jamesmontemagno/Xamarin.Plugins 3 | 4 | **IMPORTANT** 5 | 6 | 7 | Windows Phone: 8 | Permissions to add: 9 | ID_CAP_IDENTITY_DEVICE -------------------------------------------------------------------------------- /SaveTheDate/Helpers/Strings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SaveTheDate.Helpers 4 | { 5 | public static class Strings 6 | { 7 | public static readonly string ShareText = "I can't wait for EVENT in LOCATION on DATE: http://yoururl. Save the date now!"; 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /Droid/Helpers/AndroidUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Android.App; 3 | using Android.Views; 4 | 5 | namespace SaveTheDate.Droid.Helpers 6 | { 7 | public static partial class AndroidUtils 8 | { 9 | public static Activity Context { get; set; } 10 | public static View SnackbarView {get;set;} 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /SaveTheDate/Interfaces/IMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SaveTheDate.Interfaces 4 | { 5 | public interface IMessage 6 | { 7 | void SendMessage(string message, string title = null); 8 | void SendToast(string message); 9 | void SendConfirmation(string message, string title, Action confirmationAction); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /SaveTheDate/Helpers/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SaveTheDate.Interfaces; 3 | 4 | namespace SaveTheDate.Helpers 5 | { 6 | public static partial class Utils 7 | { 8 | public static IShare Sharer { get; set; } 9 | public static IReminderService Reminder { get; set; } 10 | public static IMessage Message { get; set; } 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /SaveTheDate/Interfaces/IReminderService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SaveTheDate.Interfaces 4 | { 5 | public interface IReminderService 6 | { 7 | void AddEvent(DateTime startTime, DateTime endTime, string title, string location, string message, Actioncallback, string id); 8 | bool EventExists(DateTime startTime, string title, string id); 9 | void RemoveEvent(DateTime startDate, string title, string id); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /iOS/Custom Controls/NotifyButton.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio from the outlets and 4 | // actions declared in your storyboard file. 5 | // Manual changes to this file will not be maintained. 6 | // 7 | using Foundation; 8 | using System; 9 | using System.CodeDom.Compiler; 10 | using UIKit; 11 | 12 | namespace SaveTheDate.iOS.CustomControls 13 | { 14 | [Register ("NotifyButton")] 15 | partial class NotifyButton 16 | { 17 | void ReleaseDesignerOutlets () 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace SaveTheDate.iOS 9 | { 10 | public class Application 11 | { 12 | // This is the main entry point of the application. 13 | static void Main(string[] args) 14 | { 15 | // if you want to use a different Application Delegate class from "AppDelegate" 16 | // you can specify it here. 17 | UIApplication.Main(args, null, "AppDelegate"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Droid/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #03A9F4 5 | #0D1A32 6 | #FFC107 7 | #B3E5FC 8 | #FFFFFF 9 | #212121 10 | #727272 11 | #B6B6B6 12 | #E8E8E8 13 | -------------------------------------------------------------------------------- /Droid/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with your package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /iOS/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Droid/Resources/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | -------------------------------------------------------------------------------- /Droid/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Save The Date 2 | ============= 3 | 4 | This pre-built template enables you to easily allow attendees of your conference to register for notifications of your upcoming event. They can easily add the event to their calendar and share it with their friends. 5 | 6 | ![](Screenshots/SaveTheDate.png) 7 | 8 | ## Customization 9 | Simply update the **RegisterForNotifications** method in SaveTheDateHelper.cs to register the user's email address in your backend system. Then just update your events name, logo, and date! 10 | 11 | This mobile app is brought to you by your friends at [Xamarin](http://www.xamarin.com/). 12 | 13 | ### Authors: 14 | - [James Montemagno](http://github.com/jamesmontemagno): [Twitter](http://twitter.com/jamesmontemagno) | [Blog](http://motzcod.es) 15 | - [Mike James](http://github.com/MikeCodesDotNet): [Twitter](http://twitter.com/mikecodesdotnet) | [Blog](http://mikecodes.net) 16 | -------------------------------------------------------------------------------- /Droid/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /SaveTheDate.userprefs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /SaveTheDate/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /iOS/Helpers/Share.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SaveTheDate.Interfaces; 3 | using Foundation; 4 | using UIKit; 5 | 6 | namespace SaveTheDate.iOS.Helpers 7 | { 8 | public class Share : IShare 9 | { 10 | public static UIViewController ViewController {get;set;} 11 | public async void ShareText (string text) 12 | { 13 | try 14 | { 15 | var items = new NSObject[] { new NSString (text) }; 16 | var activityController = new UIActivityViewController (items, null); 17 | var vc = ViewController ?? UIApplication.SharedApplication.KeyWindow.RootViewController; 18 | await vc.PresentViewControllerAsync (activityController, true); 19 | } 20 | catch(Exception ex) 21 | { 22 | Xamarin.Insights.Report(ex); 23 | } 24 | } 25 | 26 | 27 | public string GetEmail () 28 | { 29 | return string.Empty; 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /iOS/Helpers/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Foundation; 3 | 4 | namespace SaveTheDate.iOS.Helpers 5 | { 6 | public static class Utils 7 | { 8 | public static NSObject Invoker; 9 | /// 10 | /// Ensures the invoked on main thread. 11 | /// 12 | /// Action to run on main thread. 13 | public static void EnsureInvokedOnMainThread (Action action) 14 | { 15 | if (NSThread.Current.IsMainThread) { 16 | action (); 17 | return; 18 | } 19 | if (Invoker == null) 20 | Invoker = new NSObject (); 21 | 22 | Invoker.BeginInvokeOnMainThread(action); 23 | } 24 | 25 | public static NSDate ToNSDate(this DateTime date) 26 | { 27 | if (date.Kind == DateTimeKind.Unspecified) 28 | date = DateTime.SpecifyKind(date, DateTimeKind.Utc); 29 | 30 | return (NSDate) date; 31 | } 32 | 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /SaveTheDate/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("SaveTheDate")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("jamesmontemagno")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | 28 | -------------------------------------------------------------------------------- /Droid/Helpers/Share.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Android.Accounts; 3 | using Android.Util; 4 | using Android.Content; 5 | using SaveTheDate.Interfaces; 6 | using SaveTheDate.Helpers; 7 | 8 | namespace SaveTheDate.Droid.Helpers 9 | { 10 | public class Share : IShare 11 | { 12 | public void ShareText (string text) 13 | { 14 | var intent = new Intent (Intent.ActionSend); 15 | intent.SetType ("text/plain"); 16 | intent.PutExtra (Intent.ExtraText, text); 17 | AndroidUtils.Context.StartActivity (Intent.CreateChooser (intent, "Share Event")); 18 | } 19 | 20 | 21 | 22 | public string GetEmail () 23 | { 24 | var emailPattern = Patterns.EmailAddress; // API level 8+ 25 | var accounts = AccountManager.Get (AndroidUtils.Context).GetAccounts (); 26 | foreach (var account in accounts) { 27 | if (emailPattern.Matcher (account.Name).Matches ()) { 28 | return account.Name; 29 | } 30 | } 31 | 32 | return string.Empty; 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /UITests/AppInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using Xamarin.UITest; 5 | using Xamarin.UITest.Queries; 6 | 7 | namespace UITests 8 | { 9 | public class AppInitializer 10 | { 11 | public static IApp StartApp(Platform platform) 12 | { 13 | // TODO: If the iOS or Android app being tested is included in the solution 14 | // then open the Unit Tests window, right click Test Apps, select Add App Project 15 | // and select the app projects that should be tested. 16 | if (platform == Platform.Android) 17 | { 18 | return ConfigureApp 19 | .Android 20 | // TODO: Update this path to point to your Android app and uncomment the 21 | // code if the app is not included in the solution. 22 | .ApkFile ("../../../Droid/bin/Debug/com.company.SaveTheDate.apk") 23 | .StartApp(); 24 | } 25 | 26 | return ConfigureApp.iOS.AppBundle("../../../iOS/bin/iPhoneSimulator/Debug/SaveTheDateiOS.app").StartApp(); 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Xamarin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Droid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using Android.App; 4 | 5 | // Information about this assembly is defined by the following attributes. 6 | // Change them to the values specific to your project. 7 | 8 | [assembly: AssemblyTitle("SaveTheDate.Droid")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("")] 13 | [assembly: AssemblyCopyright("jamesmontemagno")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 18 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 19 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 20 | 21 | [assembly: AssemblyVersion("1.0.0")] 22 | 23 | // The following attributes are used to specify the signing key for the assembly, 24 | // if desired. See the Mono documentation for more information about signing. 25 | 26 | //[assembly: AssemblyDelaySign(false)] 27 | //[assembly: AssemblyKeyFile("")] 28 | 29 | -------------------------------------------------------------------------------- /iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSRequiresIPhoneOS 6 | 7 | MinimumOSVersion 8 | 8.0 9 | UIDeviceFamily 10 | 11 | 1 12 | 13 | UILaunchStoryboardName 14 | LaunchScreen 15 | UIMainStoryboardFile 16 | Main 17 | UIRequiredDeviceCapabilities 18 | 19 | armv7 20 | 21 | UISupportedInterfaceOrientations 22 | 23 | UIInterfaceOrientationPortrait 24 | 25 | XSAppIconAssets 26 | Resources/Images.xcassets/AppIcons.appiconset 27 | UIStatusBarStyle 28 | UIStatusBarStyleLightContent 29 | UIViewControllerBasedStatusBarAppearance 30 | 31 | CFBundleIdentifier 32 | com.company.savethedate 33 | CFBundleDisplayName 34 | Save The Date 35 | CFBundleShortVersionString 36 | 1.0 37 | CFBundleVersion 38 | 1.0 39 | 40 | 41 | -------------------------------------------------------------------------------- /iOS/Custom Controls/NotifyButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UIKit; 3 | using CoreGraphics; 4 | using Foundation; 5 | using System.ComponentModel; 6 | 7 | namespace SaveTheDate.iOS.CustomControls 8 | { 9 | [Register("NotifyButton"), DesignTimeVisible(true)] 10 | public class NotifyButton : UIButton 11 | { 12 | public NotifyButton(IntPtr handle) 13 | : base(handle) 14 | { 15 | Initialize(); 16 | } 17 | 18 | public void Initialize() 19 | { 20 | this.SetTitleColor(UIColor.White, UIControlState.Normal); 21 | this.SetTitleColor(UIColor.FromRGB(73, 96, 134), UIControlState.Disabled); 22 | } 23 | 24 | public override bool Enabled 25 | { 26 | get 27 | { 28 | return base.Enabled; 29 | } 30 | set 31 | { 32 | borderColor = value == true ? UIColor.White.CGColor : UIColor.FromRGB(73, 96, 134).CGColor; 33 | SetNeedsDisplay(); 34 | base.Enabled = value; 35 | } 36 | } 37 | 38 | CGColor borderColor = UIColor.White.CGColor; 39 | 40 | 41 | public override void Draw(CoreGraphics.CGRect rect) 42 | { 43 | Layer.BorderColor = borderColor; 44 | Layer.BorderWidth = 1; 45 | Layer.CornerRadius = Frame.Height / 2; 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Droid/PluginsHelp/SettingsReadme.txt: -------------------------------------------------------------------------------- 1 | Ensure that you install NuGet into PCL and see Helpers/Settings.cs 2 | 3 | If you are installing this in a normal project and not using a pcl create a new file called Settings.cs or whatever you want and copy this code in: 4 | 5 | 6 | // Helpers/Settings.cs 7 | using Refractored.Xam.Settings; 8 | using Refractored.Xam.Settings.Abstractions; 9 | 10 | namespace SaveTheDate.Droid.Helpers 11 | { 12 | /// 13 | /// This is the Settings static class that can be used in your Core solution or in any 14 | /// of your client applications. All settings are laid out the same exact way with getters 15 | /// and setters. 16 | /// 17 | public static class Settings 18 | { 19 | private static ISettings AppSettings 20 | { 21 | get 22 | { 23 | return CrossSettings.Current; 24 | } 25 | } 26 | 27 | #region Setting Constants 28 | 29 | private const string SettingsKey = "settings_key"; 30 | private static readonly string SettingsDefault = string.Empty; 31 | 32 | #endregion 33 | 34 | 35 | public static string GeneralSettings 36 | { 37 | get 38 | { 39 | return AppSettings.GetValueOrDefault(SettingsKey, SettingsDefault); 40 | } 41 | set 42 | { 43 | AppSettings.AddOrUpdateValue(SettingsKey, value); 44 | } 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /iOS/PluginsHelp/SettingsReadme.txt: -------------------------------------------------------------------------------- 1 | Ensure that you install NuGet into PCL and see Helpers/Settings.cs 2 | 3 | If you are installing this in a normal project and not using a pcl create a new file called Settings.cs or whatever you want and copy this code in: 4 | 5 | 6 | // Helpers/Settings.cs 7 | using Refractored.Xam.Settings; 8 | using Refractored.Xam.Settings.Abstractions; 9 | 10 | namespace SaveTheDate.iOS.Helpers 11 | { 12 | /// 13 | /// This is the Settings static class that can be used in your Core solution or in any 14 | /// of your client applications. All settings are laid out the same exact way with getters 15 | /// and setters. 16 | /// 17 | public static class Settings 18 | { 19 | private static ISettings AppSettings 20 | { 21 | get 22 | { 23 | return CrossSettings.Current; 24 | } 25 | } 26 | 27 | #region Setting Constants 28 | 29 | private const string SettingsKey = "settings_key"; 30 | private static readonly string SettingsDefault = string.Empty; 31 | 32 | #endregion 33 | 34 | 35 | public static string GeneralSettings 36 | { 37 | get 38 | { 39 | return AppSettings.GetValueOrDefault(SettingsKey, SettingsDefault); 40 | } 41 | set 42 | { 43 | AppSettings.AddOrUpdateValue(SettingsKey, value); 44 | } 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Droid/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /Droid/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.axml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable/ 12 | icon.png 13 | 14 | layout/ 15 | main.axml 16 | 17 | values/ 18 | strings.xml 19 | 20 | In order to get the build system to recognize Android resources, set the build action to 21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 22 | instead operate on resource IDs. When you compile an Android application that uses resources, 23 | the build system will package the resources for distribution and generate a class called "R" 24 | (this is an Android convention) that contains the tokens for each one of the resources 25 | included. For example, for the above Resources layout, this is what the R class would expose: 26 | 27 | public class R { 28 | public class drawable { 29 | public const int icon = 0x123; 30 | } 31 | 32 | public class layout { 33 | public const int main = 0x456; 34 | } 35 | 36 | public class strings { 37 | public const int first_string = 0xabc; 38 | public const int second_string = 0xbcd; 39 | } 40 | } 41 | 42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first 44 | string in the dictionary file values/strings.xml. 45 | -------------------------------------------------------------------------------- /iOS/Helpers/MessageDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UIKit; 3 | using SaveTheDate.Interfaces; 4 | using GCDiscreetNotification; 5 | 6 | namespace SaveTheDate.iOS.Helpers 7 | { 8 | public class MessageDialog : IMessage 9 | { 10 | 11 | public void SendMessage(string message, string title = null) 12 | { 13 | Utils.EnsureInvokedOnMainThread(() => 14 | { 15 | var alertView = new UIAlertView(title ?? string.Empty, message, null, "OK"); 16 | alertView.Show(); 17 | }); 18 | } 19 | 20 | 21 | public void SendToast(string message) 22 | { 23 | Utils.EnsureInvokedOnMainThread(() => 24 | { 25 | var notificationView = new GCDiscreetNotificationView( 26 | text: message, 27 | activity: false, 28 | presentationMode: GCDNPresentationMode.Bottom, 29 | view: UIApplication.SharedApplication.KeyWindow 30 | ); 31 | 32 | notificationView.ShowAndDismissAfter(4); 33 | }); 34 | } 35 | 36 | public void SendConfirmation(string message, string title, System.Action confirmationAction) 37 | { 38 | Utils.EnsureInvokedOnMainThread(() => 39 | { 40 | var alertView = new UIAlertView(title ?? string.Empty, message, null, "OK", "Cancel"); 41 | alertView.Clicked += (sender, e) => 42 | { 43 | confirmationAction(e.ButtonIndex == 0); 44 | }; 45 | alertView.Show(); 46 | }); 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /UITests/UITests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {F69E4794-C0E5-441D-BDE3-8D40A18B1E54} 7 | Library 8 | UITests 9 | UITests 10 | v4.5 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug 17 | DEBUG; 18 | prompt 19 | 4 20 | false 21 | 22 | 23 | full 24 | true 25 | bin\Release 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | false 32 | bin\iPhone\AppStore 33 | 4 34 | 35 | 36 | 37 | 38 | ..\packages\Xamarin.UITest.1.0.0\lib\Xamarin.UITest.dll 39 | 40 | 41 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /iOS/Helpers/ViewExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UIKit; 3 | 4 | namespace SaveTheDate.iOS.Helpers 5 | { 6 | public static class ViewExtensions 7 | { 8 | /// 9 | /// Find the first responder in the 's subview hierarchy 10 | /// 11 | /// 12 | /// A 13 | /// 14 | /// 15 | /// A that is the first responder or null if there is no first responder 16 | /// 17 | public static UIView FindFirstResponder(this UIView view) 18 | { 19 | if (view.IsFirstResponder) 20 | { 21 | return view; 22 | } 23 | foreach (UIView subView in view.Subviews) 24 | { 25 | var firstResponder = subView.FindFirstResponder(); 26 | if (firstResponder != null) 27 | return firstResponder; 28 | } 29 | return null; 30 | } 31 | 32 | /// 33 | /// Find the first Superview of the specified type (or descendant of) 34 | /// 35 | /// 36 | /// A 37 | /// 38 | /// 39 | /// A that indicates where to stop looking up the superview hierarchy 40 | /// 41 | /// 42 | /// A to look for, this should be a UIView or descendant type 43 | /// 44 | /// 45 | /// A if it is found, otherwise null 46 | /// 47 | public static UIView FindSuperviewOfType(this UIView view, UIView stopAt, Type type) 48 | { 49 | if (view.Superview != null) 50 | { 51 | if (type.IsAssignableFrom(view.Superview.GetType())) 52 | { 53 | return view.Superview; 54 | } 55 | 56 | if (view.Superview != stopAt) 57 | return view.Superview.FindSuperviewOfType(stopAt, type); 58 | } 59 | 60 | return null; 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Droid/Helpers/MessageDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Android.App; 3 | using Android.Widget; 4 | using SaveTheDate.Interfaces; 5 | using Android.Support.Design.Widget; 6 | 7 | namespace SaveTheDate.Droid.Helpers 8 | { 9 | public class MessageDialog : IMessage 10 | { 11 | 12 | public static void SendMessage(Activity activity, string message, string title = null) 13 | { 14 | var builder = new AlertDialog.Builder(activity); 15 | builder 16 | .SetTitle(title ?? string.Empty) 17 | .SetMessage(message) 18 | .SetPositiveButton(Android.Resource.String.Ok, delegate 19 | { 20 | 21 | }); 22 | 23 | AlertDialog alert = builder.Create(); 24 | alert.Show(); 25 | } 26 | 27 | public void SendMessage(string message, string title = null) 28 | { 29 | var activity = AndroidUtils.Context as Activity; 30 | var builder = new AlertDialog.Builder(activity); 31 | builder 32 | .SetTitle(title ?? string.Empty) 33 | .SetMessage(message) 34 | .SetPositiveButton(Android.Resource.String.Ok, delegate 35 | { 36 | 37 | }); 38 | 39 | AlertDialog alert = builder.Create(); 40 | alert.Show(); 41 | } 42 | 43 | 44 | public void SendToast(string message) 45 | { 46 | Snackbar.Make (AndroidUtils.SnackbarView, message, Snackbar.LengthLong) 47 | .SetAction ("OK", (v) => { }) 48 | .Show (); 49 | 50 | } 51 | 52 | 53 | public void SendConfirmation(string message, string title, System.Action confirmationAction) 54 | { 55 | var activity = AndroidUtils.Context as Activity; 56 | var builder = new Android.Support.V7.App.AlertDialog.Builder(activity); 57 | builder 58 | .SetTitle(title ?? string.Empty) 59 | .SetMessage(message) 60 | .SetPositiveButton(Android.Resource.String.Ok, delegate 61 | { 62 | confirmationAction(true); 63 | }).SetNegativeButton(Android.Resource.String.Cancel, delegate 64 | { 65 | confirmationAction(false); 66 | }); 67 | 68 | var alert = builder.Create(); 69 | alert.Show(); 70 | } 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /SaveTheDate/Helpers/Settings.cs: -------------------------------------------------------------------------------- 1 | // Helpers/Settings.cs 2 | using Refractored.Xam.Settings; 3 | using Refractored.Xam.Settings.Abstractions; 4 | 5 | namespace SaveTheDate.Helpers 6 | { 7 | /// 8 | /// This is the Settings static class that can be used in your Core solution or in any 9 | /// of your client applications. All settings are laid out the same exact way with getters 10 | /// and setters. 11 | /// 12 | public static class Settings 13 | { 14 | static ISettings AppSettings 15 | { 16 | get 17 | { 18 | return CrossSettings.Current; 19 | } 20 | } 21 | 22 | #region Setting Constants 23 | 24 | const string RegisteredKey = "registered_key"; 25 | const bool RegisteredDefault = false; 26 | const string RegisteredEmailKey = "registered_email_key"; 27 | static readonly string RegisteredEmailDefault = string.Empty; 28 | const string CalendarKey = "calendar_key"; 29 | const bool CalendarDefault = false; 30 | 31 | #endregion 32 | public static long GetEventId(string id) 33 | { 34 | return AppSettings.GetValueOrDefault (id, (long)-1); 35 | } 36 | 37 | public static void AddEventId(string id, long eventId) 38 | { 39 | AppSettings.AddOrUpdateValue(id, eventId); 40 | } 41 | 42 | public static bool IsRegistered 43 | { 44 | get 45 | { 46 | return AppSettings.GetValueOrDefault(RegisteredKey, RegisteredDefault); 47 | } 48 | set 49 | { 50 | AppSettings.AddOrUpdateValue(RegisteredKey, value); 51 | } 52 | } 53 | 54 | public static string RegisteredEmail 55 | { 56 | get 57 | { 58 | return AppSettings.GetValueOrDefault(RegisteredEmailKey, RegisteredEmailDefault); 59 | } 60 | set 61 | { 62 | AppSettings.AddOrUpdateValue(RegisteredEmailKey, value); 63 | } 64 | } 65 | 66 | public static bool AddedToCalendar 67 | { 68 | get 69 | { 70 | return AppSettings.GetValueOrDefault(CalendarKey, CalendarDefault); 71 | } 72 | set 73 | { 74 | AppSettings.AddOrUpdateValue(CalendarKey, value); 75 | } 76 | } 77 | 78 | } 79 | } -------------------------------------------------------------------------------- /SaveTheDate/RegexUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace SaveTheDate 5 | { 6 | public static class RegexUtilities 7 | { 8 | 9 | public static bool IsValidEmail(this string strIn) 10 | { 11 | if (String.IsNullOrEmpty(strIn)) 12 | return false; 13 | 14 | // Return true if strIn is in valid e-mail format. 15 | try { 16 | return Regex.IsMatch(strIn, 17 | @"^(?("")("".+?(?\d{3}) # 3 digit area code 37 | (?:[\).]?) # Optional ) or . 38 | (?\d{3}) # Prefix 39 | (?:[-\.]?) # optional - or . 40 | (?\d{4}) # Suffix 41 | (?!\d) # Fail if eleventh number found"; 42 | 43 | return Regex.IsMatch(strIn, pattern,RegexOptions.IgnorePatternWhitespace, TimeSpan.FromMilliseconds(250)); 44 | } 45 | catch (RegexMatchTimeoutException) { 46 | return false; 47 | } 48 | } 49 | 50 | public static bool IsValidPin(this string strIn) 51 | { 52 | if (String.IsNullOrEmpty(strIn) || strIn.Length != 6) 53 | return false; 54 | 55 | // Return true if strIn is in valid e-mail format. 56 | try { 57 | return Regex.IsMatch(strIn, @"^[0-9]+$",RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)); 58 | } 59 | catch (RegexMatchTimeoutException) { 60 | return false; 61 | } 62 | } 63 | 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /iOS/Resources/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using UIKit; 3 | using SaveTheDate.Helpers; 4 | 5 | namespace SaveTheDate.iOS 6 | { 7 | // The UIApplicationDelegate for the application. This class is responsible for launching the 8 | // User Interface of the application, as well as listening (and optionally responding) to application events from iOS. 9 | [Register("AppDelegate")] 10 | public class AppDelegate : UIApplicationDelegate 11 | { 12 | // class-level declarations 13 | 14 | public override UIWindow Window 15 | { 16 | get; 17 | set; 18 | } 19 | 20 | public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) 21 | { 22 | // Override point for customization after application launch. 23 | // If not required for your application you can safely delete this method 24 | 25 | //Xamarin.Calabash.Start(); 26 | 27 | UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false); 28 | Xamarin.Insights.Initialize(Xamarin.Insights.DebugModeKey); 29 | if(!string.IsNullOrWhiteSpace(Settings.RegisteredEmail)) 30 | Xamarin.Insights.Identify(Settings.RegisteredEmail, Xamarin.Insights.Traits.Email, Settings.RegisteredEmail); 31 | 32 | 33 | return true; 34 | } 35 | 36 | public override void OnResignActivation(UIApplication application) 37 | { 38 | // Invoked when the application is about to move from active to inactive state. 39 | // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) 40 | // or when the user quits the application and it begins the transition to the background state. 41 | // Games should use this method to pause the game. 42 | } 43 | 44 | public override void DidEnterBackground(UIApplication application) 45 | { 46 | // Use this method to release shared resources, save user data, invalidate timers and store the application state. 47 | // If your application supports background exection this method is called instead of WillTerminate when the user quits. 48 | } 49 | 50 | public override void WillEnterForeground(UIApplication application) 51 | { 52 | // Called as part of the transiton from background to active state. 53 | // Here you can undo many of the changes made on entering the background. 54 | } 55 | 56 | public override void OnActivated(UIApplication application) 57 | { 58 | // Restart any tasks that were paused (or not yet started) while the application was inactive. 59 | // If the application was previously in the background, optionally refresh the user interface. 60 | } 61 | 62 | public override void WillTerminate(UIApplication application) 63 | { 64 | // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. 65 | } 66 | } 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /iOS/BaseViewController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UIKit; 3 | using Foundation; 4 | using CoreGraphics; 5 | using SaveTheDate.iOS.Helpers; 6 | 7 | namespace SaveTheDate.iOS 8 | { 9 | public class BaseViewController : UIViewController 10 | { 11 | public BaseViewController(IntPtr handle) 12 | : base(handle) 13 | { 14 | } 15 | 16 | #region ManageTheKeyboard 17 | 18 | NSObject _keyboardShowObserver; 19 | NSObject _keyboardHideObserver; 20 | 21 | protected virtual void RegisterForKeyboardNotifications() 22 | { 23 | if (_keyboardShowObserver == null) 24 | _keyboardShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification); 25 | if (_keyboardHideObserver == null) 26 | _keyboardHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, OnKeyboardNotification); 27 | } 28 | 29 | protected virtual void UnregisterForKeyboardNotifications() 30 | { 31 | if (_keyboardShowObserver != null) 32 | { 33 | NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardShowObserver); 34 | _keyboardShowObserver.Dispose(); 35 | _keyboardShowObserver = null; 36 | } 37 | 38 | if (_keyboardHideObserver != null) 39 | { 40 | NSNotificationCenter.DefaultCenter.RemoveObserver(_keyboardHideObserver); 41 | _keyboardHideObserver.Dispose(); 42 | _keyboardHideObserver = null; 43 | } 44 | } 45 | 46 | private void OnKeyboardNotification(NSNotification notification) 47 | { 48 | if (!IsViewLoaded) 49 | return; 50 | 51 | //Check if the keyboard is becoming visible 52 | var visible = notification.Name == UIKeyboard.WillShowNotification; 53 | 54 | //Start an animation, using values from the keyboard 55 | UIView.BeginAnimations("AnimateForKeyboard"); 56 | UIView.SetAnimationBeginsFromCurrentState(true); 57 | UIView.SetAnimationDuration(UIKeyboard.AnimationDurationFromNotification(notification)); 58 | UIView.SetAnimationCurve((UIViewAnimationCurve)UIKeyboard.AnimationCurveFromNotification(notification)); 59 | 60 | //Pass the notification, calculating keyboard height, etc. 61 | var keyboardFrame = visible 62 | ? UIKeyboard.FrameEndFromNotification(notification) 63 | : UIKeyboard.FrameBeginFromNotification(notification); 64 | 65 | OnKeyboardChanged(visible, keyboardFrame); 66 | 67 | //Commit the animation 68 | UIView.CommitAnimations(); 69 | } 70 | 71 | 72 | public virtual void OnKeyboardChanged(bool visible, CGRect keyboardFrame) 73 | { 74 | //Implement 75 | } 76 | 77 | protected void DismissKeyboardOnBackgroundTap() 78 | { 79 | // Add gesture recognizer to hide keyboard 80 | var tap = new UITapGestureRecognizer { CancelsTouchesInView = false }; 81 | tap.AddTarget(() => View.EndEditing(true)); 82 | tap.ShouldReceiveTouch = (recognizer, touch) => 83 | !(touch.View is UIControl || touch.View.FindSuperviewOfType(View, typeof(UITableViewCell)) != null); 84 | View.AddGestureRecognizer(tap); 85 | } 86 | 87 | #endregion 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /iOS/ViewController.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio from the outlets and 4 | // actions declared in your storyboard file. 5 | // Manual changes to this file will not be maintained. 6 | // 7 | using Foundation; 8 | using System; 9 | using System.CodeDom.Compiler; 10 | using UIKit; 11 | 12 | namespace SaveTheDate.iOS 13 | { 14 | [Register ("ViewController")] 15 | partial class ViewController 16 | { 17 | [Outlet] 18 | UIKit.UIButton Button { get; set; } 19 | 20 | [Outlet] 21 | [GeneratedCode ("iOS Designer", "1.0")] 22 | UIButton btnAddToCalendar { get; set; } 23 | 24 | [Outlet] 25 | [GeneratedCode ("iOS Designer", "1.0")] 26 | SaveTheDate.iOS.CustomControls.NotifyButton btnNotifyMe { get; set; } 27 | 28 | [Outlet] 29 | [GeneratedCode ("iOS Designer", "1.0")] 30 | UIButton btnShare { get; set; } 31 | 32 | [Outlet] 33 | [GeneratedCode ("iOS Designer", "1.0")] 34 | UIView emailView { get; set; } 35 | 36 | [Outlet] 37 | [GeneratedCode ("iOS Designer", "1.0")] 38 | UIImageView imgLogo { get; set; } 39 | 40 | [Outlet] 41 | [GeneratedCode ("iOS Designer", "1.0")] 42 | UILabel lblDate { get; set; } 43 | 44 | [Outlet] 45 | [GeneratedCode ("iOS Designer", "1.0")] 46 | UILabel lblEmail { get; set; } 47 | 48 | [Outlet] 49 | [GeneratedCode ("iOS Designer", "1.0")] 50 | UILabel lblSaveTheDate { get; set; } 51 | 52 | [Outlet] 53 | [GeneratedCode ("iOS Designer", "1.0")] 54 | UIView line { get; set; } 55 | 56 | [Outlet] 57 | [GeneratedCode ("iOS Designer", "1.0")] 58 | UIActivityIndicatorView progressBar { get; set; } 59 | 60 | [Outlet] 61 | [GeneratedCode ("iOS Designer", "1.0")] 62 | UITextField tbxEmailAddress { get; set; } 63 | 64 | [Action ("btnAddToCalendar_TouchUpInside:")] 65 | [GeneratedCode ("iOS Designer", "1.0")] 66 | partial void btnAddToCalendar_TouchUpInside (UIButton sender); 67 | 68 | [Action ("btnNotifyMe_TouchUpInside:")] 69 | [GeneratedCode ("iOS Designer", "1.0")] 70 | partial void btnNotifyMe_TouchUpInside (SaveTheDate.iOS.CustomControls.NotifyButton sender); 71 | 72 | [Action ("btnShare_TouchUpInside:")] 73 | [GeneratedCode ("iOS Designer", "1.0")] 74 | partial void btnShare_TouchUpInside (UIButton sender); 75 | 76 | void ReleaseDesignerOutlets () 77 | { 78 | if (btnAddToCalendar != null) { 79 | btnAddToCalendar.Dispose (); 80 | btnAddToCalendar = null; 81 | } 82 | if (btnNotifyMe != null) { 83 | btnNotifyMe.Dispose (); 84 | btnNotifyMe = null; 85 | } 86 | if (btnShare != null) { 87 | btnShare.Dispose (); 88 | btnShare = null; 89 | } 90 | if (emailView != null) { 91 | emailView.Dispose (); 92 | emailView = null; 93 | } 94 | if (imgLogo != null) { 95 | imgLogo.Dispose (); 96 | imgLogo = null; 97 | } 98 | if (lblDate != null) { 99 | lblDate.Dispose (); 100 | lblDate = null; 101 | } 102 | if (lblEmail != null) { 103 | lblEmail.Dispose (); 104 | lblEmail = null; 105 | } 106 | if (lblSaveTheDate != null) { 107 | lblSaveTheDate.Dispose (); 108 | lblSaveTheDate = null; 109 | } 110 | if (line != null) { 111 | line.Dispose (); 112 | line = null; 113 | } 114 | if (progressBar != null) { 115 | progressBar.Dispose (); 116 | progressBar = null; 117 | } 118 | if (tbxEmailAddress != null) { 119 | tbxEmailAddress.Dispose (); 120 | tbxEmailAddress = null; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /SaveTheDate/SaveTheDateHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Net.Http; 4 | using SaveTheDate.Helpers; 5 | using DeviceInfo.Plugin; 6 | 7 | namespace SaveTheDate 8 | { 9 | public static class SaveTheDateHelper 10 | { 11 | 12 | public static void Share() 13 | { 14 | Xamarin.Insights.Track("Share"); 15 | Utils.Sharer.ShareText(Strings.ShareText); 16 | } 17 | 18 | public static void AddToCalendar() 19 | { 20 | Xamarin.Insights.Track("AddToCalendar"); 21 | 22 | //Start and End dates 23 | var start = new DateTime(2016, 4, 24, 12, 0, 0); 24 | var end = new DateTime(2016, 4, 28, 12, 0, 0); 25 | 26 | Utils.Reminder.AddEvent(start, end, "Your Event Name", "Event Location", string.Empty, (success) => 27 | { 28 | Settings.AddedToCalendar = success; 29 | if (success) 30 | { 31 | Utils.Message.SendToast("Added to Calendar Successfully"); 32 | } 33 | }, "4242016400"); 34 | } 35 | 36 | public static bool IsValidEmail(string email) 37 | { 38 | email = email.Trim(); 39 | return email.IsValidEmail(); 40 | } 41 | 42 | 43 | public static async Task RegisterForNotifications(string email) 44 | { 45 | 46 | var success = false; 47 | try 48 | { 49 | 50 | email = email.Trim(); 51 | if (!email.IsValidEmail()) 52 | { 53 | Utils.Message.SendToast("Invalid Email Address."); 54 | return false; 55 | } 56 | 57 | 58 | Settings.RegisteredEmail = email; 59 | 60 | Xamarin.Insights.Track("RegisteredForNotifications"); 61 | Xamarin.Insights.Identify(Settings.RegisteredEmail, Xamarin.Insights.Traits.Email, Settings.RegisteredEmail); 62 | 63 | //TODO: Implement your backend here 64 | using (var client = new HttpClient()) 65 | { 66 | /*var content = new FormUrlEncodedContent(new[] 67 | { 68 | new KeyValuePair("email", email) 69 | }); 70 | var result = await client.PostAsync("http://your-post-end-point", content); 71 | 72 | success = result.IsSuccessStatusCode;*/ 73 | 74 | success = true; 75 | Settings.IsRegistered = success; 76 | } 77 | } 78 | catch (Exception ex) 79 | { 80 | success = false; 81 | Xamarin.Insights.Report(ex); 82 | } 83 | 84 | var title = "Registration Issue"; 85 | var message = "Unable to process, please check your connection."; 86 | if (success) 87 | { 88 | message = "Thanks! You're on the list to be notified about EVENT."; 89 | title = "All Set!"; 90 | } 91 | 92 | if (CrossDeviceInfo.Current.Platform == DeviceInfo.Plugin.Abstractions.Platform.iOS) 93 | Utils.Message.SendMessage(message, title); 94 | else 95 | Utils.Message.SendToast(message); 96 | 97 | return success; 98 | } 99 | 100 | 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | mobile.userprefs 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # PDT-specific 30 | .buildpath 31 | 32 | 33 | ################# 34 | ## Visual Studio 35 | ################# 36 | 37 | ## Ignore Visual Studio temporary files, build results, and 38 | ## files generated by popular Visual Studio add-ons. 39 | 40 | # User-specific files 41 | *.suo 42 | *.user 43 | *.sln.docstates 44 | 45 | # Build results 46 | 47 | [Dd]ebug/ 48 | [Rr]elease/ 49 | x64/ 50 | build/ 51 | [Bb]in/ 52 | [Oo]bj/ 53 | [Cc]omponents/ 54 | [Pp]ackages/ 55 | 56 | # MSTest test Results 57 | [Tt]est[Rr]esult*/ 58 | [Bb]uild[Ll]og.* 59 | 60 | *_i.c 61 | *_p.c 62 | *.ilk 63 | *.meta 64 | *.obj 65 | *.pch 66 | *.pdb 67 | *.pgc 68 | *.pgd 69 | *.rsp 70 | *.sbr 71 | *.tlb 72 | *.tli 73 | *.tlh 74 | *.tmp 75 | *.tmp_proj 76 | *.log 77 | *.vspscc 78 | *.vssscc 79 | .builds 80 | *.pidb 81 | *.log 82 | *.scc 83 | 84 | # Visual C++ cache files 85 | ipch/ 86 | *.aps 87 | *.ncb 88 | *.opensdf 89 | *.sdf 90 | *.cachefile 91 | 92 | # Visual Studio profiler 93 | *.psess 94 | *.vsp 95 | *.vspx 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | 104 | # TeamCity is a build add-in 105 | _TeamCity* 106 | 107 | # DotCover is a Code Coverage Tool 108 | *.dotCover 109 | 110 | # NCrunch 111 | *.ncrunch* 112 | .*crunch*.local.xml 113 | 114 | # Installshield output folder 115 | [Ee]xpress/ 116 | 117 | # DocProject is a documentation generator add-in 118 | DocProject/buildhelp/ 119 | DocProject/Help/*.HxT 120 | DocProject/Help/*.HxC 121 | DocProject/Help/*.hhc 122 | DocProject/Help/*.hhk 123 | DocProject/Help/*.hhp 124 | DocProject/Help/Html2 125 | DocProject/Help/html 126 | 127 | # Click-Once directory 128 | publish/ 129 | 130 | # Publish Web Output 131 | *.Publish.xml 132 | *.pubxml 133 | 134 | # NuGet Packages Directory 135 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 136 | #packages/ 137 | 138 | # Windows Azure Build Output 139 | csx 140 | *.build.csdef 141 | 142 | # Windows Store app package directory 143 | AppPackages/ 144 | 145 | # Others 146 | sql/ 147 | *.Cache 148 | ClientBin/ 149 | [Ss]tyle[Cc]op.* 150 | ~$* 151 | *~ 152 | *.dbmdl 153 | *.[Pp]ublish.xml 154 | *.pfx 155 | *.publishsettings 156 | 157 | # RIA/Silverlight projects 158 | Generated_Code/ 159 | 160 | # Backup & report files from converting an old project file to a newer 161 | # Visual Studio version. Backup files are not needed, because we have git ;-) 162 | _UpgradeReport_Files/ 163 | Backup*/ 164 | UpgradeLog*.XML 165 | UpgradeLog*.htm 166 | 167 | # SQL Server files 168 | App_Data/*.mdf 169 | App_Data/*.ldf 170 | 171 | ############# 172 | ## Windows detritus 173 | ############# 174 | 175 | # Windows image file caches 176 | Thumbs.db 177 | ehthumbs.db 178 | 179 | # Folder config file 180 | Desktop.ini 181 | 182 | # Recycle Bin used on file shares 183 | $RECYCLE.BIN/ 184 | 185 | # Mac crap 186 | .DS_Store 187 | 188 | ############# 189 | Git 190 | ############# 191 | 192 | *.orig 193 | 194 | ############# 195 | ## Python 196 | ############# 197 | 198 | *.py[co] 199 | 200 | # Packages 201 | *.egg 202 | *.egg-info 203 | dist/ 204 | build/ 205 | eggs/ 206 | parts/ 207 | var/ 208 | sdist/ 209 | develop-eggs/ 210 | .installed.cfg 211 | 212 | # Installer logs 213 | pip-log.txt 214 | 215 | # Unit test / coverage reports 216 | .coverage 217 | .tox 218 | 219 | #Translations 220 | *.mo 221 | 222 | #Mr Developer 223 | .mr.developer.cfg 224 | 225 | XamarinEvolve.userprefs 226 | -------------------------------------------------------------------------------- /iOS/Resources/Images.xcassets/AppIcons.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "filename": "Icon-Settings.png", 5 | "size": "29x29", 6 | "scale": "1x", 7 | "idiom": "iphone" 8 | }, 9 | { 10 | "filename": "Icon-Settings@2x.png", 11 | "size": "29x29", 12 | "scale": "2x", 13 | "idiom": "iphone" 14 | }, 15 | { 16 | "filename": "Icon-Settings@3x.png", 17 | "size": "29x29", 18 | "scale": "3x", 19 | "idiom": "iphone" 20 | }, 21 | { 22 | "filename": "Icon-Small@2x.png", 23 | "size": "40x40", 24 | "scale": "2x", 25 | "idiom": "iphone" 26 | }, 27 | { 28 | "filename": "Icon-Small@3x.png", 29 | "size": "40x40", 30 | "scale": "3x", 31 | "idiom": "iphone" 32 | }, 33 | { 34 | "size": "57x57", 35 | "scale": "1x", 36 | "idiom": "iphone" 37 | }, 38 | { 39 | "size": "57x57", 40 | "scale": "2x", 41 | "idiom": "iphone" 42 | }, 43 | { 44 | "filename": "Icon@2x.png", 45 | "size": "60x60", 46 | "scale": "2x", 47 | "idiom": "iphone" 48 | }, 49 | { 50 | "filename": "Icon@3x.png", 51 | "size": "60x60", 52 | "scale": "3x", 53 | "idiom": "iphone" 54 | }, 55 | { 56 | "size": "29x29", 57 | "scale": "1x", 58 | "idiom": "ipad" 59 | }, 60 | { 61 | "size": "29x29", 62 | "scale": "2x", 63 | "idiom": "ipad" 64 | }, 65 | { 66 | "size": "40x40", 67 | "scale": "1x", 68 | "idiom": "ipad" 69 | }, 70 | { 71 | "size": "40x40", 72 | "scale": "2x", 73 | "idiom": "ipad" 74 | }, 75 | { 76 | "size": "50x50", 77 | "scale": "1x", 78 | "idiom": "ipad" 79 | }, 80 | { 81 | "size": "50x50", 82 | "scale": "2x", 83 | "idiom": "ipad" 84 | }, 85 | { 86 | "size": "72x72", 87 | "scale": "1x", 88 | "idiom": "ipad" 89 | }, 90 | { 91 | "size": "72x72", 92 | "scale": "2x", 93 | "idiom": "ipad" 94 | }, 95 | { 96 | "size": "76x76", 97 | "scale": "1x", 98 | "idiom": "ipad" 99 | }, 100 | { 101 | "size": "76x76", 102 | "scale": "2x", 103 | "idiom": "ipad" 104 | }, 105 | { 106 | "role": "notificationCenter", 107 | "size": "24x24", 108 | "subtype": "38mm", 109 | "scale": "2x", 110 | "idiom": "watch" 111 | }, 112 | { 113 | "role": "notificationCenter", 114 | "size": "27.5x27.5", 115 | "subtype": "42mm", 116 | "scale": "2x", 117 | "idiom": "watch" 118 | }, 119 | { 120 | "role": "companionSettings", 121 | "size": "29x29", 122 | "scale": "2x", 123 | "idiom": "watch" 124 | }, 125 | { 126 | "role": "companionSettings", 127 | "size": "29x29", 128 | "scale": "3x", 129 | "idiom": "watch" 130 | }, 131 | { 132 | "role": "appLauncher", 133 | "size": "40x40", 134 | "subtype": "38mm", 135 | "scale": "2x", 136 | "idiom": "watch" 137 | }, 138 | { 139 | "role": "longLook", 140 | "size": "44x44", 141 | "subtype": "42mm", 142 | "scale": "2x", 143 | "idiom": "watch" 144 | }, 145 | { 146 | "role": "quickLook", 147 | "size": "86x86", 148 | "subtype": "38mm", 149 | "scale": "2x", 150 | "idiom": "watch" 151 | }, 152 | { 153 | "role": "quickLook", 154 | "size": "98x98", 155 | "subtype": "42mm", 156 | "scale": "2x", 157 | "idiom": "watch" 158 | }, 159 | { 160 | "size": "120x120", 161 | "scale": "1x", 162 | "idiom": "car" 163 | } 164 | ], 165 | "info": { 166 | "version": 1, 167 | "author": "xcode" 168 | }, 169 | "properties": { 170 | "pre-rendered": true 171 | } 172 | } -------------------------------------------------------------------------------- /Droid/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Android.App; 4 | using Android.Content; 5 | using Android.Runtime; 6 | using Android.Views; 7 | using Android.Widget; 8 | using Android.OS; 9 | using SaveTheDate.Droid.Helpers; 10 | using Android.Support.Design.Widget; 11 | using SaveTheDate.Helpers; 12 | using Android.Support.V7.App; 13 | 14 | namespace SaveTheDate.Droid 15 | { 16 | [Activity(Label = "Save The Date", MainLauncher = true, Icon = "@drawable/ic_launcher", ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait)] 17 | public class MainActivity : AppCompatActivity 18 | { 19 | 20 | protected override void OnCreate(Bundle bundle) 21 | { 22 | base.OnCreate(bundle); 23 | 24 | // Set our view from the "main" layout resource 25 | SetContentView(Resource.Layout.Main); 26 | 27 | Xamarin.Insights.Initialize(Xamarin.Insights.DebugModeKey, this); 28 | if(!string.IsNullOrWhiteSpace(Settings.RegisteredEmail)) 29 | Xamarin.Insights.Identify(Settings.RegisteredEmail, Xamarin.Insights.Traits.Email, Settings.RegisteredEmail); 30 | 31 | 32 | Utils.Sharer = new Share(); 33 | Utils.Reminder = new ReminderService(); 34 | Utils.Message = new MessageDialog(); 35 | 36 | AndroidUtils.SnackbarView = FindViewById(Resource.Id.main); 37 | AndroidUtils.Context = this; 38 | 39 | var email = FindViewById(Resource.Id.text_email); 40 | var notify = FindViewById 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 77 | 89 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | --------------------------------------------------------------------------------