예제 #1
0
        public override Task OnSuspendingAsync(object s, SuspendingEventArgs e, bool prelaunchActivated)
        {
            // Log suspension.
            LifecycleLog.AppSuspending();

            return(base.OnSuspendingAsync(s, e, prelaunchActivated));
        }
예제 #2
0
        public App()
        {
            InitializeComponent();
            SplashFactory = (e) => new Views.Splash(e);

            #if DEBUG
            DebugSettings.EnableFrameRateCounter = true;
            #endif

            #region App Settings

            // some settings must be set in app.constructor
            var settings = SettingsService.Instance;
            RequestedTheme      = settings.AppTheme;
            CacheMaxDuration    = settings.CacheMaxDuration;
            ShowShellBackButton = settings.UseShellBackButton;

            #endregion

            // Initialize logger.
            informationListener = new StorageFileEventListener("info");
            verboseListener     = new StorageFileEventListener("verbose");
            // Enable events for loggers.
            informationListener.EnableEvents(EventLog.Log, EventLevel.Informational);
            verboseListener.EnableEvents(EventLog.Log, EventLevel.LogAlways);

            // Clear FutureAccessList as it has a max limit of 1000.
            ClearFutureAccessList();

            // Log startup.
            LifecycleLog.AppStarting();
        }
예제 #3
0
        public static async Task UpdateMediaMetaDataAsync(this MediaMetaDatabaseContext context, MediaMetadata metaToSave)
        {
            try
            {
                // Time and log updating and saving.
                using (new DisposableLogger(DatabaseLog.UpdateSingleBegin, DatabaseLog.UpdateSingleEnd))
                {
                    // Find MediaMetaJson in database list.
                    var metaJson = context.MediaMetaJsons.Include(m => m.Labels).SingleOrDefault(mj => mj.Labels.ListEquals(metaToSave.Labels));

                    if (metaJson != null)
                    {
                        var newMetaJson = new MediaMetaJson(metaToSave);
                        metaJson.Json = newMetaJson.Json;

                        await context.SaveChangesAsync();
                    }
                }
            }
            catch (Exception e)
            {
                // Log Exception.
                LifecycleLog.Exception(e);
            }
        }
예제 #4
0
        public override Task OnPrelaunchAsync(IActivatedEventArgs args, out bool runOnStartAsync)
        {
            // Log prelaunch.
            LifecycleLog.AppPrelaunch();

            runOnStartAsync = true;
            return(Task.CompletedTask);
        }
예제 #5
0
        private async void SessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args)
        {
            await NavigationService.Dispatcher.DispatchAsync(() =>
            {
                // Log reason.
                LifecycleLog.ExtensionRevoked(args.Reason);

                ClearExtendedExecution();
            }, 0, CoreDispatcherPriority.Normal);
        }
예제 #6
0
        /// <summary>
        /// This is the go-to method to handle the authorization and sign-in OAuth flow.
        /// It tries to fetch the google auth token from cache, and if it can't it will try to
        /// fetch it using a refresh token, if that's not possible it will prompt the user to
        /// authorize the application resulting in a google auth token.
        /// It will then use this google auth token to try to sign into firebase, and if that
        /// doesn't work the first time it will retry a second time after having the using re-authorize
        /// the application. (It does this since the refresh token could have been revoked.)
        /// </summary>
        /// <returns><c>true</c> if sign in was successful, <c>false</c> otherwise.</returns>
        public async Task <bool> SignInPromptUserIfNecessary()
        {
            try
            {
                string googleToken;

                using (new DisposableLogger(() => AuthLog.GetAccessTokenBegin("Google"), (sw) => AuthLog.GetAccessTokenEnd(sw, "Google", !string.IsNullOrEmpty(GoogleClient.accessToken))))
                {
                    // Try to fetch google token without prompting the user (authorizing).
                    if (await GoogleClient.Client.GetAccessTokenWithoutAuthentication())
                    {
                        googleToken = GoogleClient.accessToken;
                    }
                    else // Prompt the user to authorize the application.
                    {
                        googleToken = await AuthModal.AuthorizeAndGetGoogleAccessTokenAsync();
                    }
                }

                var firebaseSignInSuccess = false;
                using (new DisposableLogger(() => AuthLog.GetAccessTokenBegin("Firebase"), (sw) => AuthLog.GetAccessTokenEnd(sw, "Firebase", firebaseSignInSuccess)))
                {
                    // Try to sign into firebase with the googleToken.
                    firebaseSignInSuccess = await SignInWithFirebaseAsync(googleToken);
                }
                if (!firebaseSignInSuccess)
                {
                    // Could not log into firebase. Could be caused by a refresh token revocation, try re-authenticating with Google.
                    googleToken = await AuthModal.AuthorizeAndGetGoogleAccessTokenAsync();

                    using (new DisposableLogger(() => AuthLog.GetAccessTokenBegin("Firebase"), (sw) => AuthLog.GetAccessTokenEnd(sw, "Firebase", firebaseSignInSuccess)))
                    {
                        // Retry firebase login.
                        firebaseSignInSuccess = await SignInWithFirebaseAsync(googleToken);

                        // Return result.
                        return(firebaseSignInSuccess);
                    }
                }

                return(firebaseSignInSuccess);
            }
            catch (Exception e)
            {
                // Log Exception.
                LifecycleLog.Exception(e);
                return(false);
            }
        }
예제 #7
0
        public static async Task SaveAllMetadatasAsync(this MediaMetaDatabaseContext context, ICollection <MediaMetadata> metas)
        {
            // Time and log serialization.
            using (new DisposableLogger(DatabaseLog.SerializationBegin, (sw) => DatabaseLog.SerializationEnd(sw, metas.Count)))
            {
                var fullList = await context.MediaMetaJsons.Include(m => m.Labels).ToListAsync();

                foreach (var meta in metas)
                {
                    // If any MediaMetaJson has a set of labels that are equal to the ones of meta, then update it.
                    var toUpdate = fullList.FirstOrDefault(mmj =>
                    {
                        return(mmj.Labels.ListEquals(meta.Labels));
                    });


                    // If there is an existing item to update.
                    if (toUpdate != null)
                    {
                        var metaJson = await MediaMetaJson.FromMediaMetaAsync(meta);

                        toUpdate.Json = metaJson.Json;
                    }
                    else // If a new item needs to be added.
                    {
                        meta.DateAdded = DateTime.Now;
                        var metaJson = await MediaMetaJson.FromMediaMetaAsync(meta);

                        context.MediaMetaJsons.Add(metaJson);
                    }
                }
            }

            try
            {
                // Time and log saving of MediaMetaJsons.
                using (new DisposableLogger(DatabaseLog.SaveBegin, (sw) => DatabaseLog.SaveEnd(sw, metas.Count)))
                {
                    await context.SaveChangesAsync();
                }
            }
            catch (Exception e)
            {
                // Log Exception.
                LifecycleLog.Exception(e);
            }
        }
예제 #8
0
 private static async Task <string> ParseInternetShortcut(StorageFile file)
 {
     try
     {
         using (var stream = await file.OpenStreamForReadAsync())
         {
             var    lines = ReadLines(stream, Encoding.UTF8);
             string line  = lines.Skip(1).Take(1).First();
             string url   = line.Replace("URL=", "");
             url = url.Replace("\"", "");
             url = url.Replace("BASE", "");
             return(url);
         }
     }
     catch (Exception e)
     {
         // Log Exception.
         LifecycleLog.Exception(e);
         return(string.Empty);
     }
 }
예제 #9
0
        public async Task <bool> SignInWithFirebaseAsync(string googleAccessToken)
        {
            try
            {
                var authProvider = new FirebaseAuthProvider(new FirebaseConfig(ApiKey));

                FirebaseAuthLink = await authProvider.SignInWithOAuthAsync(FirebaseAuthType.Google, googleAccessToken);

                accessToken = FirebaseAuthLink.FirebaseToken;

                FirebaseAuthLink.FirebaseAuthRefreshed += FirebaseAuthLink_FirebaseAuthRefreshed;

                return(true);
            }
            catch (Exception e)
            {
                // Log Exception.
                LifecycleLog.Exception(e);
                return(false);
            }
        }
예제 #10
0
        protected override INavigationService CreateNavigationService(Frame frame)
        {
            var navService = base.CreateNavigationService(frame);

            navService.Frame.ContentTransitions?.Clear();
            navService.Frame.ContentTransitions?.Add(new NavigationThemeTransition {
                DefaultNavigationTransitionInfo = new ContinuumNavigationTransitionInfo()
            });

            frame.NavigationFailed += (obj, e) =>
            {
                // Log NavigationException.
                LifecycleLog.NavigationException(e);
                // Set handled to true so the application doesn't crash.
                e.Handled = true;
            };
            navService.FrameFacade.BackRequested += async(sender, backArgs) =>
            {
                // Handle event so this is the only place handling it.
                backArgs.Handled = true;

                // Perform navigation on main thread.
                await navService.Dispatcher.DispatchAsync(() =>
                {
                    try
                    {
                        // Go back when on main thread.
                        navService.FrameFacade.GoBack();
                    }
                    catch (Exception e)
                    {
                        // Log Exception.
                        LifecycleLog.Exception(e);
                    }
                },
                                                          0, CoreDispatcherPriority.Normal);
            };

            return(navService);
        }
예제 #11
0
        public async Task EvaluateImagesOnline(IProgress <int> progress, CancellationToken cancellationToken)
        {
            // Sign into firebase.
            if (await FirebaseClient.Client.SignInPromptUserIfNecessary())
            {
                // Find all media datas without annotation data.
                var mediaDatasWithoutAnnotationData = MediaDatas.Where(data => data.Meta.AnnotationData == null);

                var evaluated = 0;
                using (new DisposableLogger(GalleryLog.EvaluateOnlineBegin, (sw) => GalleryLog.EvaluateOnlineEnd(sw, evaluated)))
                {
                    IsEvaluating = true;
                    await mediaDatasWithoutAnnotationData.ForEachAsyncConcurrent(async media =>
                    {
                        try
                        {
                            // Evaluate media thumbnail online.
                            await media.EvaluateOnlineAsync(FirebaseClient.accessToken);
                        }
                        catch (Exception e)
                        {
                            // Log Exception.
                            LifecycleLog.Exception(e);
                        }
                        finally
                        {
                            // Update and then report progress.
                            evaluated++;
                            progress.Report(evaluated);
                        }
                    }, cancellationToken, 5);

                    IsEvaluating = false;
                }

                // Save online results to database.
                await DatabaseUtils.SaveAllMetadatasAsync(MediaDatas);
            }
        }
예제 #12
0
 public static async Task SaveAllMetadatasAsync(ICollection <MediaData> mediaDatas)
 {
     using (var context = new MediaMetaDatabaseContext())
     {
         var metaDatas = new List <MediaMetadata>();
         foreach (var data in mediaDatas)
         {
             metaDatas.Add(data.Meta);
         }
         try
         {
             await context.SaveAllMetadatasAsync(metaDatas);
         }
         catch (Exception e)
         {
             // Log Exception.
             LifecycleLog.Exception(e);
         }
         // Update static list.
         App.MediaDatas = new List <MediaData>(mediaDatas);
     }
 }
예제 #13
0
        public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
        {
            // Log OnStart.
            LifecycleLog.AppOnStart(startKind, args);
            // CoreApplication.EnablePrelaunch was introduced in Windows 10 version 1607
            var canEnablePrelaunch = Windows.Foundation.Metadata.ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch");

            if (startKind == StartKind.Activate)
            {
                if (args.Kind == ActivationKind.Protocol)
                {
                    // Opens the URI for "navigation" (handling) on the GalleryPage. TODO: Open Auth completed page here.
                    await NavigationService.NavigateAsync(typeof(Views.GalleryPage), SettingsService.Instance.FolderPath);

                    Window.Current.Activate();
                }
            }
            if (startKind == StartKind.Launch)
            {
                // Enable prelaunch.
                if (canEnablePrelaunch)
                {
                    TryEnablePrelaunch();
                }

                // End the Extended Execution Session.
                ClearExtendedExecution();

                using (session = new ExtendedExecutionSession
                {
                    Reason = ExtendedExecutionReason.Unspecified,
                    Description = "Loading Memes from database"
                })
                {
                    // Register Revoked listener.
                    session.Revoked += SessionRevoked;

                    var accessStatus = BackgroundExecutionManager.GetAccessStatus();
                    if (accessStatus != BackgroundAccessStatus.AlwaysAllowed)
                    {
                        // Request background access.
                        var accessGranted = await BackgroundExecutionManager.RequestAccessKindAsync(BackgroundAccessRequestKind.AlwaysAllowed, "To allow faster launch performance");
                    }
                    // Request extension. This is done so that if the application can finish loading data
                    // from database when prelaunched or minimized (suspended prematurely).
                    var result = await session.RequestExtensionAsync();

                    LifecycleLog.ExtensionRequestResult(result);

                    if (result == ExtendedExecutionResult.Denied)
                    {
                        session.Dispose();
                        // TODO: Notify user of extension result denied.
                    }

                    // Set up database.
                    using (new DisposableLogger(DatabaseLog.LoadBegin, DatabaseLog.LoadEnd))
                    {
                        if (!(args.PreviousExecutionState == ApplicationExecutionState.Suspended && MediaDatas.Count > 0))
                        {
                            await SetUpAndLoadFromDatabase();
                        }
                    }

                    // If MediaDatas have been loaded from database then open GalleryPage using those.
                    if (MediaDatas.Count > 0)
                    {
                        await NavigationService.NavigateAsync(typeof(Views.GalleryPage), nameof(MediaDatas));

                        return;
                    }

                    // If no folder path has been set, have the user select one.
                    if (string.IsNullOrEmpty(SettingsService.Instance.FolderPath))
                    {
                        await NavigationService.NavigateAsync(typeof(Views.FolderSelectPage));
                    }
                    else
                    {
                        await NavigationService.NavigateAsync(typeof(Views.GalleryPage));
                    }
                }
            }
        }
예제 #14
0
        public async void SearchForHigherResolutionOnlineAsync()
        {
            // Don't scan for videos.
            if (MediaData is VideoData)
            {
                return;
            }

            var onlineMedias = new Dictionary <Uri, (Size, long)>();

            // Get file size and dimensions of every fully matched image.
            foreach (var webImage in FullyMatchedImages)
            {
                // Parse URL.
                if (Uri.TryCreate(webImage.Url, UriKind.Absolute, out var uri))
                {
                    // Check to make sure this URL points to a file and not a webpage.
                    if (Path.HasExtension(uri.AbsoluteUri))
                    {
                        // Get MIME type of online file.
                        var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(uri.AbsoluteUri));
                        // Check if MIME type of online file is supported.
                        if (FileTypes.IsSupportedMIME(mimeType))
                        {
                            try
                            {
                                // Get dimensions of online image.
                                var dimensions = await ImageUtilities.GetWebDimensionsAsync(uri);

                                // If dimensions is empty, continue.
                                if (dimensions.IsEmpty)
                                {
                                    continue;
                                }
                                // Get file size of online image.
                                var contentLength = await OnlineUtil.GetContentSizeAsync(uri);

                                // Add to dictionary.
                                onlineMedias.Add(uri, (dimensions, contentLength));
                            }
                            catch (Exception e)
                            {
                                // Log Exception.
                                LifecycleLog.Exception(e);
                            }
                        }
                    }
                }
            }

            // If these are null then no comparisons can be made.
            if (MediaData?.Meta == null)
            {
                return;
            }
            if (MediaData?.BasicProperties == null)
            {
                return;
            }

            // Check if any of the fully matched images are higher resolution or larger than local file.
            var largerMedia = new KeyValuePair <Uri, (Size, long)>();

            foreach (var urlAndData in onlineMedias)
            {
                var url = urlAndData.Key;
                var(dimensions, contentLength) = urlAndData.Value;

                // If online media is larger in file size than local media.
                if (contentLength > (long)MediaData.BasicProperties.Size)
                {
                    // If size of this online media is larger than the currently largest media.
                    if (Math.Max(largerMedia.Value.Item2, contentLength) == contentLength)
                    {
                        largerMedia = urlAndData; // Update largerMedia.
                    }
                }
                else if (dimensions.Height > MediaData.Meta.Height && // If online media is larger in both width and height
                         dimensions.Width > MediaData.Meta.Width)     // than the local media.
                {
                    // If dimensions of this online media is larger than the currently largest media.
                    if (Math.Max(largerMedia.Value.Item1.Height, dimensions.Height) == dimensions.Height &&
                        Math.Max(largerMedia.Value.Item1.Width, dimensions.Width) == dimensions.Width)
                    {
                        largerMedia = urlAndData; // Update largerMedia.
                    }
                }
            }

            // If no larger media has been found, return.
            if (largerMedia.Key == null)
            {
                return;
            }

            // Set property.
            LargerMedia = largerMedia.Key;
        }
 private void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
 {
     e.Handled = true;
     LifecycleLog.Exception(e.Exception);
 }
예제 #16
0
        private async Task ProcessFileChange(StorageLibraryChange change)
        {
            // Temp variable used for instantiating StorageFiles for sorting if needed later
            //StorageFile newFile = null;
            var extension = Path.GetExtension(change.Path);

            switch (change.ChangeType)
            {
            // New File in the Library
            case StorageLibraryChangeType.Created:
            case StorageLibraryChangeType.MovedIntoLibrary:
                if (FileTypes.Extensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                {
                    try
                    {
                        // Don't add file to gallery if it already exists.
                        if (MediaDatas.Any(data => data.MediaFile.Path == change.Path))
                        {
                            return;
                        }

                        var mediaFile = (StorageFile)(await change.GetStorageItemAsync());

                        if (mediaFile == null)
                        {
                            return;
                        }

                        await AddFileAsync(ImageSize, mediaFile);
                    }
                    catch (Exception e)
                    {
                        // Log Exception.
                        LifecycleLog.Exception(e);
                    }
                }
                break;

            // Renamed file
            case StorageLibraryChangeType.MovedOrRenamed:
                if (FileTypes.Extensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                {
                    try
                    {
                        var mediaData = GetMediaDataFromPath(change.PreviousPath, MediaDatas);
                        var newName   = Path.GetFileName(change.Path);

                        // If no MediaData could be found in Gallery for this renamed item AND there is an entry for it in App.MediaDatas (lostMediaData)
                        // that probably means it has been renamed while the application was off, so update its path and add it to the gallery.
                        var lostMediaFile = GetMediaFileFromPath(change.Path, _lostMediaFiles);
                        if (mediaData == null && lostMediaFile != null)
                        {
                            var lostMetaData = GetMediaMetaDataFromPath(change.PreviousPath, App.DatabaseMetaDatas);
                            // Update path on metadata.
                            lostMetaData.MediaFilePath = change.Path;
                            // Get current MediaData associated with metadata.
                            var lostMediaData = await MediaData.CreateFromMediaMetadataAsync(lostMetaData);

                            // If file can still not be found then return.
                            if (lostMediaData == null)
                            {
                                return;
                            }
                            // Add file to gallery, including the lost media data.
                            await AddFileAsync(ImageSize, lostMediaFile, false, lostMediaData);
                        }
                        else if (mediaData == null)
                        {
                            return;
                        }

                        // Don't rename file in gallery if it is already renamed
                        if (MediaDatas.Any(data => data.Title == newName))
                        {
                            return;
                        }

                        var mediaFile = (StorageFile)(await change.GetStorageItemAsync());
                        // Run on UI thread.
                        await App.Current.NavigationService.Frame.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                        {
                            // Update MediaFile of mediaData.
                            mediaData.MediaFile = mediaFile;
                        });

                        await mediaData.UpdateFileNameValuesAsync(newName);
                    }
                    catch (Exception e)
                    {
                        // Log Exception.
                        LifecycleLog.Exception(e);
                    }
                }
                break;

            // File Removed From Library
            case StorageLibraryChangeType.Deleted:
            case StorageLibraryChangeType.MovedOutOfLibrary:
                if (FileTypes.Extensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                {
                    try
                    {
                        // Only remove file from gallery if it exists in gallery.
                        if (MediaDatas.Any(data => data.MediaFile.Path == change.Path))
                        {
                            RemoveFile(change.Path);
                        }
                    }
                    catch (Exception e)
                    {
                        // Log Exception.
                        LifecycleLog.Exception(e);
                    }
                }
                break;

            // Modified Contents
            case StorageLibraryChangeType.ContentsChanged:
                if (FileTypes.Extensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                {
                    /*newFile = (StorageFile)(await change.GetStorageItemAsync());
                     * var imageProps = await newFile.Properties.GetImagePropertiesAsync();
                     * var dateTaken = imageProps.DateTaken;
                     * var dateModified = newFile.DateCreated;
                     * if (DateTimeOffset.Compare(dateTaken.AddSeconds(70), dateModified) > 0)
                     * {
                     *  // File was modified by the user
                     * }*/
                }
                break;

            // Ignored Cases
            case StorageLibraryChangeType.EncryptionChanged:
            case StorageLibraryChangeType.ContentsReplaced:
            case StorageLibraryChangeType.IndexingStatusChanged:
            default:
                // These are safe to ignore in this application
                break;
            }
        }