├── .gitignore ├── Docs ├── Images │ ├── CognitiveServices_Keys.png │ ├── CognitiveServices_Signup.png │ ├── TranslatorService_Creation.png │ └── TranslatorService_Keys.png └── Register.md ├── LICENSE.md ├── README.md ├── Screenshots ├── Windows │ ├── DescribeImage01.png │ └── DescribeImage02.png └── iOS │ └── DescribeImage01.png ├── See4Me.sln └── Src ├── See4Me.Android ├── Activities │ ├── MainActivity.cs │ └── SplashActivity.cs ├── Application.cs ├── Assets │ └── AboutAssets.txt ├── Common │ └── ActivityBase.cs ├── Extensions │ └── ContextExtensions.cs ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs ├── Resources │ ├── AboutResources.txt │ ├── Resource.Designer.cs │ ├── Values-it │ │ └── AppResources.xml │ ├── drawable │ │ ├── Icon.png │ │ ├── camera.png │ │ ├── roundedbutton.xml │ │ └── splash_screen.xml │ ├── layout │ │ └── Main.axml │ └── values │ │ ├── AppResources.xml │ │ ├── Strings.xml │ │ └── Styles.xml ├── See4Me.Android.csproj ├── Services │ ├── AppService.cs │ ├── LauncherService.cs │ ├── MediaPicker.cs │ ├── NavigationService.cs │ └── StreamingService.cs ├── ViewModels │ ├── SplashViewModel.cs │ └── ViewModelLocator.cs ├── app.config └── packages.config ├── See4Me.Engine ├── CognitiveClient.cs ├── CognitiveException.cs ├── CognitiveResult.cs ├── CognitiveSettings.cs ├── Enums │ ├── Emotion.cs │ ├── Gender.cs │ ├── RecognitionPhase.cs │ └── RecognitionType.cs ├── Extensions │ ├── FaceExtensions.cs │ ├── OcrResultExtensions.cs │ ├── StreamExtensions.cs │ ├── StringExtensions.cs │ └── VisionExtensions.cs ├── Properties │ └── AssemblyInfo.cs ├── See4Me.Engine.csproj ├── Services │ ├── ServiceSettings │ │ ├── IVisionSettingsProvider.cs │ │ ├── SimpleVisionSettingsProvider.cs │ │ └── VisionSettings.cs │ └── TranslatorService │ │ ├── AzureAuthToken.cs │ │ ├── ErrorResponse.cs │ │ ├── ITranslatorServiceClient.cs │ │ ├── TranslatorServiceClient.cs │ │ └── TranslatorServiceException.cs ├── app.config └── packages.config ├── See4Me.Localization ├── HowToUse.it.txt ├── HowToUse.txt ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── AppResources.Designer.cs │ ├── AppResources.it.resx │ ├── AppResources.resx │ ├── Resx2Others.tt │ ├── Resx2OthersTemplate.cs │ ├── Resx2OthersTemplate.tt │ └── Strings.cs ├── See4Me.Localization.csproj └── project.json ├── See4Me.Shared ├── Common │ ├── AutoRelayCommand.cs │ └── VisionSettings.json ├── Constants.cs ├── Extensions │ ├── ExceptionExtensions.cs │ └── StreamExtensions.cs ├── See4Me.Shared.projitems ├── See4Me.Shared.shproj ├── ServiceKeys.cs ├── Services │ ├── DialogService.cs │ ├── IAppService.cs │ ├── IDialogService.cs │ ├── ILauncherService.cs │ ├── IMediaPicker.cs │ ├── INavigationService.cs │ ├── INetworkService.cs │ ├── ISettingsService.cs │ ├── ISpeechService.cs │ ├── IStreamingService.cs │ ├── NetworkService.cs │ ├── SettingsService.cs │ ├── SpeechHelper.cs │ └── SpeechService.cs └── ViewModels │ ├── AboutViewModel.cs │ ├── MainViewModel.cs │ ├── PrivacyViewModel.cs │ ├── RecognizeTextViewModel.cs │ ├── SettingsViewModel.cs │ ├── ViewModelBase.cs │ └── ViewModelLocator.cs ├── See4Me.Windows ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── Original │ │ ├── SplashScreen.scale-100.png │ │ ├── SplashScreen.scale-125.png │ │ ├── SplashScreen.scale-150.png │ │ ├── SplashScreen.scale-200.png │ │ └── SplashScreen.scale-400.png │ ├── Sounds │ │ └── Shutter.mp3 │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square310x310Logo.scale-100.png │ ├── Square310x310Logo.scale-125.png │ ├── Square310x310Logo.scale-150.png │ ├── Square310x310Logo.scale-200.png │ ├── Square310x310Logo.scale-400.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.targetsize-48.png │ ├── Square71x71Logo.scale-100.png │ ├── Square71x71Logo.scale-125.png │ ├── Square71x71Logo.scale-150.png │ ├── Square71x71Logo.scale-200.png │ ├── Square71x71Logo.scale-400.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── Wide310x150Logo.scale-100.png │ ├── Wide310x150Logo.scale-125.png │ ├── Wide310x150Logo.scale-150.png │ ├── Wide310x150Logo.scale-200.png │ └── Wide310x150Logo.scale-400.png ├── Behaviors │ ├── CameraPressedBehavior.cs │ ├── PushButton.cs │ ├── PushButtonBehavior.cs │ └── SwipeTriggerBehavior.cs ├── Constants.cs ├── Extensions │ └── ImageExtensions.cs ├── LocalizedStrings.cs ├── Package.appxmanifest ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── See4Me.Windows.csproj ├── Services │ ├── AppService.cs │ ├── LauncherService.cs │ ├── MediaPicker.cs │ ├── NavigationService.cs │ ├── StreamResolution.cs │ └── StreamingService.cs ├── Strings │ ├── en │ │ └── Resources.resw │ └── it │ │ └── Resources.resw ├── Styles │ └── Styles.xaml ├── ViewModels │ ├── MainViewModel.cs │ ├── RecognizeTextViewModel.cs │ ├── SettingsViewModel.cs │ ├── ViewModelBase.cs │ └── ViewModelLocator.cs ├── Views │ ├── AboutPage.xaml │ ├── AboutPage.xaml.cs │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── PrivacyPolicyPage.xaml │ ├── PrivacyPolicyPage.xaml.cs │ ├── RecognizeTextPage.xaml │ ├── RecognizeTextPage.xaml.cs │ ├── SettingsPage.xaml │ └── SettingsPage.xaml.cs └── project.json └── See4Me.iOS ├── AppDelegate.cs ├── Common └── ViewControllerBase.cs ├── Entitlements.plist ├── Extensions ├── AVCaptureExtensions.cs ├── ContextExtensions.cs └── LocalizationExtensions.cs ├── Info.plist ├── LinkerWorkarounds.cs ├── Main.cs ├── Main.storyboard ├── Properties └── AssemblyInfo.cs ├── Resources ├── Icon-60.png ├── Icon-60@2x.png ├── Icon-60@3x.png ├── Icon-72.png ├── Icon-72@2x.png ├── Icon-76.png ├── Icon-76@2x.png ├── Icon-83.5@2x.png ├── Icon-Small-40.png ├── Icon-Small-40@2x.png ├── Icon-Small-40@3x.png ├── Icon-Small-50.png ├── Icon-Small-50@2x.png ├── Icon-Small.png ├── Icon-Small@2x.png ├── Icon-Small@3x.png ├── Icon.png ├── Icon@2x.png ├── Images │ ├── Camera.png │ ├── Camera@2x.png │ ├── Eye.png │ ├── Eye@2x.png │ ├── Settings.png │ ├── Settings@2x.png │ ├── SwitchCamera.png │ └── SwitchCamera@2x.png ├── LaunchScreen.xib ├── iTunesArtwork.png └── iTunesArtwork@2x.png ├── See4Me.iOS.csproj ├── Services ├── AppService.cs ├── ImageTools.cs ├── LauncherService.cs ├── MediaPicker.cs ├── NavigationService.cs ├── OutputRecorder.cs ├── SoundTools.cs └── StreamingService.cs ├── ViewControllers ├── AboutViewController.cs ├── AboutViewController.designer.cs ├── MainViewController.cs ├── MainViewController.designer.cs ├── PrivacyPolicyViewController.cs ├── PrivacyPolicyViewController.designer.cs ├── SettingsViewController.cs └── SettingsViewController.designer.cs ├── app.config ├── en.lproj └── Localizable.strings ├── it.lproj └── Localizable.strings └── packages.config /Docs/Images/CognitiveServices_Keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Docs/Images/CognitiveServices_Keys.png -------------------------------------------------------------------------------- /Docs/Images/CognitiveServices_Signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Docs/Images/CognitiveServices_Signup.png -------------------------------------------------------------------------------- /Docs/Images/TranslatorService_Creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Docs/Images/TranslatorService_Creation.png -------------------------------------------------------------------------------- /Docs/Images/TranslatorService_Keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Docs/Images/TranslatorService_Keys.png -------------------------------------------------------------------------------- /Docs/Register.md: -------------------------------------------------------------------------------- 1 | # How to Register Cognitive Services 2 | 3 | In order to use Microsoft Cognitive Services, you need to get the corresponding service keys by following the instructions available in the **Microsoft Cognitive Services subscription** page: 4 | 5 | 1. Go to https://www.microsoft.com/cognitive-services/en-us/sign-up and login with your Microsoft, GitHub or LinkedIn account: 6 | 7 | 8 | 9 | 2. After logging in, click the **Request new trials** button and select the products you want to subscribe. For our purposes, we need the following ones: 10 | 1. Computer Vision 11 | 2. Face 12 | 13 | In the description column you can see the free quota limit for each service. Check the option *I agree to the Microsoft Cognitive Services Terms and Microsoft Privacy Statement* and click **Subscribe**. 14 | 15 | 3. You'll be redirect to the **My free subscription** pages, that contains all the products for which you have a subscription. For each one there is a couple of Keys, for example: 16 | 17 | 18 | 19 | By clicking on **Show**, you'll see the keys you'll need to enter in the app setting page to use Cognitive Services features. 20 | 21 | 22 | Then, if you want to use translation feature, you also need an Azure subscription to activate **Microsoft Translator Service**. Go to https://portal.azure.com/#create/Microsoft.CognitiveServices/apitype/TextTranslation to start the service creation wizard: 23 | 24 | 25 | 26 | Enter an account name and be sure that, under API type, the value *Translator Text API* is selected. Then insert all the other information. In particular, in the *Pricing tier* box you can select how to pay the service: as all the resources available on Azure, you pay what you use. There is a free tier that allows to translate up to 2M characters a month. When you have set all the properties, confirm by clicking on **Create**. After the service deployment is completed, go to its **Keys** section: 27 | 28 | 29 | 30 | You need to enter either Key 1 or Key 2 in the app setting page to activate translator feature. Note that it may take up to 10 minutes for the newly (re)generated keys to take effect. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introducing See4Me 2 | 3 | *See4Me* is a cross-platform app to 'see' the world using [Microsoft Cognitive Services](https://www.microsoft.com/cognitive-services). Simply point the smartphone and tap: in a few moments the app will describe and speak what it sees -- from scenes to objects to people with age and emotion. The app is also able to automatically translate descriptions using [Microsoft Translator](https://www.microsoft.com/en-us/translator/products.aspx). 4 | 5 | **Getting started** 6 | 7 | To use See4Me, you must obtain Cognitive API and Microsoft Translator subscription keys by following the instructions available in [How to register Cognitive Services](Docs/Register.md). 8 | 9 | Then, you need to enter these service keys (Subscription Key for Vision, Face, Emotion and Translator Services) in the *Src/See4Me.Shared/ServiceKeys.cs* file. 10 | 11 | **Screenshots** 12 | 13 | *Windows 10 version* 14 | 15 | 16 | 17 | 18 | *iOS version* 19 | 20 | 21 | 22 | **Contribute** 23 | 24 | The project is continuously evolving. We welcome contributions. Feel free to file issues and pull requests on the repo and we'll address them as we can. 25 | 26 | **Developer Code of Conduct** 27 | 28 | The image, voice, video or text understanding capabilities of See4Me use Microsoft Cognitive Services. Microsoft will receive the images, audio, video, and other data that you upload (via this app) for service improvement purposes. To report abuse of the Microsoft Cognitive Services to Microsoft, please visit the Microsoft Cognitive Services website at https://www.microsoft.com/cognitive-services, and use the "Report Abuse" link at the bottom of the page to contact Microsoft. For more information about Microsoft privacy policies please see their privacy statement here: https://go.microsoft.com/fwlink/?LinkId=521839. 29 | 30 | See4Me uses the Microsoft Cognitive Services, see https://www.microsoft.com/cognitive-services/. Developers using this project are expected to follow the “Developer Code of Conduct for Microsoft Cognitive Services” at http://go.microsoft.com/fwlink/?LinkId=698895. 31 | -------------------------------------------------------------------------------- /Screenshots/Windows/DescribeImage01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Screenshots/Windows/DescribeImage01.png -------------------------------------------------------------------------------- /Screenshots/Windows/DescribeImage02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Screenshots/Windows/DescribeImage02.png -------------------------------------------------------------------------------- /Screenshots/iOS/DescribeImage01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Screenshots/iOS/DescribeImage01.png -------------------------------------------------------------------------------- /Src/See4Me.Android/Activities/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Android.App; 4 | using Android.Content; 5 | using Android.Runtime; 6 | using Android.Views; 7 | using Android.Widget; 8 | using See4Me.ViewModels; 9 | using See4Me.Android.Common; 10 | using GalaSoft.MvvmLight.Messaging; 11 | using Android.Media; 12 | using Android.OS; 13 | using Android.Hardware; 14 | using GalaSoft.MvvmLight.Helpers; 15 | using Java.Security; 16 | using Messaging = GalaSoft.MvvmLight.Messaging; 17 | using Microsoft.Practices.ServiceLocation; 18 | using See4Me.Android.Extensions; 19 | using See4Me.Services; 20 | using Android.Content.Res; 21 | using Android.Content.PM; 22 | using System.Collections.Generic; 23 | 24 | namespace See4Me.Android 25 | { 26 | [Activity(Label = "@string/ApplicationName", Icon = "@drawable/icon", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, 27 | ScreenOrientation = ScreenOrientation.Landscape, Theme = "@style/See4Me")] 28 | public class MainActivity : ActivityBase 29 | { 30 | private List bindings; 31 | 32 | private TextureView textureView; 33 | private TextView statusMessage; 34 | private ImageButton takePhotoButton; 35 | 36 | public TextView StatusMessage => statusMessage ?? (statusMessage = FindViewById(Resource.Id.textViewMessage)); 37 | 38 | public ImageButton TakePhotoButton => takePhotoButton ?? (takePhotoButton = FindViewById(Resource.Id.takePhotoButton)); 39 | 40 | public TextureView TextureView => textureView ?? (textureView = FindViewById(Resource.Id.textureViewMain)); 41 | 42 | protected override int? LayoutResourseID => Resource.Layout.Main; 43 | 44 | protected override void OnInitialize(Bundle bundle) 45 | { 46 | this.RegisterMessages(); 47 | this.bindings = new List() 48 | { 49 | this.SetBinding(() => ViewModel.StatusMessage, () => StatusMessage.Text, BindingMode.OneWay).RegisterHandler(StatusMessage), 50 | }; 51 | 52 | this.TakePhotoButton.SetCommand(this.ViewModel.DescribeImageCommand); 53 | 54 | // Initializes camera streaming. 55 | var streamingService = ServiceLocator.Current.GetInstance() as TextureView.ISurfaceTextureListener; 56 | TextureView.SurfaceTextureListener = streamingService; 57 | 58 | base.OnInitialize(bundle); 59 | } 60 | 61 | private void RegisterMessages() 62 | { 63 | Messaging.Messenger.Default.Register>(this, (message) => 64 | { 65 | switch (message.Notification) 66 | { 67 | case Constants.InitializeStreaming: 68 | message.Execute(TextureView); 69 | break; 70 | } 71 | }); 72 | } 73 | 74 | protected override async void OnResume() 75 | { 76 | base.OnResume(); 77 | 78 | await ViewModel.InitializeStreamingAsync(); 79 | await ViewModel.CheckShowConsentAsync(); 80 | } 81 | 82 | protected override async void OnPause() 83 | { 84 | base.OnPause(); 85 | 86 | await ViewModel.CleanupAsync(); 87 | } 88 | 89 | public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e) 90 | { 91 | if (keyCode == Keycode.VolumeDown || keyCode == Keycode.VolumeUp) 92 | { 93 | ViewModel.DescribeImageCommand.Execute(null); 94 | return true; 95 | } 96 | 97 | return base.OnKeyDown(keyCode, e); 98 | } 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Activities/SplashActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content; 3 | using Android.OS; 4 | using Android.Content.PM; 5 | using GalaSoft.MvvmLight.Views; 6 | using See4Me.Android; 7 | using System.Threading.Tasks; 8 | using See4Me.ViewModels; 9 | using See4Me.Android.Common; 10 | 11 | namespace SpeedOrder.Droid.Activities 12 | { 13 | [Activity(MainLauncher = true, Label = "@string/ApplicationName", Theme = "@style/See4Me.Splash", Icon = "@drawable/icon", 14 | ScreenOrientation = ScreenOrientation.Landscape, NoHistory = true)] 15 | public class SplashActivity : ActivityBase 16 | { 17 | protected override async void OnResume() 18 | { 19 | base.OnResume(); 20 | 21 | // Uses a delay to force the splash screen to appear. 22 | await Task.Delay(100); 23 | 24 | // Navigates to the actual Main Page. 25 | ViewModel.NavigateToMainPage(); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/Application.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Android.App; 4 | using Android.Runtime; 5 | using See4Me.ViewModels; 6 | using GalaSoft.MvvmLight.Threading; 7 | using GalaSoft.MvvmLight.Views; 8 | using See4Me.Services; 9 | 10 | namespace See4Me.Android 11 | { 12 | [Application(Label = "See4Me", Icon = "@drawable/Icon")] 13 | public class Application : global::Android.App.Application 14 | { 15 | /// 16 | /// Must implement this constructor for subclassing the application class. 17 | /// Will act as a global application class throughout the app. 18 | /// 19 | /// pointer to java 20 | /// transfer enumeration 21 | public Application(IntPtr javaReference, JniHandleOwnership transfer) 22 | : base(javaReference, transfer) 23 | { } 24 | 25 | /// 26 | /// Override on create to instantiate the service container to be persistant. 27 | /// 28 | public override void OnCreate() 29 | { 30 | base.OnCreate(); 31 | 32 | // Registers services for core library 33 | this.Initialize(); 34 | } 35 | 36 | private void Initialize() 37 | { 38 | // Page navigation 39 | var navigationService = new Services.NavigationService(); 40 | navigationService.Configure(Pages.MainPage.ToString(), typeof(MainActivity)); 41 | 42 | this.Locator = new ViewModelLocator(); 43 | Locator.Initialize(navigationService); 44 | 45 | // MVVM Light's DispatcherHelper for cross-thread handling. 46 | DispatcherHelper.Initialize(); 47 | } 48 | 49 | public ViewModelLocator Locator { get; private set; } 50 | } 51 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/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 you 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"); -------------------------------------------------------------------------------- /Src/See4Me.Android/Common/ActivityBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Android.App; 6 | using Android.Content; 7 | using Android.Runtime; 8 | using Android.Views; 9 | using Android.Widget; 10 | using See4Me.ViewModels; 11 | using Microsoft.Practices.ServiceLocation; 12 | using GalaSoft.MvvmLight.Messaging; 13 | using Android.OS; 14 | using GalaSoft.MvvmLight.Views; 15 | 16 | namespace See4Me.Android.Common 17 | { 18 | public abstract class ActivityBase : GalaSoft.MvvmLight.Views.ActivityBase where T : ViewModelBase 19 | { 20 | protected T ViewModel => ServiceLocator.Current.GetInstance(); 21 | 22 | protected virtual int? LayoutResourseID { get; } 23 | 24 | protected override void OnCreate(Bundle savedInstanceState) 25 | { 26 | base.OnCreate(savedInstanceState); 27 | 28 | if (LayoutResourseID.HasValue) 29 | { 30 | SetContentView(LayoutResourseID.Value); 31 | } 32 | else 33 | { 34 | var view = OnSetContentView(savedInstanceState); 35 | if (view != null) 36 | SetContentView(view); 37 | } 38 | 39 | OnInitialize(savedInstanceState); 40 | } 41 | 42 | protected virtual View OnSetContentView(Bundle savedInstanceState) => null; 43 | 44 | protected override void OnDestroy() 45 | { 46 | GalaSoft.MvvmLight.Messaging.Messenger.Default.Unregister(this); 47 | base.OnDestroy(); 48 | } 49 | 50 | protected virtual void OnInitialize(Bundle bundle) { } 51 | } 52 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/Extensions/ContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Android.App; 6 | using Android.Content; 7 | using Android.Views; 8 | using Android.Widget; 9 | using GalaSoft.MvvmLight.Helpers; 10 | using GalaSoft.MvvmLight.Command; 11 | 12 | namespace See4Me.Android.Extensions 13 | { 14 | public static class ContextExtensions 15 | { 16 | public static Binding RegisterHandler(this Binding binding, View view) 17 | { 18 | if (view is TextView) 19 | { 20 | var textView = (view as TextView); 21 | textView.Text = null; 22 | textView.TextChanged += (s, e) => { }; 23 | } 24 | else if (view is CheckBox) 25 | { 26 | (view as CheckBox).CheckedChange += (s, e) => { }; 27 | } 28 | 29 | return binding; 30 | } 31 | 32 | public static View SetCommand(this View view, RelayCommand command) 33 | { 34 | view.Click += (s, e) => { }; 35 | view.SetCommand(Events.Click, command); 36 | 37 | //view.Enabled = command.CanExecute(null); 38 | //command.CanExecuteChanged += (s, args) => view.Enabled = command.CanExecute(null); 39 | 40 | return view; 41 | } 42 | } 43 | 44 | public static class Events 45 | { 46 | public const string TextChanged = "TextChanged"; 47 | public const string CheckedChanged = "CheckedChanged"; 48 | public const string Click = "Click"; 49 | } 50 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("See4Me.Android")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("See4Me.Android")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Src/See4Me.Android/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. -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/drawable/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Android/Resources/drawable/Icon.png -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/drawable/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Android/Resources/drawable/camera.png -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/drawable/roundedbutton.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/drawable/splash_screen.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/layout/Main.axml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 14 | 23 | 37 | 38 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/values/Strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | See4Me 4 | 5 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Resources/values/Styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Services/AppService.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Android; 2 | using See4Me.Localization.Resources; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace See4Me.Services 10 | { 11 | public class AppService : IAppService 12 | { 13 | private const string BLOG_URL = "https://marcominerva.wordpress.com"; 14 | private const string TWITTER_URL = "https://twitter.com/marcominerva"; 15 | private const string LINKEDIN_URL = "https://www.linkedin.com/in/marcominerva"; 16 | 17 | public string Version 18 | { 19 | get 20 | { 21 | var context = Application.Context; 22 | var versionName = context.PackageManager.GetPackageInfo(context.PackageName, global::Android.Content.PM.PackageInfoFlags.MetaData).VersionName; 23 | return versionName; 24 | } 25 | } 26 | 27 | public string Author => AppResources.AndroidProjectAuthor; 28 | 29 | public string BlogUrl => BLOG_URL; 30 | 31 | public string TwitterUrl => TWITTER_URL; 32 | 33 | public string LinkedInUrl => LINKEDIN_URL; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Services/LauncherService.cs: -------------------------------------------------------------------------------- 1 | using Android.Content; 2 | using See4Me.Android; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace See4Me.Services 10 | { 11 | public class LauncherService : ILauncherService 12 | { 13 | public Task LaunchUriAsync(string uri) 14 | { 15 | var intent = new Intent(Intent.ActionView); 16 | intent.SetData(global::Android.Net.Uri.Parse(uri)); 17 | MainActivity.CurrentActivity.StartActivity(intent); 18 | 19 | return Task.FromResult(null); 20 | } 21 | 22 | public Task LaunchMailAsync(string mailAddress) 23 | { 24 | var intent = new Intent(Intent.ActionSendto); 25 | intent.SetData(global::Android.Net.Uri.Parse($"mailto:{mailAddress}")); 26 | MainActivity.CurrentActivity.StartActivity(intent); 27 | 28 | return Task.FromResult(null); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Src/See4Me.Android/Services/MediaPicker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Android.App; 8 | using Android.Content; 9 | using Android.OS; 10 | using Android.Runtime; 11 | using Android.Views; 12 | using Android.Widget; 13 | 14 | namespace See4Me.Services 15 | { 16 | public class MediaPicker : IMediaPicker 17 | { 18 | public Task TakePhotoAsync() 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | using Android.App; 7 | using Android.Content; 8 | using Android.OS; 9 | using Android.Runtime; 10 | using Android.Views; 11 | using Android.Widget; 12 | 13 | namespace See4Me.Services 14 | { 15 | public class NavigationService : GalaSoft.MvvmLight.Views.NavigationService, See4Me.Services.INavigationService 16 | { } 17 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/ViewModels/SplashViewModel.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight; 2 | using GalaSoft.MvvmLight.Views; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Microsoft.Practices.ServiceLocation; 7 | using See4Me.Services; 8 | 9 | namespace See4Me.ViewModels 10 | { 11 | public class SplashViewModel : ViewModelBase 12 | { 13 | private readonly Services.INavigationService navigationService; 14 | 15 | public SplashViewModel(Services.INavigationService navigationService) 16 | { 17 | this.navigationService = navigationService; 18 | } 19 | 20 | public void NavigateToMainPage() 21 | { 22 | navigationService.NavigateTo(Pages.MainPage.ToString()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Src/See4Me.Android/ViewModels/ViewModelLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | using Android.App; 7 | using Android.Content; 8 | using Android.OS; 9 | using Android.Runtime; 10 | using Android.Views; 11 | using Android.Widget; 12 | using GalaSoft.MvvmLight.Ioc; 13 | using Microsoft.Practices.ServiceLocation; 14 | 15 | namespace See4Me.ViewModels 16 | { 17 | public partial class ViewModelLocator 18 | { 19 | static partial void OnInitialize() 20 | { 21 | SimpleIoc.Default.Register(); 22 | } 23 | 24 | public SplashViewModel SplashViewModel => ServiceLocator.Current.GetInstance(); 25 | } 26 | } -------------------------------------------------------------------------------- /Src/See4Me.Android/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Src/See4Me.Android/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/CognitiveException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.Engine 9 | { 10 | public class CognitiveException : Exception 11 | { 12 | public CognitiveException(string message, Exception innerException = null) 13 | : base(message, innerException) 14 | { } 15 | 16 | public string Code { get; internal set; } 17 | 18 | public HttpStatusCode HttpStatusCode { get; internal set; } = HttpStatusCode.InternalServerError; 19 | 20 | internal CognitiveException() 21 | { 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/CognitiveResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | public class CognitiveResult 10 | { 11 | public VisionResult VisionResult { get; internal set; } = new VisionResult(); 12 | 13 | public IList FaceResults { get; internal set; } = new List(); 14 | 15 | public OcrResult OcrResult { get; internal set; } = new OcrResult(); 16 | 17 | internal CognitiveResult() 18 | { 19 | } 20 | } 21 | 22 | public class VisionResult 23 | { 24 | public bool IsValid { get; internal set; } 25 | 26 | public double Confidence { get; internal set; } 27 | 28 | public string RawDescription { get; internal set; } 29 | 30 | public string Description { get; internal set; } 31 | 32 | private string translatedDescription; 33 | public string TranslatedDescription 34 | { 35 | get { return translatedDescription ?? Description; } 36 | internal set { translatedDescription = value; } 37 | } 38 | 39 | public bool IsTranslated => Description != translatedDescription; 40 | 41 | internal VisionResult() 42 | { 43 | } 44 | } 45 | 46 | public class FaceResult 47 | { 48 | public Emotion Emotion { get; internal set; } = Emotion.Neutral; 49 | 50 | public int Age { get; internal set; } 51 | 52 | public Gender Gender { get; internal set; } 53 | 54 | public string Name { get; internal set; } 55 | 56 | public double IdentifyConfidence { get; internal set; } 57 | 58 | internal FaceResult() 59 | { 60 | } 61 | } 62 | 63 | public class OcrResult 64 | { 65 | private string text; 66 | public string Text 67 | { 68 | get { return !string.IsNullOrWhiteSpace(text) ? text : null; } 69 | internal set { text = value; } 70 | } 71 | 72 | public bool ContainsText => !string.IsNullOrWhiteSpace(Text); 73 | 74 | internal OcrResult() 75 | { 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Src/See4Me.Engine/CognitiveSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | public class CognitiveSettings 10 | { 11 | public string VisionSubscriptionKey { get; set; } 12 | 13 | public string FaceSubscriptionKey { get; set; } 14 | 15 | public string TranslatorSubscriptionKey { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Src/See4Me.Engine/Enums/Emotion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | public enum Emotion 10 | { 11 | Neutral, 12 | Anger, 13 | Contempt, 14 | Disgust, 15 | Fear, 16 | Happiness, 17 | Sadness, 18 | Surprise 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Enums/Gender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | public enum Gender 10 | { 11 | Male, 12 | Female 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Enums/RecognitionPhase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | public enum RecognitionPhase 10 | { 11 | QueryingService, 12 | Translating, 13 | RecognizingFaces, 14 | RecognizingText 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Enums/RecognitionType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine 8 | { 9 | [Flags] 10 | public enum RecognitionType 11 | { 12 | Vision = 1, 13 | Face = 2, 14 | Emotion = 4, 15 | Text = 8, 16 | All = Vision | Face | Emotion | Text 17 | } 18 | } -------------------------------------------------------------------------------- /Src/See4Me.Engine/Extensions/FaceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Linq; 5 | using Microsoft.ProjectOxford.Face.Contract; 6 | using Microsoft.ProjectOxford.Common.Contract; 7 | 8 | namespace See4Me.Engine.Extensions 9 | { 10 | internal static class FaceExtensions 11 | { 12 | public static Emotion GetBestEmotion(this EmotionScores emotions) 13 | { 14 | var bestEmotion = emotions?.ToRankedList().FirstOrDefault().Key ?? nameof(EmotionScores.Neutral); 15 | return (Emotion)Enum.Parse(typeof(Emotion), bestEmotion, true); 16 | } 17 | 18 | public static FaceResult GetFaceResult(this Face face) 19 | { 20 | var age = (int)face.FaceAttributes.Age; 21 | if (age == 0) 22 | { 23 | age = 1; 24 | } 25 | 26 | return new FaceResult 27 | { 28 | Age = age, 29 | Gender = (Gender)Enum.Parse(typeof(Gender), face.FaceAttributes.Gender, true), 30 | Emotion = face.FaceAttributes.Emotion.GetBestEmotion() 31 | }; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Extensions/OcrResultExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ProjectOxford.Vision.Contract; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.Engine.Extensions 9 | { 10 | internal static class OcrResultExtensions 11 | { 12 | public static string GetRecognizedText(this OcrResults results) 13 | { 14 | var stringBuilder = new StringBuilder(); 15 | 16 | if (results?.Regions != null) 17 | { 18 | foreach (var item in results.Regions) 19 | { 20 | foreach (var line in item.Lines) 21 | { 22 | foreach (var word in line.Words) 23 | { 24 | stringBuilder.Append(word.Text); 25 | stringBuilder.Append(" "); 26 | } 27 | 28 | stringBuilder.AppendLine(); 29 | } 30 | 31 | stringBuilder.AppendLine(); 32 | } 33 | } 34 | 35 | return stringBuilder.ToString(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Extensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Extensions 8 | { 9 | internal static class StreamExtensions 10 | { 11 | public static async Task ToArrayAsync(this Stream stream) 12 | { 13 | stream.Position = 0; 14 | 15 | using (var ms = new MemoryStream()) 16 | { 17 | await stream.CopyToAsync(ms); 18 | stream.Position = 0; 19 | return ms.ToArray(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.Engine.Extensions 9 | { 10 | internal static class StringExtensions 11 | { 12 | public static bool Contains(this string source, string value, StringComparison comparison) 13 | => source?.IndexOf(value, comparison) >= 0; 14 | 15 | public static bool ContainsIgnoreCase(this string source, string value) 16 | => source?.Contains(value, StringComparison.OrdinalIgnoreCase) ?? false; 17 | 18 | public static bool EqualsIgnoreCase(this string source, string value) 19 | => string.Equals(source, value, StringComparison.OrdinalIgnoreCase); 20 | 21 | public static bool StartsWithIgnoreCase(this string source, string value) 22 | => source?.StartsWith(value, StringComparison.OrdinalIgnoreCase) ?? false; 23 | 24 | public static string ReplaceIgnoreCase(this string input, string pattern, string replacement) 25 | => Regex.Replace(input, pattern, replacement, RegexOptions.IgnoreCase); 26 | } 27 | } -------------------------------------------------------------------------------- /Src/See4Me.Engine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("See4Me.Engine")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("See4Me.Engine")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Services/ServiceSettings/IVisionSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Services.ServiceSettings 8 | { 9 | public interface IVisionSettingsProvider 10 | { 11 | Task GetSettingsAsync(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Services/ServiceSettings/SimpleVisionSettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Services.ServiceSettings 8 | { 9 | public class SimpleVisionSettingsProvider : IVisionSettingsProvider 10 | { 11 | public SimpleVisionSettingsProvider(VisionSettings settings) 12 | { 13 | Settings = settings; 14 | } 15 | 16 | public VisionSettings Settings { get; set; } 17 | 18 | public Task GetSettingsAsync() => Task.FromResult(Settings); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Services/ServiceSettings/VisionSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Services.ServiceSettings 8 | { 9 | public class VisionSettings 10 | { 11 | /* Somes strings are actually invalid or need to be temporaly removed 12 | * because very often they aren't so accurate 13 | * (they will be probably added again in a future release). 14 | */ 15 | 16 | public IEnumerable InvalidDescriptions { get; set; } 17 | 18 | public IEnumerable DescriptionsToRemove { get; set; } 19 | 20 | public Dictionary DescriptionsToReplace { get; set; } 21 | 22 | // The minimum confidence to consider a description valid. 23 | public double MinimumConfidence { get; set; } = 0.16; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Services/TranslatorService/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Services.TranslatorService 8 | { 9 | /// 10 | /// Holds information about an error occurred while accessing Microsoft Translator Service. 11 | /// 12 | internal class ErrorResponse 13 | { 14 | /// 15 | /// Gets or sets the error message. 16 | /// 17 | public string Message { get; set; } 18 | 19 | /// 20 | /// Gets or sets the HTTP status code. 21 | /// 22 | public int StatusCode { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/Services/TranslatorService/TranslatorServiceException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Engine.Services.TranslatorService 8 | { 9 | /// 10 | /// The TranslatorServiceException class holds information about Exception related to . 11 | /// 12 | /// 13 | public class TranslatorServiceException : Exception 14 | { 15 | /// 16 | /// Initializes a new instance of the class using the specified error message. 17 | /// 18 | public TranslatorServiceException(string message) 19 | : base(message) 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Src/See4Me.Engine/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Src/See4Me.Localization/HowToUse.it.txt: -------------------------------------------------------------------------------- 1 | La funzionalità della PCL è stata ripresa da questo articolo: http://blog.giovannimodica.com/post/internationalization-of-a-cross-platform-application 2 | 3 | Per prima cosa scaricare l'estensione T4 Toolbox for Visual Studio 2015 4 | 5 | E' necessario inserire le coppie chiave-valore modificando il file AppResources.resx (e le relative localizzazioni) 6 | Successivamente va lanciato il custom tool sul file RES2OTHERS.TT che genererà i relativi file nel progetto DROID e IOS 7 | 8 | Come usare le traduzioni: 9 | 10 | - ANDROID 11 | - in text 12 | 13 | 18 | 19 | - in code 20 | 21 | label.Text = Resources.GetString(Resource.String.users); 22 | 23 | - IOS 24 | - in code 25 | 26 | label.Text = NSBundle.MainBundle.LocalizedString(Strings.users, Strings.users); -------------------------------------------------------------------------------- /Src/See4Me.Localization/HowToUse.txt: -------------------------------------------------------------------------------- 1 | This PCL has been developed following this article: http://blog.giovannimodica.com/post/internationalization-of-a-cross-platform-application 2 | 3 | First of all, you need to download the T4 Toolbox for Visual Studio 2015 Extensions. 4 | 5 | Then, insert translations in AppResources.resx (and relative localizations) and launch the custom tool RES2OTHERS.TT, that in turns will 6 | generate the necessary files for Android e iOS. 7 | 8 | How to use translations: 9 | 10 | - ANDROID 11 | 12 | - in text 13 | 14 | 19 | 20 | - in code 21 | 22 | label.Text = Resources.GetString(Resource.String.users); 23 | 24 | - IOS 25 | 26 | - in code 27 | 28 | label.Text = NSBundle.MainBundle.LocalizedString(Strings.users, Strings.users); -------------------------------------------------------------------------------- /Src/See4Me.Localization/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("See4Me.Localization")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("See4Me.Localization")] 14 | [assembly: AssemblyCopyright("Copyright © 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /Src/See4Me.Localization/Resources/Resx2OthersTemplate.cs: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Src/See4Me.Localization/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "supports": {}, 3 | "dependencies": {}, 4 | "frameworks": { 5 | ".NETPortable,Version=v4.5,Profile=Profile111": {} 6 | } 7 | } -------------------------------------------------------------------------------- /Src/See4Me.Shared/Common/AutoRelayCommand.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace See4Me.Common 11 | { 12 | public class AutoRelayCommand : GalaSoft.MvvmLight.Command.RelayCommand, IDisposable 13 | { 14 | private ISet properties; 15 | 16 | public AutoRelayCommand(Action execute) 17 | : base(execute) 18 | { 19 | this.Initialize(); 20 | } 21 | 22 | public AutoRelayCommand(Action execute, Func canExecute) 23 | : base(execute, canExecute) 24 | { 25 | this.Initialize(); 26 | } 27 | 28 | private void Initialize() 29 | { 30 | Messenger.Default.Register(this, true, (property) => 31 | { 32 | if (properties != null && properties.Contains(property.PropertyName)) 33 | this.RaiseCanExecuteChanged(); 34 | }); 35 | } 36 | 37 | public AutoRelayCommand DependsOn(Expression> propertyExpression) 38 | { 39 | if (properties == null) 40 | properties = new HashSet(); 41 | 42 | properties.Add(this.GetPropertyName(propertyExpression)); 43 | return this; 44 | } 45 | 46 | private string GetPropertyName(Expression> propertyExpression) 47 | { 48 | if (propertyExpression == null) 49 | throw new ArgumentNullException(nameof(propertyExpression)); 50 | 51 | var body = propertyExpression.Body as MemberExpression; 52 | if (body == null) 53 | throw new ArgumentException("Invalid argument", nameof(propertyExpression)); 54 | 55 | var property = body.Member as PropertyInfo; 56 | if (property == null) 57 | throw new ArgumentException("Argument is not a property", nameof(propertyExpression)); 58 | 59 | return property.Name; 60 | } 61 | 62 | public void Dispose() 63 | { 64 | Messenger.Default.Unregister(this); 65 | } 66 | } 67 | 68 | public class AutoRelayCommand : GalaSoft.MvvmLight.Command.RelayCommand, IDisposable 69 | { 70 | private ISet properties; 71 | 72 | public AutoRelayCommand(Action execute) 73 | : base(execute) 74 | { 75 | this.Initialize(); 76 | } 77 | 78 | public AutoRelayCommand(Action execute, Func canExecute) 79 | : base(execute, canExecute) 80 | { 81 | this.Initialize(); 82 | } 83 | 84 | private void Initialize() 85 | { 86 | Messenger.Default.Register(this, true, (property) => 87 | { 88 | if (properties != null && properties.Contains(property.PropertyName)) 89 | this.RaiseCanExecuteChanged(); 90 | }); 91 | } 92 | 93 | public AutoRelayCommand DependsOn(Expression> propertyExpression) 94 | { 95 | if (properties == null) 96 | properties = new HashSet(); 97 | 98 | properties.Add(this.GetPropertyName(propertyExpression)); 99 | return this; 100 | } 101 | 102 | private string GetPropertyName(Expression> propertyExpression) 103 | { 104 | if (propertyExpression == null) 105 | throw new ArgumentNullException(nameof(propertyExpression)); 106 | 107 | var body = propertyExpression.Body as MemberExpression; 108 | if (body == null) 109 | throw new ArgumentException("Invalid argument", nameof(propertyExpression)); 110 | 111 | var property = body.Member as PropertyInfo; 112 | if (property == null) 113 | throw new ArgumentException("Argument is not a property", nameof(propertyExpression)); 114 | 115 | return property.Name; 116 | } 117 | 118 | public void Dispose() 119 | { 120 | Messenger.Default.Unregister(this); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Common/VisionSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "MinimumConfidence": 0.16, 3 | "InvalidDescriptions": [ 4 | "is lit up at night", 5 | "person sitting at night", 6 | "a picture of a sign", 7 | "a room with a remote control", 8 | "a reflection in a mirror", 9 | "a dark night", 10 | "the dark", 11 | "a airplane that is on display", 12 | "an image of a bird", 13 | "a laptop is lit up on the screen", 14 | "himself in the mirror", 15 | "a blurry picture", 16 | "there is a guitar" 17 | ], 18 | "DescriptionsToRemove": [ 19 | "holding a wine glass", 20 | "holding a basketball bat", 21 | "holding a remote control", 22 | "holding a donut", 23 | "eating a donut", 24 | "and a tie", 25 | "and tie", 26 | "wearing a tie", 27 | "holding a wii remote", 28 | "brushing his teeth", 29 | "brushing her teeth", 30 | "with a remote", 31 | "the airplane is parked on the side of", 32 | "a picture of", 33 | "a view of", 34 | "a blurry photo of", 35 | "a blurry picture of", 36 | "a bird flying in", 37 | "a bird standing on the side of", 38 | "a bird is standing near", 39 | "a train is parked on the side of", 40 | "a man flying in", 41 | "a airplane that is flying in", 42 | "a plane flying in", 43 | "a close up of", 44 | "a bird walikng on", 45 | "a man laying on", 46 | "a white toilet sitting in", 47 | "a man riding a skateboard up", 48 | "a hot dog in", 49 | "playing a video game", 50 | "a street scene with focus on", 51 | "a man flying through", 52 | "a plane that is flying in", 53 | "a bird flying over", 54 | "the air while riding a skateboard on", 55 | "a bird walking on", 56 | "a clock tower in front of", 57 | "a clock sitting in front of", 58 | "a sign with a clock on", 59 | "an image of", 60 | "a boat is sitting on", 61 | "an umbrella is sitting on", 62 | "wearing a red umbrella", 63 | "a train sitting on" 64 | ], 65 | "DescriptionsToReplace": { 66 | "a man in a blue cloudy sky": "a blue cloudy sky", 67 | "a sidewalk with luggage": "a sidewalk", 68 | "a train traveling down tracks next to a mountain": "a mountain", 69 | "a train on a path": "a path", 70 | "a train is coming down the mountain": "a mountain", 71 | "a train going down the road": "a road", 72 | "a group of baseball players standing on the side of a road": "a road", 73 | "a baby sitting in a suitcase": "a baby", 74 | "a street scene": "a street", 75 | "a train traveling over a bridge": "a bridge", 76 | "a train is on the side of a road": "the side of a road", 77 | "a train traveling down tracks next to a highway": "a road", 78 | "a train is traveling down the road": "a road", 79 | "a train traveling down tracks next to a body of water": "a body of water", 80 | "a large long train on a bridge": "a bridge", 81 | "a large long train on a steel track": "a road", 82 | "a train on a steel track": "a road" 83 | } 84 | } -------------------------------------------------------------------------------- /Src/See4Me.Shared/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace See4Me 2 | { 3 | public static partial class Constants 4 | { 5 | public const string TakingPhoto = "TakingPhoto"; 6 | public const string PhotoTaken = "PhotoTaken"; 7 | public const string InitializeStreaming = "InitializeStreaming"; 8 | public const string VisionSettingsFile = "See4Me.Common.VisionSettings.json"; 9 | 10 | public const string Child = "Child"; 11 | public const string Boy = "Boy"; 12 | public const string Man = "Man"; 13 | public const string LookingMessage = "Looking"; 14 | public const string PersonAgeMessage = "PersonAgeMessage"; 15 | public const string EmotionMessage = "EmotionMessage"; 16 | 17 | public const string HowToRegisterUrl = "https://github.com/DotNetToscana/See4Me/blob/master/Docs/Register.md"; 18 | public const string CognitiveServicesUrl = "https://www.microsoft.com/cognitive-services"; 19 | public const string MicrosoftPrivacyPoliciesUrl = "https://go.microsoft.com/fwlink/?LinkId=521839"; 20 | public const string GitHubProjectUrl = "https://github.com/DotNetToscana/see4me"; 21 | public const string CognitiveServicesSubscriptionUrl = "https://www.microsoft.com/cognitive-services/en-us/sign-up"; 22 | public const string TranslatorServiceSubscriptionUrl = "https://portal.azure.com/#create/Microsoft.CognitiveServices/apitype/TextTranslation"; 23 | 24 | #if __ANDROID__ 25 | public const string SentenceEnd = " / "; 26 | #elif __IOS__ 27 | public const string SentenceEnd = "."; 28 | #else 29 | public const string SentenceEnd = ".."; 30 | #endif 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Extensions/ExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Practices.ServiceLocation; 2 | using See4Me.Localization.Resources; 3 | using See4Me.Services; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace See4Me.Extensions 9 | { 10 | public static class ExceptionExtensions 11 | { 12 | private static ISettingsService settings; 13 | 14 | static ExceptionExtensions() 15 | { 16 | settings = ServiceLocator.Current.GetInstance(); 17 | } 18 | 19 | public static string GetExceptionMessage(this Exception exception) 20 | { 21 | var error = AppResources.RecognitionError; 22 | 23 | if (settings.ShowExceptionOnError) 24 | error = $"{error} ({exception.Message})"; 25 | 26 | return error; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Extensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Extensions 8 | { 9 | public static class StreamExtensions 10 | { 11 | public static async Task ToArrayAsync(this Stream stream) 12 | { 13 | stream.Position = 0; 14 | 15 | using (var ms = new MemoryStream()) 16 | { 17 | await stream.CopyToAsync(ms); 18 | stream.Position = 0; 19 | return ms.ToArray(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/See4Me.Shared.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {a289f8ed-1de9-4381-bfcd-c092709e1849} 5 | SAK 6 | SAK 7 | SAK 8 | SAK 9 | 10 | 11 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 12 | true 13 | 9e2cec20-3ea7-4627-a5fb-1f57f0716aa2 14 | 15 | 16 | See4Me.Shared 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 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/See4Me.Shared.shproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9e2cec20-3ea7-4627-a5fb-1f57f0716aa2 5 | 14.0 6 | SAK 7 | SAK 8 | SAK 9 | SAK 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/ServiceKeys.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Practices.ServiceLocation; 2 | using See4Me.Services; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace See4Me 8 | { 9 | public static class ServiceKeys 10 | { 11 | #if DEBUG 12 | private const string visionSubscriptionKey = ""; 13 | private const string faceSubscriptionKey = ""; 14 | private const string translatorSubscriptionKey = ""; 15 | #else 16 | private const string visionSubscriptionKey = ""; 17 | private const string faceSubscriptionKey = ""; 18 | private const string translatorSubscriptionKey = ""; 19 | #endif 20 | 21 | private static readonly ISettingsService settings; 22 | 23 | static ServiceKeys() 24 | { 25 | settings = ServiceLocator.Current.GetInstance(); 26 | } 27 | 28 | public static string VisionSubscriptionKey 29 | { 30 | get { return GetValue(settings.VisionSubscriptionKey) ?? visionSubscriptionKey; } 31 | set { settings.VisionSubscriptionKey = value; } 32 | } 33 | 34 | public static string FaceSubscriptionKey 35 | { 36 | get { return GetValue(settings.FaceSubscriptionKey) ?? faceSubscriptionKey; } 37 | set { settings.FaceSubscriptionKey = value; } 38 | } 39 | 40 | public static string TranslatorSubscriptionKey 41 | { 42 | get { return GetValue(settings.TranslatorSubscriptionKey) ?? translatorSubscriptionKey; } 43 | set { settings.TranslatorSubscriptionKey = value; } 44 | } 45 | 46 | private static string GetValue(string value) 47 | { 48 | if (!string.IsNullOrWhiteSpace(value)) 49 | return value; 50 | 51 | return null; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/DialogService.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Localization.Resources; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.Services 9 | { 10 | public class DialogService : IDialogService 11 | { 12 | private GalaSoft.MvvmLight.Views.DialogService dialogService; 13 | 14 | public DialogService() 15 | { 16 | dialogService = new GalaSoft.MvvmLight.Views.DialogService(); 17 | } 18 | 19 | public Task ShowAsync(string message, string title = null, string buttonText = null, DialogIcon icon = DialogIcon.Question) 20 | => dialogService.ShowMessage(message, title ?? AppResources.ApplicationTitle, buttonText ?? AppResources.OK, null); 21 | 22 | public Task AskAsync(string message, string title = null, string buttonConfirmText = null, string buttonCancelText = null, DialogIcon icon = DialogIcon.Information) 23 | { 24 | var tcs = new TaskCompletionSource(); 25 | 26 | dialogService.ShowMessage(message, title ?? AppResources.ApplicationTitle, 27 | buttonConfirmText ?? AppResources.Yes, buttonCancelText ?? AppResources.No, 28 | (result) => { tcs.TrySetResult(result); }); 29 | 30 | return tcs.Task; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/IAppService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Services 8 | { 9 | public interface IAppService 10 | { 11 | string Version { get; } 12 | 13 | string Author { get; } 14 | 15 | string BlogUrl { get; } 16 | 17 | string TwitterUrl { get; } 18 | 19 | string LinkedInUrl { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/IDialogService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace See4Me.Services 7 | { 8 | public interface IDialogService 9 | { 10 | Task ShowAsync(string message, string title = null, string buttonText = null, DialogIcon icon = DialogIcon.Information); 11 | 12 | Task AskAsync(string message, string title = null, string buttonConfirmText = null, string buttonCancelText = null, DialogIcon icon = DialogIcon.Question); 13 | } 14 | 15 | public enum DialogIcon 16 | { 17 | None, 18 | Information, 19 | Question, 20 | Warning, 21 | Error 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/ILauncherService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Services 8 | { 9 | public interface ILauncherService 10 | { 11 | Task LaunchUriAsync(string uri); 12 | 13 | Task LaunchMailAsync(string mailAddress); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/IMediaPicker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.Services 9 | { 10 | public interface IMediaPicker 11 | { 12 | Task TakePhotoAsync(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/INavigationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Services 8 | { 9 | public enum Pages { MainPage, SettingsPage, AboutPage, PrivacyPolicyPage, RecognizeTextPage } 10 | 11 | public interface INavigationService 12 | { 13 | void GoBack(); 14 | 15 | void NavigateTo(string pageKey); 16 | 17 | void NavigateTo(string pageKey, object parameter); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/INetworkService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace See4Me.Services 7 | { 8 | public interface INetworkService 9 | { 10 | bool IsConnected { get; } 11 | 12 | event EventHandler ConnectivityChanged; 13 | 14 | Task IsInternetAvailableAsync(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/ISettingsService.cs: -------------------------------------------------------------------------------- 1 | namespace See4Me.Services 2 | { 3 | public interface ISettingsService 4 | { 5 | CameraPanel CameraPanel { get; set; } 6 | 7 | bool ShowRecognitionConfidence { get; set; } 8 | 9 | bool ShowExceptionOnError { get; set; } 10 | 11 | bool ShowOriginalDescriptionOnTranslation { get; set; } 12 | 13 | bool ShowRawDescriptionOnInvalidRecognition { get; set; } 14 | 15 | string VisionSubscriptionKey { get; set; } 16 | 17 | string FaceSubscriptionKey { get; set; } 18 | 19 | string TranslatorSubscriptionKey { get; set; } 20 | 21 | bool IsTextToSpeechEnabled { get; set; } 22 | 23 | bool IsConsentGiven { get; set; } 24 | 25 | bool ShowDescriptionOnFaceIdentification { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/ISpeechService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace See4Me.Services 4 | { 5 | public interface ISpeechService 6 | { 7 | string Language { get; set; } 8 | 9 | Task SpeechAsync(string text, string languge = null); 10 | } 11 | } -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/IStreamingService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | 4 | namespace See4Me.Services 5 | { 6 | public interface IStreamingService 7 | { 8 | ScenarioState CurrentState { get; } 9 | 10 | Task InitializeAsync(); 11 | 12 | Task CleanupAsync(); 13 | 14 | Task StartStreamingAsync(CameraPanel panel, object preview); 15 | 16 | Task GetCurrentFrameAsync(); 17 | 18 | Task StopStreamingAsync(); 19 | 20 | CameraPanel CameraPanel { get; } 21 | 22 | Task SwapCameraAsync(); 23 | } 24 | 25 | /// 26 | /// Values for identifying and controlling scenario states. 27 | /// 28 | public enum ScenarioState 29 | { 30 | /// 31 | /// Display is blank - default state. 32 | /// 33 | Idle, 34 | 35 | /// 36 | /// Webcam is actively engaged and a live video stream is displayed. 37 | /// 38 | Streaming 39 | } 40 | 41 | public enum CameraPanel 42 | { 43 | Unknown = 0, 44 | Front = 1, 45 | Back = 2 46 | } 47 | } -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/NetworkService.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight; 2 | using Plugin.Connectivity; 3 | using Plugin.Connectivity.Abstractions; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Net.Http; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace See4Me.Services 11 | { 12 | public class NetworkService : INetworkService, IDisposable 13 | { 14 | private readonly IConnectivity connectionManager; 15 | 16 | private const string CONNECTION_TEST_URL = "https://www.google.com"; 17 | private const int CONNECTION_TEST_TIMEOUT_MILLISECONDS = 5000; 18 | 19 | public bool IsConnected { get; private set; } 20 | 21 | public event EventHandler ConnectivityChanged; 22 | 23 | public NetworkService() 24 | { 25 | connectionManager = CrossConnectivity.Current; 26 | 27 | IsConnected = connectionManager.IsConnected; 28 | connectionManager.ConnectivityChanged += OnConnectivityChanged; 29 | } 30 | 31 | private void OnConnectivityChanged(object sender, ConnectivityChangedEventArgs e) 32 | { 33 | IsConnected = e.IsConnected; 34 | ConnectivityChanged?.Invoke(this, EventArgs.Empty); 35 | } 36 | 37 | public async Task IsInternetAvailableAsync() 38 | { 39 | try 40 | { 41 | if (IsConnected) 42 | { 43 | var isReachable = await connectionManager.IsRemoteReachable(CONNECTION_TEST_URL, msTimeout: CONNECTION_TEST_TIMEOUT_MILLISECONDS); 44 | return isReachable; 45 | } 46 | } 47 | catch { } 48 | 49 | return false; 50 | } 51 | 52 | public void Dispose() 53 | { 54 | connectionManager.ConnectivityChanged -= OnConnectivityChanged; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/SpeechHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Practices.ServiceLocation; 2 | using See4Me.Engine; 3 | using See4Me.Localization.Resources; 4 | using See4Me.Services; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | 11 | namespace See4Me.Services 12 | { 13 | public static class SpeechHelper 14 | { 15 | private static readonly ISettingsService settings; 16 | private static readonly ISpeechService speechService; 17 | 18 | static SpeechHelper() 19 | { 20 | settings = ServiceLocator.Current.GetInstance(); 21 | speechService = ServiceLocator.Current.GetInstance(); 22 | } 23 | 24 | public static FaceResultMessage GetFaceMessage(FaceResult face) 25 | { 26 | var result = new FaceResultMessage(); 27 | 28 | // Creates the face description text to be speeched. 29 | string faceMessage = null; 30 | string personMessage; 31 | 32 | if (!string.IsNullOrWhiteSpace(face.Name)) 33 | { 34 | // A person name has been identified. 35 | personMessage = $"{face.Name} "; 36 | 37 | if (settings.ShowRecognitionConfidence) 38 | { 39 | personMessage = $"{personMessage} ({Math.Round(face.IdentifyConfidence, 2)})"; 40 | } 41 | 42 | result.ContainsFace = true; 43 | } 44 | else 45 | { 46 | var ageDescription = GetAgeDescription(face.Age, face.Gender); 47 | personMessage = string.Format(GetString(Constants.PersonAgeMessage, face.Gender), ageDescription, face.Age); 48 | } 49 | 50 | if (face.Emotion != Emotion.Neutral) 51 | { 52 | var emotion = GetString(face.Emotion.ToString(), face.Gender).ToLower(); 53 | var lookingMessage = string.Format(GetString(Constants.LookingMessage, face.Gender), emotion); 54 | faceMessage = $"{personMessage} {lookingMessage}"; 55 | } 56 | else 57 | { 58 | // No emotion recognized, so includes only the person name or age in the message. 59 | faceMessage = personMessage; 60 | } 61 | 62 | faceMessage = $"{faceMessage} {Constants.SentenceEnd} "; 63 | result.Message = faceMessage; 64 | 65 | return result; 66 | } 67 | 68 | private static string GetAgeDescription(int age, Gender gender) 69 | { 70 | string key = null; 71 | 72 | if (age <= 13) 73 | key = Constants.Child; 74 | else if (age >= 14 && age <= 29) 75 | key = Constants.Boy; 76 | else 77 | key = Constants.Man; 78 | 79 | var ageDescription = GetString(key, gender).ToLower(); 80 | return ageDescription; 81 | } 82 | 83 | private static string GetString(string key, Gender gender) 84 | => AppResources.ResourceManager.GetString(key + gender.ToString()); 85 | 86 | public static async Task TrySpeechAsync(string message) 87 | { 88 | if (settings.IsTextToSpeechEnabled) 89 | { 90 | var speechMessage = Regex.Replace(message, @" ?\(.*?\)", string.Empty); 91 | await speechService.SpeechAsync(speechMessage); 92 | } 93 | } 94 | } 95 | 96 | public class FaceResultMessage 97 | { 98 | public bool ContainsFace { get; set; } 99 | 100 | public string Message { get; set; } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/Services/SpeechService.cs: -------------------------------------------------------------------------------- 1 | using Plugin.TextToSpeech; 2 | using Plugin.TextToSpeech.Abstractions; 3 | using System; 4 | using System.Threading.Tasks; 5 | using System.Linq; 6 | using System.Globalization; 7 | 8 | namespace See4Me.Services 9 | { 10 | public class SpeechService : ISpeechService 11 | { 12 | private readonly ITextToSpeech synthesizer; 13 | 14 | public SpeechService() 15 | { 16 | synthesizer = CrossTextToSpeech.Current; 17 | synthesizer.Init(); 18 | } 19 | 20 | public string Language { get; set; } 21 | 22 | public Task SpeechAsync(string text, string language = null) 23 | { 24 | CrossLocale? locale = null; 25 | language = language ?? Language; 26 | 27 | if (language != null) 28 | locale = new CrossLocale { Language = language, Country = language }; 29 | 30 | synthesizer.Speak(text, crossLocale: locale); 31 | return Task.FromResult(null); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GalaSoft.MvvmLight.Command; 3 | using GalaSoft.MvvmLight.Messaging; 4 | using See4Me.Common; 5 | using See4Me.Localization.Resources; 6 | using See4Me.Services; 7 | 8 | namespace See4Me.ViewModels 9 | { 10 | public partial class AboutViewModel : ViewModelBase 11 | { 12 | private readonly ILauncherService launcherService; 13 | private readonly IAppService appService; 14 | 15 | public string BlogUrl => appService.BlogUrl; 16 | 17 | public string TwitterUrl => appService.TwitterUrl; 18 | 19 | public string LinkedInUrl => appService.LinkedInUrl; 20 | 21 | public string CognitiveServicesUrl => Constants.CognitiveServicesUrl; 22 | 23 | public AutoRelayCommand GotoGitHubCommand { get; set; } 24 | 25 | public AutoRelayCommand GotoPrivacyPolicyCommand { get; set; } 26 | 27 | public AutoRelayCommand GotoUrlCommand { get; set; } 28 | 29 | public string AppVersion => appService.Version; 30 | 31 | public string ProjectAuthor => appService.Author; 32 | 33 | public AboutViewModel(ILauncherService launcherService, IAppService appService) 34 | { 35 | this.launcherService = launcherService; 36 | this.appService = appService; 37 | 38 | this.CreateCommands(); 39 | } 40 | 41 | private void CreateCommands() 42 | { 43 | GotoGitHubCommand = new AutoRelayCommand(() => launcherService.LaunchUriAsync(Constants.GitHubProjectUrl)); 44 | GotoUrlCommand = new AutoRelayCommand((url) => launcherService.LaunchUriAsync(url)); 45 | GotoPrivacyPolicyCommand = new AutoRelayCommand(() => AppNavigationService.NavigateTo(Pages.PrivacyPolicyPage.ToString())); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/ViewModels/PrivacyViewModel.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Common; 2 | using See4Me.Localization.Resources; 3 | using See4Me.Services; 4 | using System; 5 | 6 | 7 | namespace See4Me.ViewModels 8 | { 9 | public partial class PrivacyViewModel : ViewModelBase 10 | { 11 | private readonly ILauncherService launcherService; 12 | 13 | public AutoRelayCommand GotoCognitiveServicesUrlCommand { get; set; } 14 | 15 | public AutoRelayCommand GotoMicrosoftPrivacyPoliciesUrlCommand { get; set; } 16 | 17 | public PrivacyViewModel(ILauncherService launcherService, IAppService appService) 18 | { 19 | this.launcherService = launcherService; 20 | 21 | this.CreateCommands(); 22 | } 23 | 24 | private void CreateCommands() 25 | { 26 | GotoCognitiveServicesUrlCommand = new AutoRelayCommand(() => launcherService.LaunchUriAsync(Constants.CognitiveServicesUrl)); 27 | GotoMicrosoftPrivacyPoliciesUrlCommand = new AutoRelayCommand(() => launcherService.LaunchUriAsync(Constants.MicrosoftPrivacyPoliciesUrl)); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/ViewModels/RecognizeTextViewModel.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Command; 2 | using GalaSoft.MvvmLight.Messaging; 3 | using See4Me.Common; 4 | using See4Me.Localization.Resources; 5 | using See4Me.Services; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Diagnostics; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | using See4Me.Extensions; 12 | using System.IO; 13 | using System.Text; 14 | using System.Net; 15 | using See4Me.Engine; 16 | 17 | namespace See4Me.ViewModels 18 | { 19 | public partial class RecognizeTextViewModel : ViewModelBase 20 | { 21 | private readonly IMediaPicker mediaPicker; 22 | private readonly ISpeechService speechService; 23 | private readonly CognitiveClient cognitiveClient; 24 | 25 | public AutoRelayCommand TakePhotoCommand { get; set; } 26 | 27 | public string message; 28 | public string Message 29 | { 30 | get { return message; } 31 | set { this.Set(ref message, value, broadcast: true); } 32 | } 33 | 34 | public RecognizeTextViewModel(CognitiveClient cognitiveClient, IMediaPicker mediaPicker, ISpeechService speechService) 35 | { 36 | this.cognitiveClient = cognitiveClient; 37 | this.mediaPicker = mediaPicker; 38 | this.speechService = speechService; 39 | 40 | this.CreateCommands(); 41 | } 42 | 43 | private void CreateCommands() 44 | { 45 | TakePhotoCommand = new AutoRelayCommand(async () => await TakePhotoAsync(), () => !IsBusy).DependsOn(() => IsBusy); 46 | } 47 | 48 | private async Task TakePhotoAsync() 49 | { 50 | IsBusy = true; 51 | 52 | string recognizeText = null; 53 | 54 | try 55 | { 56 | using (var stream = await mediaPicker.TakePhotoAsync()) 57 | { 58 | if (stream != null) 59 | { 60 | var imageBytes = await stream.ToArrayAsync(); 61 | MessengerInstance.Send(new NotificationMessage(imageBytes, Constants.PhotoTaken)); 62 | Message = null; 63 | 64 | if (await NetworkService.IsInternetAvailableAsync()) 65 | { 66 | var result = await cognitiveClient.AnalyzeAsync(stream, Language, RecognitionType.Text); 67 | var ocrResult = result.OcrResult; 68 | 69 | if (ocrResult.ContainsText) 70 | recognizeText = ocrResult.Text; 71 | else 72 | recognizeText = AppResources.UnableToRecognizeText; 73 | } 74 | else 75 | { 76 | // Internet isn't available, the service cannot be reached. 77 | recognizeText = AppResources.NoConnection; 78 | } 79 | } 80 | else 81 | { 82 | // If message is null at this point, this is the first request. If we cancel it, turns automatically to the 83 | // previous page. 84 | if (message == null) 85 | AppNavigationService.GoBack(); 86 | 87 | IsBusy = false; 88 | return; 89 | } 90 | } 91 | } 92 | catch (CognitiveException ex) 93 | { 94 | // Unable to access the service (message contains translated error details). 95 | recognizeText = ex.Message; 96 | } 97 | catch (WebException) 98 | { 99 | // Internet isn't available, the service cannot be reached. 100 | recognizeText = AppResources.NoConnection; 101 | } 102 | catch (Exception ex) 103 | { 104 | var error = AppResources.RecognitionError; 105 | 106 | if (Settings.ShowExceptionOnError) 107 | error = $"{error} ({ex.Message})"; 108 | 109 | recognizeText = error; 110 | } 111 | 112 | // Shows the result. 113 | Message = this.GetNormalizedMessage(recognizeText); 114 | IsBusy = false; 115 | } 116 | 117 | private string GetNormalizedMessage(string message) => message; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Src/See4Me.Shared/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Practices.ServiceLocation; 2 | using See4Me.Services; 3 | using GalaSoft.MvvmLight.Threading; 4 | using Newtonsoft.Json; 5 | using GalaSoft.MvvmLight.Views; 6 | 7 | namespace See4Me.ViewModels 8 | { 9 | public abstract partial class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase 10 | { 11 | protected ISettingsService Settings { get; } 12 | 13 | protected INetworkService NetworkService { get; } 14 | 15 | protected Services.INavigationService AppNavigationService { get; } 16 | 17 | protected Services.IDialogService DialogService { get; } 18 | 19 | public ViewModelBase() 20 | { 21 | Settings = ServiceLocator.Current.GetInstance(); 22 | NetworkService = ServiceLocator.Current.GetInstance(); 23 | 24 | AppNavigationService = ServiceLocator.Current.GetInstance(); 25 | DialogService = ServiceLocator.Current.GetInstance(); 26 | 27 | IsConnected = NetworkService.IsConnected; 28 | NetworkService.ConnectivityChanged += (s, e) => 29 | { 30 | DispatcherHelper.CheckBeginInvokeOnUI(() => IsConnected = NetworkService.IsConnected); 31 | }; 32 | } 33 | 34 | private bool isBusy; 35 | public bool IsBusy 36 | { 37 | get { return isBusy; } 38 | set 39 | { 40 | if (this.SetBusy(value) && !isBusy) 41 | BusyMessage = null; 42 | } 43 | } 44 | 45 | private string busyMessage; 46 | public string BusyMessage 47 | { 48 | get { return busyMessage; } 49 | set { this.Set(ref busyMessage, value, broadcast: true); } 50 | } 51 | 52 | public bool SetBusy(bool value, string message = null) 53 | { 54 | BusyMessage = message; 55 | 56 | var isSet = this.Set(() => IsBusy, ref isBusy, value, broadcast: true); 57 | if (isSet) 58 | { 59 | OnIsBusyChangedBase(); 60 | OnIsBusyChanged(); 61 | } 62 | 63 | return isSet; 64 | } 65 | 66 | private bool isConnected; 67 | public bool IsConnected 68 | { 69 | get { return isConnected; } 70 | set 71 | { 72 | if (this.Set(ref isConnected, value, broadcast: true)) 73 | { 74 | OnNetworkAvailabilityChangedBase(); 75 | OnNetworkAvailabilityChanged(); 76 | } 77 | } 78 | } 79 | 80 | public string Language => ViewModelLocator.GetLanguage(); 81 | 82 | protected virtual void OnIsBusyChanged() { } 83 | 84 | protected virtual void OnNetworkAvailabilityChanged() { } 85 | 86 | partial void OnIsBusyChangedBase(); 87 | 88 | partial void OnNetworkAvailabilityChangedBase(); 89 | } 90 | } -------------------------------------------------------------------------------- /Src/See4Me.Shared/ViewModels/ViewModelLocator.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Ioc; 2 | using GalaSoft.MvvmLight.Views; 3 | using Microsoft.Practices.ServiceLocation; 4 | using Newtonsoft.Json; 5 | using See4Me.Engine; 6 | using See4Me.Engine.Services.ServiceSettings; 7 | using See4Me.Services; 8 | using System.Globalization; 9 | using System.IO; 10 | using System.Reflection; 11 | 12 | namespace See4Me.ViewModels 13 | { 14 | public partial class ViewModelLocator 15 | { 16 | public void Initialize(Services.INavigationService navigationService) 17 | { 18 | SimpleIoc.Default.Register(() => navigationService); 19 | } 20 | 21 | static ViewModelLocator() 22 | { 23 | ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 24 | 25 | SimpleIoc.Default.Register(() => 26 | { 27 | VisionSettings visionSettings = null; 28 | using (var stream = typeof(ViewModelLocator).GetTypeInfo().Assembly.GetManifestResourceStream(Constants.VisionSettingsFile)) 29 | { 30 | using (var reader = new StreamReader(stream)) 31 | visionSettings = JsonConvert.DeserializeObject(reader.ReadToEnd()); 32 | } 33 | 34 | var visionSettingsProvider = new SimpleVisionSettingsProvider(visionSettings); 35 | var cognitiveClient = new CognitiveClient(visionSettingsProvider); 36 | 37 | var cognitiveSettings = cognitiveClient.Settings; 38 | cognitiveSettings.VisionSubscriptionKey = ServiceKeys.VisionSubscriptionKey; 39 | cognitiveSettings.FaceSubscriptionKey = ServiceKeys.FaceSubscriptionKey; 40 | cognitiveSettings.TranslatorSubscriptionKey = ServiceKeys.TranslatorSubscriptionKey; 41 | 42 | return cognitiveClient; 43 | }); 44 | 45 | SimpleIoc.Default.Register(() => 46 | { 47 | var language = GetLanguage(); 48 | var service = new SpeechService { Language = language }; 49 | return service; 50 | }); 51 | 52 | SimpleIoc.Default.Register(); 53 | SimpleIoc.Default.Register(); 54 | SimpleIoc.Default.Register(); 55 | SimpleIoc.Default.Register(); 56 | SimpleIoc.Default.Register(); 57 | SimpleIoc.Default.Register(); 58 | SimpleIoc.Default.Register(); 59 | 60 | SimpleIoc.Default.Register(); 61 | SimpleIoc.Default.Register(); 62 | SimpleIoc.Default.Register(); 63 | SimpleIoc.Default.Register(); 64 | SimpleIoc.Default.Register(); 65 | 66 | OnInitialize(); 67 | } 68 | 69 | public MainViewModel MainViewModel => ServiceLocator.Current.GetInstance(); 70 | 71 | public SettingsViewModel SettingsViewModel => ServiceLocator.Current.GetInstance(); 72 | 73 | public AboutViewModel AboutViewModel => ServiceLocator.Current.GetInstance(); 74 | 75 | public RecognizeTextViewModel RecognizeTextViewModel => ServiceLocator.Current.GetInstance(); 76 | 77 | public PrivacyViewModel PrivacyViewModel => ServiceLocator.Current.GetInstance(); 78 | 79 | static partial void OnInitialize(); 80 | 81 | private static CultureInfo culture; 82 | public static string GetLanguage() 83 | { 84 | if (culture == null) 85 | { 86 | #if __ANDROID__ || __IOS__ 87 | var language = Localization.Resources.AppResources.ResourceLanguage; 88 | #else 89 | var language = Windows.System.UserProfile.GlobalizationPreferences.Languages[0]; 90 | #endif 91 | 92 | culture = new CultureInfo(language); 93 | if (!culture.IsNeutralCulture) 94 | culture = culture.Parent; 95 | } 96 | 97 | return culture.TwoLetterISOLanguageName; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/App.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Views; 2 | using System.Threading.Tasks; 3 | using Windows.ApplicationModel.Activation; 4 | using GalaSoft.MvvmLight.Threading; 5 | using Windows.ApplicationModel; 6 | using Microsoft.Practices.ServiceLocation; 7 | using See4Me.Services; 8 | using See4Me.ViewModels; 9 | using Windows.Globalization; 10 | using Template10.Common; 11 | 12 | namespace See4Me 13 | { 14 | sealed partial class App : BootStrapper 15 | { 16 | /// 17 | /// Initializes the singleton application object. This is the first line of authored code 18 | /// executed, and as such is the logical equivalent of main() or WinMain(). 19 | /// 20 | public App() 21 | { 22 | this.InitializeComponent(); 23 | } 24 | 25 | public override Task OnInitializeAsync(IActivatedEventArgs args) 26 | { 27 | ApplicationLanguages.PrimaryLanguageOverride = ViewModelLocator.GetLanguage(); 28 | 29 | var keys = PageKeys(); 30 | keys.Add(Pages.MainPage, typeof(MainPage)); 31 | keys.Add(Pages.SettingsPage, typeof(SettingsPage)); 32 | keys.Add(Pages.AboutPage, typeof(AboutPage)); 33 | keys.Add(Pages.RecognizeTextPage, typeof(RecognizeTextPage)); 34 | keys.Add(Pages.PrivacyPolicyPage, typeof(PrivacyPolicyPage)); 35 | 36 | var navigationService = new NavigationService(); 37 | var locator = Resources["Locator"] as ViewModelLocator; 38 | locator.Initialize(navigationService); 39 | 40 | // MVVM Light's DispatcherHelper for cross-thread handling. 41 | DispatcherHelper.Initialize(); 42 | 43 | return base.OnInitializeAsync(args); 44 | } 45 | 46 | public override Task OnStartAsync(StartKind startKind, IActivatedEventArgs args) 47 | { 48 | NavigationService.Navigate(Pages.MainPage); 49 | return Task.CompletedTask; 50 | } 51 | 52 | public override async void OnResuming(object s, object e, AppExecutionState previousExecutionState) 53 | { 54 | // Resumes the camera streaming. 55 | await ViewModelLocator.ResumeAsync(); 56 | 57 | base.OnResuming(s, e, previousExecutionState); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Original/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Original/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Original/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Original/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Original/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Original/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Original/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Original/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Original/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Original/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Sounds/Shutter.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Sounds/Shutter.mp3 -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square310x310Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square310x310Logo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square310x310Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square310x310Logo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square310x310Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square310x310Logo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square310x310Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square310x310Logo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square310x310Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square310x310Logo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square71x71Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square71x71Logo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square71x71Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square71x71Logo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square71x71Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square71x71Logo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square71x71Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square71x71Logo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Square71x71Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Square71x71Logo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Assets/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.Windows/Assets/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /Src/See4Me.Windows/Behaviors/CameraPressedBehavior.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xaml.Interactivity; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.CompilerServices; 4 | using Windows.Phone.UI.Input; 5 | using Windows.UI.Xaml; 6 | using Windows.UI.Xaml.Markup; 7 | 8 | namespace See4Me.Behaviors 9 | { 10 | /// 11 | /// A behavior that listens for a specified event on its source and executes its actions when that event is fired. 12 | /// 13 | [ContentProperty(Name = "Actions")] 14 | public sealed class CameraPressedBehavior : Behavior 15 | { 16 | /// 17 | /// Identifies the dependency property. 18 | /// 19 | [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] 20 | public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register( 21 | "Actions", 22 | typeof(ActionCollection), 23 | typeof(CameraPressedBehavior), 24 | new PropertyMetadata(null)); 25 | 26 | /// 27 | /// Gets the collection of actions associated with the behavior. This is a dependency property. 28 | /// 29 | public ActionCollection Actions 30 | { 31 | get 32 | { 33 | var actionCollection = (ActionCollection)this.GetValue(ActionsProperty); 34 | if (actionCollection == null) 35 | { 36 | actionCollection = new ActionCollection(); 37 | this.SetValue(ActionsProperty, actionCollection); 38 | } 39 | 40 | return actionCollection; 41 | } 42 | } 43 | 44 | [PlatformSpecific] 45 | private readonly bool isTypePresent; 46 | 47 | public CameraPressedBehavior() 48 | { 49 | isTypePresent = Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"); 50 | } 51 | 52 | /// 53 | /// Called after the behavior is attached to the . 54 | /// 55 | protected override void OnAttached() 56 | { 57 | base.OnAttached(); 58 | 59 | if (isTypePresent) 60 | HardwareButtons.CameraPressed += HardwareButtons_CameraPressed; 61 | } 62 | 63 | /// 64 | /// Called when the behavior is being detached from its . 65 | /// 66 | protected override void OnDetaching() 67 | { 68 | base.OnDetaching(); 69 | 70 | if (isTypePresent) 71 | HardwareButtons.CameraPressed -= HardwareButtons_CameraPressed; 72 | } 73 | 74 | private void HardwareButtons_CameraPressed(object sender, CameraEventArgs e) 75 | { 76 | this.OnEvent(this.AssociatedObject, null); 77 | } 78 | 79 | private void OnEvent(object sender, object eventArgs) 80 | { 81 | Interaction.ExecuteActions(this, this.Actions, eventArgs); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Behaviors/PushButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Windows.ApplicationModel.Core; 9 | using Windows.Devices.Gpio; 10 | using Windows.UI.Core; 11 | 12 | namespace See4Me.Behaviors 13 | { 14 | public enum ButtonType 15 | { 16 | PullDown = 0, 17 | PullUp = 1 18 | } 19 | 20 | public class PushButton : IDisposable 21 | { 22 | public readonly GpioController controller; 23 | public readonly GpioPin pin; 24 | 25 | private readonly GpioPinValue actualLowPinValue; 26 | private readonly GpioPinValue actualHighPinValue; 27 | 28 | private GpioPinValue lastPinValue; 29 | 30 | public bool IsPressed { get; private set; } = false; 31 | 32 | public PushButtonBehavior Behavior { get; } 33 | 34 | public event EventHandler Pressed; 35 | public event EventHandler Released; 36 | public event EventHandler Click; 37 | public event EventHandler LongClick; 38 | 39 | private readonly Stopwatch longClickWatch; 40 | private readonly TimeSpan longClickTimeout = TimeSpan.FromMilliseconds(1200); 41 | 42 | [PlatformSpecific] 43 | public PushButton(int pinNumber, ButtonType type = ButtonType.PullDown, PushButtonBehavior behavior = null) 44 | { 45 | Behavior = behavior; 46 | longClickWatch = new Stopwatch(); 47 | 48 | controller = GpioController.GetDefault(); 49 | pin = controller.OpenPin(pinNumber); 50 | 51 | if (type == ButtonType.PullUp) 52 | { 53 | actualHighPinValue = GpioPinValue.High; 54 | actualLowPinValue = GpioPinValue.Low; 55 | } 56 | else 57 | { 58 | actualHighPinValue = GpioPinValue.Low; 59 | actualLowPinValue = GpioPinValue.High; 60 | } 61 | 62 | pin.Write(actualLowPinValue); 63 | pin.SetDriveMode(GpioPinDriveMode.Input); 64 | 65 | lastPinValue = actualLowPinValue; 66 | 67 | pin.DebounceTimeout = TimeSpan.FromMilliseconds(20); 68 | pin.ValueChanged += Pin_ValueChanged; 69 | } 70 | 71 | [PlatformSpecific] 72 | private void Pin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args) 73 | { 74 | var currentPinValue = pin.Read(); 75 | 76 | // If same value of last read, exits. 77 | if (currentPinValue == lastPinValue) 78 | return; 79 | 80 | // Checks the pin value. 81 | if (currentPinValue == actualHighPinValue) 82 | { 83 | longClickWatch.Restart(); 84 | 85 | IsPressed = true; 86 | this.RaiseEvent(Pressed); 87 | } 88 | else if (currentPinValue == actualLowPinValue) 89 | { 90 | longClickWatch.Stop(); 91 | 92 | this.RaiseEvent(Released); 93 | 94 | if (IsPressed) 95 | { 96 | IsPressed = false; 97 | 98 | if (longClickWatch.Elapsed > longClickTimeout) 99 | this.RaiseEvent(LongClick); 100 | else 101 | this.RaiseEvent(Click); 102 | } 103 | } 104 | 105 | lastPinValue = currentPinValue; 106 | } 107 | 108 | [PlatformSpecific] 109 | public void Dispose() 110 | { 111 | pin.ValueChanged -= Pin_ValueChanged; 112 | pin.Dispose(); 113 | } 114 | 115 | private async void RaiseEvent(EventHandler eventHandler) 116 | { 117 | var dispatcher = CoreApplication.MainView?.CoreWindow?.Dispatcher; 118 | if (dispatcher != null) 119 | await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => eventHandler?.Invoke(this, EventArgs.Empty)); 120 | else 121 | eventHandler?.Invoke(this, EventArgs.Empty); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me 8 | { 9 | public static partial class Constants 10 | { 11 | public const string WindowsMobileFamily = "Windows.Mobile"; 12 | public const string WindowsIoTFamily = "Windows.IoT"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Extensions/ImageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Windows.Graphics.Imaging; 9 | using Windows.Storage.Streams; 10 | using Windows.UI.Xaml.Controls; 11 | using Windows.UI.Xaml.Media; 12 | using Windows.UI.Xaml.Media.Imaging; 13 | 14 | namespace See4Me.Extensions 15 | { 16 | public static class ImageExtensions 17 | { 18 | public static async Task AsSoftwareBitmapAsync(this Stream stream) 19 | { 20 | var decoder = await BitmapDecoder.CreateAsync(stream.AsRandomAccessStream()); 21 | var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 22 | 23 | var softwareBitmapBGR8 = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied); 24 | return softwareBitmapBGR8; 25 | } 26 | 27 | public static async Task AsImageSourceAsync(this SoftwareBitmap softwareBitmap) 28 | { 29 | var bitmapSource = new SoftwareBitmapSource(); 30 | await bitmapSource.SetBitmapAsync(softwareBitmap); 31 | 32 | return bitmapSource; 33 | } 34 | 35 | public static async Task AsImageSourceAsync(this Stream stream) 36 | { 37 | var softwareBitmap = await stream.AsSoftwareBitmapAsync(); 38 | var bitmapSource = await softwareBitmap.AsImageSourceAsync(); 39 | 40 | return bitmapSource; 41 | } 42 | 43 | public static async Task SetSourceAsync(this BitmapImage image, byte[] buffer) 44 | { 45 | using (var stream = new InMemoryRandomAccessStream()) 46 | { 47 | await stream.WriteAsync(buffer.AsBuffer()); 48 | stream.Seek(0); 49 | 50 | await image.SetSourceAsync(stream); 51 | } 52 | } 53 | 54 | public static async Task SetSourceAsync(this Image image, byte[] buffer) 55 | { 56 | using (var ms = new MemoryStream(buffer)) 57 | image.Source = await ms.AsImageSourceAsync(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/LocalizedStrings.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Localization.Resources; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me 9 | { 10 | public class LocalizedStrings 11 | { 12 | private static AppResources localizedResources = new AppResources(); 13 | 14 | public AppResources LocalizedResources => localizedResources; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | See4Me 7 | Marco Minerva 8 | Assets\StoreLogo.png 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 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("See4Me")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("See4Me")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Version information for an assembly consists of the following four values: 17 | // 18 | // Major Version 19 | // Minor Version 20 | // Build Number 21 | // Revision 22 | // 23 | // You can specify all the values or you can default the Build and Revision Numbers 24 | // by using the '*' as shown below: 25 | // [assembly: AssemblyVersion("1.0.*")] 26 | [assembly: AssemblyVersion("1.0.0.0")] 27 | [assembly: AssemblyFileVersion("1.0.0.0")] 28 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Src/See4Me.Windows/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Services/AppService.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Localization.Resources; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Windows.ApplicationModel; 8 | 9 | namespace See4Me.Services 10 | { 11 | public class AppService : IAppService 12 | { 13 | private const string BLOG_URL = "https://marcominerva.wordpress.com"; 14 | private const string TWITTER_URL = "https://twitter.com/marcominerva"; 15 | private const string LINKEDIN_URL = "https://www.linkedin.com/in/marcominerva"; 16 | 17 | public string Version 18 | { 19 | get 20 | { 21 | var version = Package.Current.Id.Version; 22 | return $"{version.Major}.{version.Minor}.{version.Build}"; 23 | } 24 | } 25 | 26 | public string Author => AppResources.WindowsProjectAuthor; 27 | 28 | public string BlogUrl => BLOG_URL; 29 | 30 | public string TwitterUrl => TWITTER_URL; 31 | 32 | public string LinkedInUrl => LINKEDIN_URL; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Services/LauncherService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.System; 7 | 8 | namespace See4Me.Services 9 | { 10 | public class LauncherService : ILauncherService 11 | { 12 | public Task LaunchUriAsync(string uri) => Launcher.LaunchUriAsync(new Uri(uri)).AsTask(); 13 | 14 | public Task LaunchMailAsync(string mailAddress) => this.LaunchUriAsync($"mailto:{mailAddress}"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Services/MediaPicker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Windows.Media.Capture; 8 | using Windows.Storage; 9 | 10 | namespace See4Me.Services 11 | { 12 | public class MediaPicker : IMediaPicker 13 | { 14 | public async Task TakePhotoAsync() 15 | { 16 | var captureUI = new CameraCaptureUI(); 17 | captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg; 18 | captureUI.PhotoSettings.AllowCropping = true; 19 | captureUI.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.MediumXga; ; 20 | 21 | var photo = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo); 22 | 23 | if (photo != null) 24 | { 25 | var stream = await photo.OpenAsync(FileAccessMode.Read); 26 | return stream.AsStreamForRead(); 27 | } 28 | 29 | return null; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Template10.Common; 7 | 8 | namespace See4Me.Services 9 | { 10 | public class NavigationService : INavigationService 11 | { 12 | private Template10.Services.NavigationService.INavigationService navigationService; 13 | private Template10.Services.NavigationService.INavigationService Navigator 14 | { 15 | get 16 | { 17 | if (navigationService == null) 18 | navigationService = WindowWrapper.Current().NavigationServices.FirstOrDefault(); 19 | 20 | return navigationService; 21 | } 22 | } 23 | 24 | public void GoBack() 25 | { 26 | if (Navigator.CanGoBack) 27 | Navigator.GoBack(); 28 | } 29 | 30 | public void NavigateTo(string pageKey) => NavigateTo(pageKey, null); 31 | 32 | public void NavigateTo(string pageKey, object parameter) 33 | { 34 | Pages key; 35 | if (Enum.TryParse(pageKey, out key)) 36 | Navigator.Navigate(key, null); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Services/StreamResolution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.Media.MediaProperties; 7 | 8 | namespace See4Me.Services 9 | { 10 | /// 11 | /// Wrapper class around IMediaEncodingProperties to help how devices report supported resolutions 12 | /// 13 | public class StreamResolution 14 | { 15 | private readonly IMediaEncodingProperties properties; 16 | 17 | public StreamResolution(IMediaEncodingProperties properties) 18 | { 19 | if (properties == null) 20 | throw new ArgumentNullException(nameof(properties)); 21 | 22 | // Only handle ImageEncodingProperties and VideoEncodingProperties, which are the two types that GetAvailableMediaStreamProperties can return 23 | if (!(properties is ImageEncodingProperties) && !(properties is VideoEncodingProperties)) 24 | throw new ArgumentException($"Argument is of the wrong type. Required: {typeof(ImageEncodingProperties).Name} or {typeof(VideoEncodingProperties).Name}.", nameof(properties)); 25 | 26 | // Store the actual instance of the IMediaEncodingProperties for setting them later 27 | this.properties = properties; 28 | } 29 | 30 | public uint Width 31 | { 32 | get 33 | { 34 | if (properties is ImageEncodingProperties) 35 | return (properties as ImageEncodingProperties).Width; 36 | 37 | else if (properties is VideoEncodingProperties) 38 | return (properties as VideoEncodingProperties).Width; 39 | 40 | return 0; 41 | } 42 | } 43 | 44 | public uint Height 45 | { 46 | get 47 | { 48 | if (properties is ImageEncodingProperties) 49 | return (properties as ImageEncodingProperties).Height; 50 | 51 | if (properties is VideoEncodingProperties) 52 | return (properties as VideoEncodingProperties).Height; 53 | 54 | return 0; 55 | } 56 | } 57 | 58 | public uint FrameRate 59 | { 60 | get 61 | { 62 | if (properties is VideoEncodingProperties) 63 | { 64 | if ((properties as VideoEncodingProperties).FrameRate.Denominator != 0) 65 | return (properties as VideoEncodingProperties).FrameRate.Numerator / (properties as VideoEncodingProperties).FrameRate.Denominator; 66 | } 67 | 68 | return 0; 69 | } 70 | } 71 | 72 | public double AspectRatio => Math.Round((Height != 0) ? (Width / (double)Height) : double.NaN, 2); 73 | 74 | public IMediaEncodingProperties EncodingProperties => properties; 75 | 76 | /// 77 | /// Output properties to a readable format for UI purposes 78 | /// eg. 1920x1080 [1.78] 30fps MPEG 79 | /// 80 | /// Readable string 81 | public string GetFriendlyName(bool showFrameRate = true) 82 | { 83 | if (properties is ImageEncodingProperties || !showFrameRate) 84 | return $"{Width}x{Height} [{AspectRatio}] {properties.Subtype}"; 85 | 86 | if (properties is VideoEncodingProperties) 87 | return $"{Width}x{Height} [{AspectRatio}] {FrameRate} FPS {properties.Subtype}"; 88 | 89 | return string.Empty; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Styles/Styles.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 9 | 10 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using See4Me.Common; 2 | using See4Me.Services; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Windows.UI.Xaml.Navigation; 8 | using Template10.Services.NavigationService; 9 | using Microsoft.Practices.ServiceLocation; 10 | using See4Me.Localization.Resources; 11 | using System; 12 | using Windows.System; 13 | using Windows.Foundation.Metadata; 14 | using System.Runtime.CompilerServices; 15 | 16 | namespace See4Me.ViewModels 17 | { 18 | public partial class MainViewModel : ViewModelBase 19 | { 20 | public AutoRelayCommand ShutdownCommand { get; set; } 21 | 22 | partial void OnCreateCommands() 23 | { 24 | ShutdownCommand = new AutoRelayCommand(async () => await Shutdown(), () => !IsBusy).DependsOn(() => IsBusy); 25 | } 26 | 27 | public async Task Shutdown() 28 | { 29 | try 30 | { 31 | // Shutdowns the device immediately. 32 | if (ApiInformation.IsTypePresent("Windows.System.ShutdownManager")) 33 | { 34 | IsBusy = true; 35 | StatusMessage = AppResources.ShuttingDown; 36 | await SpeechHelper.TrySpeechAsync(AppResources.ShuttingDown); 37 | 38 | ShutdownManager.BeginShutdown(ShutdownKind.Shutdown, TimeSpan.FromSeconds(3)); 39 | } 40 | } 41 | catch { } 42 | finally 43 | { 44 | IsBusy = false; 45 | } 46 | } 47 | 48 | public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary state) 49 | { 50 | // Calls methods to initialize the app. 51 | await this.InitializeStreamingAsync(); 52 | await this.CheckShowConsentAsync(); 53 | 54 | DescribeImageCommand.RaiseCanExecuteChanged(); 55 | SwapCameraCommand.RaiseCanExecuteChanged(); 56 | GotoRecognizeTextCommand.RaiseCanExecuteChanged(); 57 | HowToRegisterCommand.RaiseCanExecuteChanged(); 58 | 59 | await base.OnNavigatedToAsync(parameter, mode, state); 60 | } 61 | 62 | public override async Task OnNavigatedFromAsync(IDictionary state, bool suspending) 63 | { 64 | // When navigating away from this page (even for suspending), cleanup the associated resources. 65 | await this.CleanupAsync(); 66 | 67 | await base.OnNavigatedFromAsync(state, suspending); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/ViewModels/RecognizeTextViewModel.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Command; 2 | using GalaSoft.MvvmLight.Messaging; 3 | using See4Me.Common; 4 | using See4Me.Services; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using Windows.UI.Xaml.Navigation; 10 | using Template10.Services.NavigationService; 11 | using Microsoft.Practices.ServiceLocation; 12 | 13 | namespace See4Me.ViewModels 14 | { 15 | public partial class RecognizeTextViewModel : ViewModelBase 16 | { 17 | public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary state) 18 | { 19 | TakePhotoCommand.Execute(null); 20 | 21 | await base.OnNavigatedToAsync(parameter, mode, state); 22 | } 23 | 24 | public override async Task OnNavigatedFromAsync(IDictionary state, bool suspending) 25 | { 26 | await base.OnNavigatedFromAsync(state, suspending); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/ViewModels/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Command; 2 | using GalaSoft.MvvmLight.Messaging; 3 | using See4Me.Common; 4 | using See4Me.Services; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using Windows.UI.Xaml.Navigation; 10 | using Template10.Services.NavigationService; 11 | using Microsoft.Practices.ServiceLocation; 12 | using System; 13 | 14 | namespace See4Me.ViewModels 15 | { 16 | public partial class SettingsViewModel : ViewModelBase 17 | { 18 | private const string SHOW_RECOGNITION_CONFIDENCE = "ShowRecognitionConfidence"; 19 | private const string SHOW_ORIGINAL_DESCRIPTION_ON_TRANSLATION = "ShowOriginalDescriptionOnTranslation"; 20 | private const string VISION_SUBSCRIPTION_KEY = "VisionSubscriptionKey"; 21 | private const string FACE_SUBSCRIPTION_KEY = "FaceSubscriptionKey"; 22 | private const string EMOTION_SUBSCRIPTION_KEY = "EmotionSubscriptionKey"; 23 | private const string TRANSLATOR_SUBSCRIPTION_KEY = "TranslatorSubscriptionKey"; 24 | private const string IS_TEXT_TO_SPEECH_ENABLED = "IsTextToSpeechEnabled"; 25 | private const string SHOW_DESCRIPTION_ON_FACE_IDENTIFICATION = "ShowDescriptionOnFaceIdentification"; 26 | 27 | public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary state) 28 | { 29 | if (mode != NavigationMode.Back) 30 | { 31 | this.Initialize(); 32 | } 33 | 34 | if (state.Any()) 35 | { 36 | try 37 | { 38 | this.Restore(state); 39 | } 40 | catch { } 41 | finally 42 | { 43 | state.Clear(); 44 | } 45 | } 46 | 47 | await base.OnNavigatedToAsync(parameter, mode, state); 48 | } 49 | 50 | public override Task OnNavigatingFromAsync(NavigatingEventArgs args) 51 | { 52 | this.Save(); 53 | return base.OnNavigatingFromAsync(args); 54 | } 55 | 56 | public override Task OnNavigatedFromAsync(IDictionary state, bool suspending) 57 | { 58 | if (suspending) 59 | { 60 | state[SHOW_RECOGNITION_CONFIDENCE] = showRecognitionConfidence; 61 | state[SHOW_ORIGINAL_DESCRIPTION_ON_TRANSLATION] = showOriginalDescriptionOnTranslation; 62 | state[VISION_SUBSCRIPTION_KEY] = visionSubscriptionKey; 63 | state[TRANSLATOR_SUBSCRIPTION_KEY] = translatorSubscriptionKey; 64 | state[IS_TEXT_TO_SPEECH_ENABLED] = isTextToSpeechEnabled; 65 | state[SHOW_DESCRIPTION_ON_FACE_IDENTIFICATION] = showDescriptionOnFaceIdentification; 66 | } 67 | 68 | return base.OnNavigatedFromAsync(state, suspending); 69 | } 70 | 71 | private void Restore(IDictionary state) 72 | { 73 | showRecognitionConfidence = Convert.ToBoolean(state[SHOW_RECOGNITION_CONFIDENCE]); 74 | showOriginalDescriptionOnTranslation = Convert.ToBoolean(state[SHOW_ORIGINAL_DESCRIPTION_ON_TRANSLATION]); 75 | visionSubscriptionKey = state[VISION_SUBSCRIPTION_KEY].ToString(); 76 | translatorSubscriptionKey = state[TRANSLATOR_SUBSCRIPTION_KEY].ToString(); 77 | faceSubscriptionKey = state[FACE_SUBSCRIPTION_KEY].ToString(); 78 | isTextToSpeechEnabled = Convert.ToBoolean(state[IS_TEXT_TO_SPEECH_ENABLED]); 79 | showDescriptionOnFaceIdentification = Convert.ToBoolean(state[SHOW_DESCRIPTION_ON_FACE_IDENTIFICATION]); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Template10.Services.NavigationService; 5 | using Windows.UI.Xaml.Navigation; 6 | 7 | namespace See4Me.ViewModels 8 | { 9 | public abstract partial class ViewModelBase : INavigable 10 | { 11 | public virtual Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary state) 12 | => Task.CompletedTask; 13 | 14 | public virtual Task OnNavigatedFromAsync(IDictionary state, bool suspending) 15 | { 16 | MessengerInstance.Unregister(this); 17 | return Task.CompletedTask; 18 | } 19 | 20 | public virtual Task OnNavigatingFromAsync(NavigatingEventArgs args) 21 | => Task.CompletedTask; 22 | 23 | [JsonIgnore] 24 | public Template10.Services.NavigationService.INavigationService NavigationService { get; set; } 25 | 26 | [JsonIgnore] 27 | public Template10.Common.IDispatcherWrapper Dispatcher { get; set; } 28 | 29 | [JsonIgnore] 30 | public Template10.Common.IStateItems SessionState { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /Src/See4Me.Windows/ViewModels/ViewModelLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GalaSoft.MvvmLight.Ioc; 3 | using Microsoft.Practices.ServiceLocation; 4 | using See4Me.Services; 5 | using System.Globalization; 6 | using System.Threading.Tasks; 7 | 8 | namespace See4Me.ViewModels 9 | { 10 | public partial class ViewModelLocator 11 | { 12 | public static async Task ResumeAsync() 13 | { 14 | var mainViewModel = ServiceLocator.Current.GetInstance(); 15 | await mainViewModel.InitializeStreamingAsync(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/AboutPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using Microsoft.Practices.ServiceLocation; 3 | using See4Me.Services; 4 | using Windows.UI.Xaml.Controls; 5 | using Windows.UI.Xaml.Navigation; 6 | using System.IO; 7 | using See4Me.Extensions; 8 | 9 | namespace See4Me.Views 10 | { 11 | public sealed partial class AboutPage : Page 12 | { 13 | public AboutPage() 14 | { 15 | this.InitializeComponent(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using Microsoft.Practices.ServiceLocation; 3 | using See4Me.Services; 4 | using Windows.UI.Xaml.Controls; 5 | using Windows.UI.Xaml.Navigation; 6 | using System.IO; 7 | using See4Me.Extensions; 8 | using Windows.System.Profile; 9 | using See4Me.Common; 10 | using Windows.UI.Core; 11 | using System; 12 | using See4Me.ViewModels; 13 | 14 | namespace See4Me.Views 15 | { 16 | public sealed partial class MainPage : Page 17 | { 18 | private static string deviceFamily; 19 | 20 | private readonly MainViewModel viewModel; 21 | 22 | public MainPage() 23 | { 24 | this.InitializeComponent(); 25 | 26 | NavigationCacheMode = NavigationCacheMode.Required; 27 | deviceFamily = AnalyticsInfo.VersionInfo.DeviceFamily; 28 | 29 | viewModel = DataContext as MainViewModel; 30 | } 31 | 32 | protected override void OnNavigatedTo(NavigationEventArgs e) 33 | { 34 | SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; 35 | RegisterMessages(); 36 | 37 | base.OnNavigatedTo(e); 38 | } 39 | 40 | private void RegisterMessages() 41 | { 42 | Messenger.Default.Register>(this, (message) => 43 | { 44 | try 45 | { 46 | switch (message.Notification) 47 | { 48 | case Constants.InitializeStreaming: 49 | message.Execute(video); 50 | break; 51 | } 52 | } 53 | catch (Exception ex) 54 | { 55 | var error = ex.GetExceptionMessage(); 56 | viewModel.StatusMessage = error; 57 | } 58 | }); 59 | 60 | Messenger.Default.Register(this, (message) => 61 | { 62 | try 63 | { 64 | switch (message.Notification) 65 | { 66 | case Constants.TakingPhoto: 67 | fullSizeImage.Source = null; 68 | 69 | previewImageBorder.Visibility = Windows.UI.Xaml.Visibility.Collapsed; 70 | previewImage.Source = null; 71 | 72 | if (deviceFamily != Constants.WindowsMobileFamily) 73 | shutter.Play(); 74 | 75 | break; 76 | } 77 | } 78 | catch (Exception ex) 79 | { 80 | var error = ex.GetExceptionMessage(); 81 | viewModel.StatusMessage = error; 82 | } 83 | }); 84 | 85 | Messenger.Default.Register>(this, async (message) => 86 | { 87 | try 88 | { 89 | switch (message.Notification) 90 | { 91 | case Constants.PhotoTaken: 92 | await previewImage.SetSourceAsync(message.Content); 93 | previewImageBorder.Visibility = Windows.UI.Xaml.Visibility.Visible; 94 | 95 | await fullSizeImage.SetSourceAsync(message.Content); 96 | 97 | break; 98 | } 99 | } 100 | catch (Exception ex) 101 | { 102 | var error = ex.GetExceptionMessage(); 103 | viewModel.StatusMessage = error; 104 | } 105 | }); 106 | } 107 | 108 | protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) 109 | { 110 | SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; 111 | Messenger.Default.Unregister(this); 112 | 113 | base.OnNavigatingFrom(e); 114 | } 115 | 116 | private void OnBackRequested(object sender, BackRequestedEventArgs e) 117 | { 118 | if (fullSizeImage.Opacity == 1) 119 | { 120 | // If the full size image is shown, the back button must actually hide it. 121 | hideFullSizeImageAnimation.Begin(); 122 | e.Handled = true; 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/PrivacyPolicyPage.xaml: -------------------------------------------------------------------------------- 1 |  15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/PrivacyPolicyPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using Microsoft.Practices.ServiceLocation; 3 | using See4Me.Services; 4 | using Windows.UI.Xaml.Controls; 5 | using Windows.UI.Xaml.Navigation; 6 | using System.IO; 7 | using See4Me.Extensions; 8 | 9 | namespace See4Me.Views 10 | { 11 | public sealed partial class PrivacyPolicyPage : Page 12 | { 13 | public PrivacyPolicyPage() 14 | { 15 | this.InitializeComponent(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/RecognizeTextPage.xaml: -------------------------------------------------------------------------------- 1 |  15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 32 | 33 | 34 | 35 | 40 | 41 | 42 | 47 | 52 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/RecognizeTextPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using Microsoft.Practices.ServiceLocation; 3 | using See4Me.Services; 4 | using Windows.UI.Xaml.Controls; 5 | using Windows.UI.Xaml.Navigation; 6 | using System.IO; 7 | using See4Me.Extensions; 8 | 9 | namespace See4Me.Views 10 | { 11 | public sealed partial class RecognizeTextPage : Page 12 | { 13 | public RecognizeTextPage() 14 | { 15 | this.InitializeComponent(); 16 | this.NavigationCacheMode = NavigationCacheMode.Required; 17 | } 18 | 19 | protected override void OnNavigatedTo(NavigationEventArgs e) 20 | { 21 | this.RegisterMessages(); 22 | base.OnNavigatedTo(e); 23 | } 24 | 25 | private void RegisterMessages() 26 | { 27 | Messenger.Default.Register>(this, async (message) => 28 | { 29 | switch (message.Notification) 30 | { 31 | case Constants.PhotoTaken: 32 | photo.Source = null; 33 | await photo.SetSourceAsync(message.Content); 34 | 35 | break; 36 | } 37 | }); 38 | } 39 | 40 | protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) 41 | { 42 | Messenger.Default.Unregister(this); 43 | base.OnNavigatingFrom(e); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/Views/SettingsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using GalaSoft.MvvmLight.Messaging; 2 | using Microsoft.Practices.ServiceLocation; 3 | using See4Me.Services; 4 | using Windows.UI.Xaml.Controls; 5 | using Windows.UI.Xaml.Navigation; 6 | using System.IO; 7 | using See4Me.Extensions; 8 | 9 | namespace See4Me.Views 10 | { 11 | public sealed partial class SettingsPage : Page 12 | { 13 | public SettingsPage() 14 | { 15 | this.InitializeComponent(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/See4Me.Windows/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.3.3", 4 | "Microsoft.Xaml.Behaviors.Uwp.Managed": "2.0.0", 5 | "MvvmLightLibs": "5.3.0", 6 | "Newtonsoft.Json": "9.0.1", 7 | "PlatformSpecific.Analyzer": "2.0.3", 8 | "Template10": "1.1.12", 9 | "WindowsStateTriggers": "1.1.0", 10 | "Xam.Plugin.Connectivity": "2.3.0", 11 | "Xam.Plugins.Settings": "2.5.8", 12 | "Xam.Plugins.TextToSpeech": "2.0.0" 13 | }, 14 | "frameworks": { 15 | "uap10.0": {} 16 | }, 17 | "runtimes": { 18 | "win10-arm": {}, 19 | "win10-arm-aot": {}, 20 | "win10-x86": {}, 21 | "win10-x86-aot": {}, 22 | "win10-x64": {}, 23 | "win10-x64-aot": {} 24 | } 25 | } -------------------------------------------------------------------------------- /Src/See4Me.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using GalaSoft.MvvmLight.Threading; 3 | using See4Me.Services; 4 | using See4Me.ViewModels; 5 | using UIKit; 6 | 7 | namespace See4Me.iOS 8 | { 9 | // The UIApplicationDelegate for the application. This class is responsible for launching the 10 | // User Interface of the application, as well as listening (and optionally responding) to 11 | // application events from iOS. 12 | [Register("AppDelegate")] 13 | public class AppDelegate : UIApplicationDelegate 14 | { 15 | // class-level declarations 16 | public ViewModelLocator Locator { get; private set; } 17 | public override UIWindow Window { get; set; } 18 | public static UIStoryboard Storyboard = UIStoryboard.FromName("Main", null); 19 | public static UINavigationController initialController; 20 | 21 | public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) 22 | { 23 | this.Initialize(application); 24 | 25 | //Uncomment the 3 rows below to enforce English 26 | //var ci = new System.Globalization.CultureInfo("en"); 27 | //System.Threading.Thread.CurrentThread.CurrentCulture = ci; 28 | //System.Threading.Thread.CurrentThread.CurrentUICulture = ci; 29 | 30 | return true; 31 | } 32 | 33 | private void Initialize(UIApplication application) 34 | { 35 | this.Window = new UIWindow(UIScreen.MainScreen.Bounds); 36 | 37 | var navigationService = new See4Me.Services.NavigationService(); 38 | 39 | this.Locator = new ViewModelLocator(); 40 | this.Locator.Initialize(navigationService); 41 | 42 | initialController = Storyboard.InstantiateInitialViewController() as UINavigationController; 43 | navigationService.Initialize(initialController); 44 | navigationService.Configure(Pages.MainPage.ToString(), Pages.MainPage.ToString()); 45 | navigationService.Configure(Pages.SettingsPage.ToString(), Pages.SettingsPage.ToString()); 46 | navigationService.Configure(Pages.AboutPage.ToString(), Pages.AboutPage.ToString()); 47 | navigationService.Configure(Pages.PrivacyPolicyPage.ToString(), Pages.PrivacyPolicyPage.ToString()); 48 | 49 | Window.RootViewController = initialController; 50 | Window.MakeKeyAndVisible(); 51 | // MVVM Light's DispatcherHelper for cross-thread handling. 52 | DispatcherHelper.Initialize(application); 53 | } 54 | 55 | public override void OnResignActivation(UIApplication application) 56 | { 57 | // Invoked when the application is about to move from active to inactive state. 58 | // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) 59 | // or when the user quits the application and it begins the transition to the background state. 60 | // Games should use this method to pause the game. 61 | } 62 | 63 | public override void DidEnterBackground(UIApplication application) 64 | { 65 | // Use this method to release shared resources, save user data, invalidate timers and store the application state. 66 | // If your application supports background exection this method is called instead of WillTerminate when the user quits. 67 | } 68 | 69 | public override void WillEnterForeground(UIApplication application) 70 | { 71 | // Called as part of the transiton from background to active state. 72 | // Here you can undo many of the changes made on entering the background. 73 | } 74 | 75 | public override void OnActivated(UIApplication application) 76 | { 77 | // Restart any tasks that were paused (or not yet started) while the application was inactive. 78 | // If the application was previously in the background, optionally refresh the user interface. 79 | } 80 | 81 | public override void WillTerminate(UIApplication application) 82 | { 83 | // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Src/See4Me.iOS/Common/ViewControllerBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.Practices.ServiceLocation; 5 | using See4Me.ViewModels; 6 | using GalaSoft.MvvmLight.Views; 7 | using UIKit; 8 | using GalaSoft.MvvmLight.Messaging; 9 | 10 | namespace See4Me.iOS.Common 11 | { 12 | public abstract class ViewControllerBase : UIViewController where T : ViewModelBase 13 | { 14 | protected T ViewModel => ServiceLocator.Current.GetInstance(); 15 | 16 | public ViewControllerBase(IntPtr handle) : base (handle) 17 | { } 18 | 19 | public override void ViewDidUnload() 20 | { 21 | base.ViewDidUnload(); 22 | Messenger.Default.Unregister(this); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Extensions/AVCaptureExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using AVFoundation; 5 | 6 | namespace See4Me.iOS.Extensions 7 | { 8 | public static class AVCaptureExtensions 9 | { 10 | public static AVCaptureDevicePosition GetPosition(this AVCaptureInput avCaptureInput) 11 | => ((AVCaptureDeviceInput) avCaptureInput).Device.Position; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Extensions/ContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UIKit; 3 | using GalaSoft.MvvmLight.Command; 4 | using GalaSoft.MvvmLight.Helpers; 5 | 6 | namespace See4Me 7 | { 8 | public static class ContextExtensions 9 | { 10 | public static Binding RegisterHandler(this Binding binding, UIControl control) 11 | { 12 | if (control is UITextField) 13 | (control as UITextField).EditingChanged += (s, e) => { }; 14 | else if (control is UISwitch) 15 | (control as UISwitch).ValueChanged += (s, e) => { }; 16 | 17 | return binding; 18 | } 19 | 20 | public static UIButton SetCommand(this UIButton control, RelayCommand command) 21 | { 22 | control.TouchUpInside += (s, e) => { }; 23 | 24 | control.SetCommand(Events.TouchUpInside, command); 25 | control.Enabled = command.CanExecute(null); 26 | command.CanExecuteChanged += (s, args) => control.Enabled = command.CanExecute(null); 27 | 28 | return control; 29 | } 30 | 31 | public static UIBarButtonItem SetCommand(this UIBarButtonItem control, RelayCommand command) 32 | { 33 | control.Clicked += (s, e) => { }; 34 | 35 | control.SetCommand(Events.Clicked, command); 36 | control.Enabled = command.CanExecute(null); 37 | 38 | return control; 39 | } 40 | 41 | public static UITextField DismissKeyboardOnReturn(this UITextField control) 42 | { 43 | control.ShouldReturn += (textField) => 44 | { 45 | textField.ResignFirstResponder(); 46 | return true; 47 | }; 48 | return control; 49 | } 50 | } 51 | 52 | public static class Events 53 | { 54 | public const string EditingChanged = "EditingChanged"; 55 | public const string ValueChanged = "ValueChanged"; 56 | public const string TouchUpInside = "TouchUpInside"; 57 | public const string Clicked = "Clicked"; 58 | } 59 | } -------------------------------------------------------------------------------- /Src/See4Me.iOS/Extensions/LocalizationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Foundation; 5 | using UIKit; 6 | 7 | namespace See4Me.iOS.Extensions 8 | { 9 | public static class LocalizationExtensions 10 | { 11 | public static string Localize(this string s) => NSBundle.MainBundle.LocalizedString(s, s); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | See4Me 7 | CFBundleIdentifier 8 | com.riccardocappello.see4me 9 | CFBundleShortVersionString 10 | 2.0 11 | CFBundleVersion 12 | 2.0.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 9.0 17 | UIDeviceFamily 18 | 19 | 1 20 | 2 21 | 22 | UILaunchStoryboardName 23 | LaunchScreen 24 | UIRequiredDeviceCapabilities 25 | 26 | armv7 27 | 28 | UISupportedInterfaceOrientations 29 | 30 | UIInterfaceOrientationLandscapeLeft 31 | UIInterfaceOrientationLandscapeRight 32 | 33 | UISupportedInterfaceOrientations~ipad 34 | 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | 38 | UIMainStoryboardFile~ipad 39 | Main 40 | UIMainStoryboardFile 41 | Main 42 | UIStatusBarHidden 43 | 44 | CFBundleIconFiles 45 | 46 | Icon-72@2x.png 47 | Icon-72.png 48 | Icon@2x.png 49 | Icon.png 50 | Icon-60@2x.png 51 | Icon-76.png 52 | Icon-76@2x.png 53 | Icon-Small-50@2x.png 54 | Icon-Small-50.png 55 | Icon-Small-40.png 56 | Icon-Small-40@2x.png 57 | Icon-Small.png 58 | Icon-Small@2x.png 59 | Icon-83.5@2x.png 60 | 61 | CFBundleName 62 | See4Me 63 | NSCameraUsageDescription 64 | 65 | UIRequiresFullScreen 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/LinkerWorkarounds.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Foundation; 3 | using UIKit; 4 | 5 | namespace See4Me 6 | { 7 | [Preserve] 8 | static class LinkerWorkarounds 9 | { 10 | public static void KeepTheseMethods() 11 | { 12 | default(UITextField).Text = ""; 13 | default(UISwitch).On = true; 14 | throw new Exception("Don't actually call this!"); 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using UIKit; 2 | 3 | namespace See4Me.iOS 4 | { 5 | public class Application 6 | { 7 | // This is the main entry point of the application. 8 | static void Main(string[] args) 9 | { 10 | // if you want to use a different Application Delegate class from "AppDelegate" 11 | // you can specify it here. 12 | UIApplication.Main(args, null, "AppDelegate"); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Src/See4Me.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("See4Me.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("See4Me.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("07d2ce91-d4c3-4e01-88cc-9e40fe3f8d47")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-60.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-60@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-60@3x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-72.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-72@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-76.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-76@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-83.5@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small-40.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small-50.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon-Small@3x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Icon@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Camera.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Camera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Camera@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Eye.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Eye@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Eye@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Settings.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/Settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/Settings@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/SwitchCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/SwitchCamera.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/Images/SwitchCamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/Images/SwitchCamera@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/iTunesArtwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/iTunesArtwork.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Resources/iTunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DotNetToscana/See4Me/8e467eed8966a62701738e907db4439861fb73f2/Src/See4Me.iOS/Resources/iTunesArtwork@2x.png -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/AppService.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using See4Me.Localization.Resources; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace See4Me.Services 10 | { 11 | public class AppService : IAppService 12 | { 13 | private const string BLOG_URL = "http://www.riccardocappello.com"; 14 | private const string TWITTER_URL = "https://twitter.com/rcappello"; 15 | private const string LINKEDIN_URL = "https://www.linkedin.com/in/rcappello"; 16 | 17 | private readonly NSString buildKey; 18 | private readonly NSString versionKey; 19 | 20 | public AppService() 21 | { 22 | buildKey = new NSString("CFBundleVersion"); 23 | versionKey = new NSString("CFBundleShortVersionString"); 24 | } 25 | 26 | public string Version 27 | { 28 | get 29 | { 30 | try 31 | { 32 | var build = NSBundle.MainBundle.InfoDictionary.ValueForKey(buildKey); 33 | var version = NSBundle.MainBundle.InfoDictionary.ValueForKey(versionKey); 34 | return $"{version} (build {build})"; 35 | } 36 | catch 37 | { 38 | return string.Empty; 39 | } 40 | } 41 | } 42 | 43 | public string Author => AppResources.iOSProjectAuthor; 44 | 45 | public string BlogUrl => BLOG_URL; 46 | 47 | public string TwitterUrl => TWITTER_URL; 48 | 49 | public string LinkedInUrl => LINKEDIN_URL; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/ImageTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | using UIKit; 6 | 7 | namespace See4Me.Services 8 | { 9 | public static class ImageTools 10 | { 11 | public static UIImage MaxResizeImage(this UIImage sourceImage) 12 | { 13 | float h = 640.0f, w = 480.0f; 14 | 15 | //if(sourceImage.Orientation == UIImageOrientation.Up) 16 | if (sourceImage.Size.Height == 0) 17 | return sourceImage; 18 | 19 | if (sourceImage.Size.Height < sourceImage.Size.Width) 20 | { 21 | w = 640.0f; 22 | h = 480.0f; 23 | } 24 | 25 | return MaxResizeImage(sourceImage,w,h); 26 | } 27 | 28 | public static UIImage MaxResizeImage(this UIImage sourceImage, float maxWidth, float maxHeight) 29 | { 30 | var sourceSize = sourceImage.Size; 31 | var maxResizeFactor = Math.Max(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height); 32 | 33 | if (maxResizeFactor > 1) 34 | return sourceImage; 35 | 36 | var width = maxResizeFactor * sourceSize.Width; 37 | var height = maxResizeFactor * sourceSize.Height; 38 | 39 | UIGraphics.BeginImageContext(new SizeF((float)width, (float)height)); 40 | sourceImage.Draw(new RectangleF(0, 0, (float)width, (float)height)); 41 | var resultImage = UIGraphics.GetImageFromCurrentImageContext(); 42 | UIGraphics.EndImageContext(); 43 | 44 | return resultImage; 45 | } 46 | 47 | // resize the image (without trying to maintain aspect ratio) 48 | public static UIImage ResizeImage(this UIImage sourceImage, float width, float height) 49 | { 50 | UIGraphics.BeginImageContext(new SizeF(width, height)); 51 | sourceImage.Draw(new RectangleF(0, 0, width, height)); 52 | var resultImage = UIGraphics.GetImageFromCurrentImageContext(); 53 | UIGraphics.EndImageContext(); 54 | 55 | return resultImage; 56 | } 57 | 58 | // crop the image, without resizing 59 | private static UIImage CropImage(this UIImage sourceImage, int cropX, int cropY, int width, int height) 60 | { 61 | var imgSize = sourceImage.Size; 62 | UIGraphics.BeginImageContext(new SizeF(width, height)); 63 | var context = UIGraphics.GetCurrentContext(); 64 | var clippedRect = new RectangleF(0, 0, width, height); 65 | context.ClipToRect(clippedRect); 66 | var drawRect = new RectangleF(-cropX, -cropY, (float)imgSize.Width, (float)imgSize.Height); 67 | sourceImage.Draw(drawRect); 68 | var modifiedImage = UIGraphics.GetImageFromCurrentImageContext(); 69 | UIGraphics.EndImageContext(); 70 | 71 | return modifiedImage; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/LauncherService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UIKit; 7 | 8 | namespace See4Me.Services 9 | { 10 | public class LauncherService : ILauncherService 11 | { 12 | public Task LaunchUriAsync(string uri) 13 | { 14 | UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(uri)); 15 | return Task.FromResult(null); 16 | } 17 | 18 | public Task LaunchMailAsync(string mailAddress) => this.LaunchUriAsync($"mailto:{mailAddress}"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/MediaPicker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace See4Me.Services 8 | { 9 | public class MediaPicker : IMediaPicker 10 | { 11 | public Task TakePhotoAsync() 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace See4Me.Services 6 | { 7 | public class NavigationService : GalaSoft.MvvmLight.Views.NavigationService, See4Me.Services.INavigationService 8 | { } 9 | } 10 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/OutputRecorder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using AVFoundation; 5 | using CoreGraphics; 6 | using CoreImage; 7 | using CoreMedia; 8 | using CoreVideo; 9 | using UIKit; 10 | 11 | namespace See4Me.Services 12 | { 13 | public class OutputRecorder : AVCaptureVideoDataOutputSampleBufferDelegate 14 | { 15 | private UIImage image; 16 | 17 | public UIImage GetImage() 18 | { 19 | lock (syncObject) 20 | return image; 21 | } 22 | 23 | private static object syncObject = new object(); 24 | 25 | public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection) 26 | { 27 | try 28 | { 29 | lock (syncObject) 30 | { 31 | this.TryDispose(image); 32 | image = ImageFromSampleBuffer(sampleBuffer); 33 | } 34 | } 35 | catch (Exception e) 36 | { 37 | Console.WriteLine(e); 38 | } 39 | finally 40 | { 41 | // 42 | // Although this looks innocent "Oh, he is just optimizing this case away" 43 | // this is incredibly important to call on this callback, because the AVFoundation 44 | // has a fixed number of buffers and if it runs out of free buffers, it will stop 45 | // delivering frames. 46 | // 47 | sampleBuffer.Dispose(); 48 | } 49 | } 50 | 51 | private void TryDispose(IDisposable obj) 52 | { 53 | try 54 | { 55 | if (obj != null) 56 | obj.Dispose(); 57 | } 58 | catch 59 | { } 60 | } 61 | 62 | private UIImage ImageFromSampleBuffer(CMSampleBuffer sampleBuffer) 63 | { 64 | // Get the CoreVideo image 65 | using (var pixelBuffer = sampleBuffer.GetImageBuffer() as CVPixelBuffer) 66 | { 67 | // Lock the base address 68 | pixelBuffer.Lock(CVPixelBufferLock.None); 69 | 70 | // Get the number of bytes per row for the pixel buffer 71 | var baseAddress = pixelBuffer.BaseAddress; 72 | var bytesPerRow = (int)pixelBuffer.BytesPerRow; 73 | var width = (int)pixelBuffer.Width; 74 | var height = (int)pixelBuffer.Height; 75 | var flags = CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Little; 76 | 77 | // Create a CGImage on the RGB colorspace from the configured parameter above 78 | using (var cs = CGColorSpace.CreateDeviceRGB()) 79 | { 80 | using (var context = new CGBitmapContext(baseAddress, width, height, 8, bytesPerRow, cs, (CGImageAlphaInfo)flags)) 81 | { 82 | using (CGImage cgImage = context.ToImage()) 83 | { 84 | pixelBuffer.Unlock(CVPixelBufferLock.None); 85 | return UIImage.FromImage(cgImage); 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/Services/SoundTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using AudioToolbox; 5 | 6 | namespace See4Me.Services 7 | { 8 | public static class SoundTools 9 | { 10 | private const string NotificationSoundPath = "/System/Library/Audio/UISounds/photoShutter.caf"; 11 | 12 | public static void TriggerSoundAndViber() 13 | { 14 | try 15 | { 16 | var notificationSound = SystemSound.FromFile(NotificationSoundPath); 17 | notificationSound.AddSystemSoundCompletion(SystemSound.Vibrate.PlaySystemSound); 18 | notificationSound.PlaySystemSound(); 19 | } 20 | catch { } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/AboutViewController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using AVFoundation; 4 | using Foundation; 5 | using GalaSoft.MvvmLight.Messaging; 6 | using See4Me.iOS.Common; 7 | using See4Me.ViewModels; 8 | using UIKit; 9 | using System.Collections.Generic; 10 | using GalaSoft.MvvmLight.Helpers; 11 | using See4Me.iOS.Extensions; 12 | using See4Me.Localization.Resources; 13 | using See4Me.Services; 14 | using CoreGraphics; 15 | 16 | namespace See4Me 17 | { 18 | public partial class AboutViewController : ViewControllerBase 19 | { 20 | private List bindings; 21 | 22 | public AboutViewController (IntPtr handle) : base (handle) 23 | { 24 | } 25 | 26 | public override void ViewDidLoad() 27 | { 28 | base.ViewDidLoad(); 29 | 30 | NavigationController.SetNavigationBarHidden(false, false); 31 | 32 | this.SetTranslation(); 33 | this.bindings = new List() 34 | { 35 | this.SetBinding(() => ViewModel.AppVersion, () => LabelAppVersion.Text, BindingMode.OneWay), 36 | this.SetBinding(() => ViewModel.ProjectAuthor, () => LabelAuthor.Text, BindingMode.OneWay), 37 | 38 | this.SetBinding(() => ViewModel.BlogUrl, () => LinkBlog.Text, BindingMode.OneWay), 39 | this.SetBinding(() => ViewModel.LinkedInUrl, () => LinkLinkedin.Text, BindingMode.OneWay), 40 | this.SetBinding(() => ViewModel.TwitterUrl, () => LinkTwitter.Text, BindingMode.OneWay), 41 | this.SetBinding(() => ViewModel.CognitiveServicesUrl, () => LinkPoweredBy.Text, BindingMode.OneWay), 42 | }; 43 | 44 | LinkBlog.UserInteractionEnabled = true; 45 | LinkBlog.AddGestureRecognizer(new UITapGestureRecognizer(() => 46 | { 47 | this.ViewModel.GotoUrlCommand.Execute(ViewModel.BlogUrl); 48 | })); 49 | LinkLinkedin.UserInteractionEnabled = true; 50 | LinkLinkedin.AddGestureRecognizer(new UITapGestureRecognizer(() => 51 | { 52 | this.ViewModel.GotoUrlCommand.Execute(ViewModel.LinkedInUrl); 53 | })); 54 | LinkTwitter.UserInteractionEnabled = true; 55 | LinkTwitter.AddGestureRecognizer(new UITapGestureRecognizer(() => 56 | { 57 | this.ViewModel.GotoUrlCommand.Execute(ViewModel.TwitterUrl); 58 | })); 59 | LinkPoweredBy.UserInteractionEnabled = true; 60 | LinkPoweredBy.AddGestureRecognizer(new UITapGestureRecognizer(() => 61 | { 62 | this.ViewModel.GotoUrlCommand.Execute(ViewModel.CognitiveServicesUrl); 63 | })); 64 | LinkGitHub.UserInteractionEnabled = true; 65 | LinkGitHub.AddGestureRecognizer(new UITapGestureRecognizer(() => 66 | { 67 | this.ViewModel.GotoGitHubCommand.Execute(null); 68 | })); 69 | LinkPrivacy.UserInteractionEnabled = true; 70 | LinkPrivacy.AddGestureRecognizer(new UITapGestureRecognizer(() => 71 | { 72 | this.ViewModel.GotoPrivacyPolicyCommand.Execute(null); 73 | })); 74 | } 75 | 76 | private void SetTranslation() 77 | { 78 | this.NavigationItem.Title = AppResources.About; 79 | 80 | this.LabelAppName.Text = AppResources.AppName; 81 | this.LabelBlog.Text = AppResources.Blog; 82 | this.LabelLinkedin.Text = AppResources.LinkedIn; 83 | this.LabelTwitter.Text = AppResources.Twitter; 84 | this.LabelPoweredBy.Text = AppResources.PoweredByCognitiveServices; 85 | 86 | this.LinkGitHub.Text = AppResources.GotoGitHub; 87 | this.LinkPrivacy.Text = AppResources.PrivacyPolicyCommand; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/AboutViewController.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio to store outlets and 4 | // actions made in the UI designer. If it is removed, they will be lost. 5 | // Manual changes to this file may not be handled correctly. 6 | // 7 | using Foundation; 8 | using System.CodeDom.Compiler; 9 | 10 | namespace See4Me 11 | { 12 | [Register ("AboutViewController")] 13 | partial class AboutViewController 14 | { 15 | [Outlet] 16 | UIKit.UILabel LabelAppName { get; set; } 17 | 18 | [Outlet] 19 | UIKit.UILabel LabelAppVersion { get; set; } 20 | 21 | [Outlet] 22 | UIKit.UILabel LabelAuthor { get; set; } 23 | 24 | [Outlet] 25 | UIKit.UILabel LabelBlog { get; set; } 26 | 27 | [Outlet] 28 | UIKit.UILabel LabelLinkedin { get; set; } 29 | 30 | [Outlet] 31 | UIKit.UILabel LabelPoweredBy { get; set; } 32 | 33 | [Outlet] 34 | UIKit.UILabel LabelTwitter { get; set; } 35 | 36 | [Outlet] 37 | UIKit.UILabel LinkBlog { get; set; } 38 | 39 | [Outlet] 40 | UIKit.UILabel LinkGitHub { get; set; } 41 | 42 | [Outlet] 43 | UIKit.UILabel LinkLinkedin { get; set; } 44 | 45 | [Outlet] 46 | UIKit.UILabel LinkPoweredBy { get; set; } 47 | 48 | [Outlet] 49 | UIKit.UILabel LinkPrivacy { get; set; } 50 | 51 | [Outlet] 52 | UIKit.UILabel LinkTwitter { get; set; } 53 | 54 | void ReleaseDesignerOutlets () 55 | { 56 | if (LabelAppName != null) { 57 | LabelAppName.Dispose (); 58 | LabelAppName = null; 59 | } 60 | 61 | if (LabelAppVersion != null) { 62 | LabelAppVersion.Dispose (); 63 | LabelAppVersion = null; 64 | } 65 | 66 | if (LabelAuthor != null) { 67 | LabelAuthor.Dispose (); 68 | LabelAuthor = null; 69 | } 70 | 71 | if (LabelBlog != null) { 72 | LabelBlog.Dispose (); 73 | LabelBlog = null; 74 | } 75 | 76 | if (LinkBlog != null) { 77 | LinkBlog.Dispose (); 78 | LinkBlog = null; 79 | } 80 | 81 | if (LabelLinkedin != null) { 82 | LabelLinkedin.Dispose (); 83 | LabelLinkedin = null; 84 | } 85 | 86 | if (LinkLinkedin != null) { 87 | LinkLinkedin.Dispose (); 88 | LinkLinkedin = null; 89 | } 90 | 91 | if (LabelTwitter != null) { 92 | LabelTwitter.Dispose (); 93 | LabelTwitter = null; 94 | } 95 | 96 | if (LinkTwitter != null) { 97 | LinkTwitter.Dispose (); 98 | LinkTwitter = null; 99 | } 100 | 101 | if (LabelPoweredBy != null) { 102 | LabelPoweredBy.Dispose (); 103 | LabelPoweredBy = null; 104 | } 105 | 106 | if (LinkPoweredBy != null) { 107 | LinkPoweredBy.Dispose (); 108 | LinkPoweredBy = null; 109 | } 110 | 111 | if (LinkGitHub != null) { 112 | LinkGitHub.Dispose (); 113 | LinkGitHub = null; 114 | } 115 | 116 | if (LinkPrivacy != null) { 117 | LinkPrivacy.Dispose (); 118 | LinkPrivacy = null; 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/MainViewController.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 See4Me.iOS 13 | { 14 | [Register ("MainViewController")] 15 | partial class MainViewController 16 | { 17 | void ReleaseDesignerOutlets () 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/PrivacyPolicyViewController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using AVFoundation; 4 | using Foundation; 5 | using GalaSoft.MvvmLight.Messaging; 6 | using See4Me.iOS.Common; 7 | using See4Me.ViewModels; 8 | using UIKit; 9 | using System.Collections.Generic; 10 | using GalaSoft.MvvmLight.Helpers; 11 | using See4Me.iOS.Extensions; 12 | using See4Me.Localization.Resources; 13 | using See4Me.Services; 14 | using CoreGraphics; 15 | 16 | namespace See4Me 17 | { 18 | public partial class PrivacyPolicyViewController : ViewControllerBase 19 | { 20 | private List bindings; 21 | 22 | public PrivacyPolicyViewController (IntPtr handle) : base (handle) 23 | { 24 | } 25 | 26 | public override void ViewDidLoad() 27 | { 28 | base.ViewDidLoad(); 29 | 30 | NavigationController.SetNavigationBarHidden(false, false); 31 | 32 | this.SetTranslation(); 33 | this.bindings = new List() 34 | { 35 | 36 | }; 37 | 38 | LinkHomePageCognitiveServices.UserInteractionEnabled = true; 39 | LinkHomePageCognitiveServices.AddGestureRecognizer(new UITapGestureRecognizer(() => 40 | { 41 | this.ViewModel.GotoCognitiveServicesUrlCommand.Execute(null); 42 | })); 43 | LinkPrivacyPolicy.UserInteractionEnabled = true; 44 | LinkPrivacyPolicy.AddGestureRecognizer(new UITapGestureRecognizer(() => 45 | { 46 | this.ViewModel.GotoMicrosoftPrivacyPoliciesUrlCommand.Execute(null); 47 | })); 48 | } 49 | 50 | private void SetTranslation() 51 | { 52 | this.NavigationItem.Title = AppResources.PrivacyPolicy; 53 | 54 | this.LabelPrivacyText.Text = AppResources.PrivacyStatement; 55 | this.LinkHomePageCognitiveServices.Text = AppResources.GotoCognitiveServices; 56 | this.LinkPrivacyPolicy.Text = AppResources.MicrosoftPrivacyPolicies; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/PrivacyPolicyViewController.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Xamarin Studio to store outlets and 4 | // actions made in the UI designer. If it is removed, they will be lost. 5 | // Manual changes to this file may not be handled correctly. 6 | // 7 | using Foundation; 8 | using System.CodeDom.Compiler; 9 | 10 | namespace See4Me 11 | { 12 | [Register ("PrivacyPolicyViewController")] 13 | partial class PrivacyPolicyViewController 14 | { 15 | [Outlet] 16 | UIKit.UILabel LabelPageTitle { get; set; } 17 | 18 | [Outlet] 19 | UIKit.UITextView LabelPrivacyText { get; set; } 20 | 21 | [Outlet] 22 | UIKit.UILabel LinkHomePageCognitiveServices { get; set; } 23 | 24 | [Outlet] 25 | UIKit.UILabel LinkPrivacyPolicy { get; set; } 26 | 27 | void ReleaseDesignerOutlets () 28 | { 29 | if (LabelPageTitle != null) { 30 | LabelPageTitle.Dispose (); 31 | LabelPageTitle = null; 32 | } 33 | 34 | if (LabelPrivacyText != null) { 35 | LabelPrivacyText.Dispose (); 36 | LabelPrivacyText = null; 37 | } 38 | 39 | if (LinkHomePageCognitiveServices != null) { 40 | LinkHomePageCognitiveServices.Dispose (); 41 | LinkHomePageCognitiveServices = null; 42 | } 43 | 44 | if (LinkPrivacyPolicy != null) { 45 | LinkPrivacyPolicy.Dispose (); 46 | LinkPrivacyPolicy = null; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/ViewControllers/SettingsViewController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using AVFoundation; 4 | using Foundation; 5 | using GalaSoft.MvvmLight.Messaging; 6 | using See4Me.iOS.Common; 7 | using See4Me.ViewModels; 8 | using UIKit; 9 | using System.Collections.Generic; 10 | using GalaSoft.MvvmLight.Helpers; 11 | using See4Me.iOS.Extensions; 12 | using See4Me.Localization.Resources; 13 | using See4Me.Services; 14 | using CoreGraphics; 15 | 16 | namespace See4Me 17 | { 18 | public partial class SettingsViewController : ViewControllerBase 19 | { 20 | private List bindings; 21 | 22 | public SettingsViewController(IntPtr handle) : base(handle) 23 | { } 24 | 25 | public override void ViewDidLoad() 26 | { 27 | base.ViewDidLoad(); 28 | 29 | ViewModel.Initialize(); 30 | 31 | this.SetTranslation(); 32 | 33 | this.bindings = new List() 34 | { 35 | this.SetBinding(() => ViewModel.VisionSubscriptionKey, () => TextVisionSubscriptionKey.Text, BindingMode.TwoWay), 36 | this.SetBinding(() => ViewModel.FaceSubscriptionKey, () => TextFaceSubscriptionKey.Text, BindingMode.TwoWay), 37 | this.SetBinding(() => ViewModel.TranslatorSubscriptionKey, () => TextTranslatorSubscriptionKey.Text, BindingMode.TwoWay), 38 | 39 | this.SetBinding(() => ViewModel.IsTextToSpeechEnabled, () => SwitchTextToSpeech.On, BindingMode.TwoWay), 40 | this.SetBinding(() => ViewModel.ShowRecognitionConfidence, () => SwitchShowDescriptionConfidence.On, BindingMode.TwoWay), 41 | this.SetBinding(() => ViewModel.ShowOriginalDescriptionOnTranslation, () => SwitchShowOriginalDescription.On, BindingMode.TwoWay), 42 | this.SetBinding(() => ViewModel.ShowDescriptionOnFaceIdentification, () => SwitchShowDescriptionOnFaceIdentification.On, BindingMode.TwoWay), 43 | }; 44 | 45 | TextVisionSubscriptionKey.DismissKeyboardOnReturn(); 46 | TextFaceSubscriptionKey.DismissKeyboardOnReturn(); 47 | TextTranslatorSubscriptionKey.DismissKeyboardOnReturn(); 48 | 49 | ButtonAbout.SetCommand(this.ViewModel.GotoAboutCommand); 50 | ButtonPrivacy.SetCommand(this.ViewModel.GotoPrivacyPolicyCommand); 51 | 52 | this.NavigationItem.SetRightBarButtonItem( 53 | new UIBarButtonItem(UIBarButtonSystemItem.Save, (sender, args) => 54 | { 55 | this.ViewModel.Save(); 56 | NavigationController.PopViewController(true); 57 | }) 58 | , true); 59 | 60 | //dismiss the keyboard if the user taps anywhere in the view 61 | var g = new UITapGestureRecognizer(() => View.EndEditing(true)); 62 | g.CancelsTouchesInView = false; //for iOS5 63 | View.AddGestureRecognizer(g); 64 | 65 | NavigationController.SetNavigationBarHidden(false, false); 66 | } 67 | 68 | public override void ViewWillDisappear(bool animated) 69 | { 70 | base.ViewWillDisappear(animated); 71 | 72 | NavigationController.SetNavigationBarHidden(true, false); 73 | } 74 | 75 | private void SetTranslation() 76 | { 77 | this.NavigationItem.Title = AppResources.Settings; 78 | 79 | LabelVisionSubscriptionKey.Text = AppResources.VisionSubscriptionKey; 80 | LabelFaceSubscriptionKey.Text = AppResources.FaceSubscriptionKey; 81 | LabelTranslatorSubscriptionKey.Text = AppResources.TranslatorSubscriptionKey; 82 | 83 | LabelTextToSpeech.Text = AppResources.TextToSpeech; 84 | LabelShowRecognitionConfidence.Text = AppResources.ShowRecognitionConfidence; 85 | LabelShowOriginalDescription.Text = AppResources.ShowOriginalDescriptionOnTranslation; 86 | LabelShowDescriptionOnFaceIdentification.Text = AppResources.ShowDescriptionOnFaceIdentification; 87 | LabelShowDescriptionOnFaceIdentification.SizeToFit(); 88 | 89 | ButtonAbout.SetTitle(AppResources.AboutCommand, UIControlState.Normal); 90 | ButtonPrivacy.SetTitle(AppResources.PrivacyPolicyCommand, UIControlState.Normal); 91 | } 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "About"="About"; 2 | "AboutCommand"="About..."; 3 | "AngerFemale"="Angry"; 4 | "AngerMale"="Angry"; 5 | "ApplicationTitle"="See4Me"; 6 | "AppName"="See4Me"; 7 | "BackCameraReady"="Back camera ready"; 8 | "Blog"="Blog:"; 9 | "BoyFemale"="Girl"; 10 | "BoyMale"="Boy"; 11 | "ChildFemale"="Child"; 12 | "ChildMale"="Child"; 13 | "ContemptFemale"="To show contempt"; 14 | "ContemptMale"="To show contempt"; 15 | "DisgustFemale"="Disgusted"; 16 | "DisgustMale"="Disgusted"; 17 | "FaceRecognizedSingular"="I see"; 18 | "FacesRecognizedPlural"="I see {0} people"; 19 | "FearFemale"="Fearful"; 20 | "FearMale"="Fearful"; 21 | "FrontCameraReady"="Front camera ready"; 22 | "GotoCognitiveServices"="Visit Cognitive Services Home Page"; 23 | "GotoGitHub"="Follow the project on GitHub"; 24 | "HappinessFemale"="Happy"; 25 | "HappinessMale"="Happy"; 26 | "InitializationError"="Error during app initialization"; 27 | "LinkedIn"="Linkedin:"; 28 | "LookingFemale"="looking {0}"; 29 | "LookingMale"="looking {0}"; 30 | "ManFemale"="Woman"; 31 | "ManMale"="Man"; 32 | "NeutralFemale"="Neutral"; 33 | "NeutralMale"="Neutral"; 34 | "No"="No"; 35 | "NoConnection"="I\'m sorry, there is no Internet connection"; 36 | "OK"="OK"; 37 | "OpenSettings"="Go to Settings"; 38 | "PersonAgeMessageFemale"="A {1} years old {0}"; 39 | "PersonAgeMessageMale"="A {1} years old {0}"; 40 | "WindowsProjectAuthor"="Developed by Marco Minerva - MVP Windows Development"; 41 | "QueryingVisionService"="Analyzing the image..."; 42 | "RecognitionError"="I\'m sorry, there was an unexpected error"; 43 | "RecognitionFailed"="I\'m sorry, I don\'t recognize the image"; 44 | "RecognizeText"="Recognize Text"; 45 | "RecognizingFaces"="Recognizing faces and emotions..."; 46 | "ResourceLanguage"="en"; 47 | "SadnessFemale"="Sad"; 48 | "SadnessMale"="Sad"; 49 | "Save"="Save"; 50 | "ServiceNotRegistered"="Attention, the service is not registered. Tap here to discover how to proceed."; 51 | "Settings"="Settings"; 52 | "ShowRecognitionConfidence"="Show recognition confidence"; 53 | "ShowOriginalDescriptionOnTranslation"="Show original description on translation"; 54 | "SurpriseFemale"="Surprised"; 55 | "SurpriseMale"="Surprised"; 56 | "SwapCamera"="Swap camera"; 57 | "SwapCameraError"="I\'m sorry, I\'m unable to swap camera"; 58 | "TakePhoto"="Take a photo"; 59 | "TextToSpeech"="Text-To-Speech"; 60 | "Translating"="Translating..."; 61 | "TranslatorSubscriptionKey"="Translator Subscription Key"; 62 | "Twitter"="Twitter:"; 63 | "UnableToAccessService"="Unable to access the service. Ensure that registration keys are correct"; 64 | "UnableToRecognizeText"="I\'m sorry, I can\'t recognize text inside the photo"; 65 | "UnableToTakePhoto"="I\'m sorry, I can\'t take the photo. Try restarting the app"; 66 | "VisionSubscriptionKey"="Vision Subscription Key"; 67 | "Yes"="Yes"; 68 | "ConsentRequiredMessage"="You must have the consent of the people whose data (such as images, voices, video or text) are being processed by See4Me. Consent is required to use the app. See4Me adheres to all applicable privacy regulations. By proceding, you confirm you have the consent."; 69 | "ConsentRequiredTitle"="Consent required"; 70 | "PrivacyPolicy"="Privacy Policy"; 71 | "PrivacyPolicyCommand"="Privacy Policy..."; 72 | "PrivacyStatement"="The image, voice, video or text understanding capabilities of See4Me app uses Microsoft Cognitive Services. Microsoft will receive the images, audio, video, and other data that you upload (via this app) for service improvement purposes. To report abuse of the Microsoft Cognitive Services to Microsoft, please visit the Microsoft Cognitive Services website at https://www.microsoft.com/cognitive-services, and use the \"Report Abuse\" link at the bottom of the page to contact Microsoft. For more information about Microsoft privacy policies please see their privacy statement here: https://go.microsoft.com/fwlink/?LinkId=521839."; 73 | "MicrosoftPrivacyPolicies"="Microsoft privacy policies"; 74 | "PoweredByCognitiveServices"="Powered by Microsoft’s Cognitive Services:"; 75 | "RecognizingText"="Recognizing text..."; 76 | "AndroidProjectAuthor"="Developed by Marco Minerva - MVP Windows Development"; 77 | "iOSProjectAuthor"="Developed by Riccardo Cappello"; 78 | "RegisterServices"="Register services"; 79 | "FaceSubscriptionKey"="Face Subscription Key"; 80 | "ShuttingDown"="Shutting down the device..."; 81 | "ShowDescriptionOnFaceIdentification"="Show also image description when detecting one or more faces"; 82 | -------------------------------------------------------------------------------- /Src/See4Me.iOS/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------