Exemple #1
0
        /// <summary>
        /// Unsubscribe from a quiz
        /// </summary>
        /// <param name="dbId">ID to unsub from</param>
        /// <returns>If the unsub was successful</returns>
        public static async Task <OperationReturnMessage> UnsubscribeFromQuizAsync(string dbId)
        {
            QuizInfo info = QuizRosterDatabase.GetQuizInfo(dbId);

            if (info.SyncStatus != (int)SyncStatusEnum.NotDownloadedAndNeedDownload)
            {
                string location = App.UserPath + "/" + info.Category + "/" + info.QuizName + "`" + info.AuthorName;
                if (Directory.Exists(location))
                {
                    Directory.Delete(location, true);
                }
            }

            OperationReturnMessage returnMessage = await Task.Run(async() => await ServerOperations.UnsubscribeToQuizAsync(dbId));

            if (returnMessage == OperationReturnMessage.True)
            {
                QuizRosterDatabase.DeleteQuizInfo(dbId);
                return(returnMessage);
            }
            else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials)
            {
                CredentialManager.IsLoggedIn = false;
                return(returnMessage);
            }
            else
            {
                return(returnMessage);
            }
        }
Exemple #2
0
 /// <summary>
 /// updates a quizinfo in a threaded realm
 /// </summary>
 /// <param name="editedQuizInfo">quiz to update</param>
 /// <param name="threadedRealm">threaded realm to use</param>
 private static void EditQuizInfo(QuizInfo editedQuizInfo, Realm threadedRealm)
 {
     threadedRealm.Write(() =>
     {
         threadedRealm.Add(editedQuizInfo, update: true);
     });
 }
        /// <summary>
        /// Handle event when user clicks delete quiz button.
        /// </summary>
        /// <param name="e"></param>
        private async void ButtonDelete_Clicked(string deleteType, string DBId)
        {
            if (CredentialManager.IsLoggedIn)
            {
                bool   unsubscribe = deleteType == "Unsubscribe";
                string question;
                string message;
                if (unsubscribe)
                {
                    question = "Are you sure you want to unsubscribe?";
                    message  = "This will remove the copy from your device";
                }
                else
                {
                    question = "Are you sure you want to delete this quiz?";
                    message  = "This will delete the copy on your device and in the cloud. This is not reversable.";
                }

                bool answer = await this.DisplayAlert(question, message, "Yes", "No");

                if (answer)
                {
                    // Acquire QuizInfo from roster
                    QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(DBId); // Author
                    string   path       = rosterInfo.RelativePath;

                    // tell the roster that the quiz is deleted
                    QuizInfo rosterInfoUpdated = new QuizInfo(rosterInfo)
                    {
                        IsDeletedLocally = true,
                        LastModifiedDate = DateTime.Now.ToString()
                    };
                    QuizRosterDatabase.EditQuizInfo(rosterInfoUpdated);

                    // If connected, tell server to delete this quiz If not, it will tell server to delete next time it is connected in QuizRosterDatabase.UpdateLocalDatabase()
                    if (CrossConnectivity.Current.IsConnected)
                    {
                        OperationReturnMessage returnMessage;
                        if (unsubscribe)
                        {
                            returnMessage = await SubscribeUtils.UnsubscribeFromQuizAsync(DBId);
                        }
                        else
                        {
                            returnMessage = await ServerOperations.DeleteQuiz(DBId);
                        }

                        if (System.IO.Directory.Exists(path))
                        {
                            Directory.Delete(path, true);
                        }
                        this.Setup();
                    }
                }
            }
            else
            {
                await this.DisplayAlert("Hold on!", "You must be create an account or log in before you can unsubscribe", "OK");
            }
        }
        /// <summary>
        /// Handle when user clicks edit button
        /// </summary>
        private async void ButtonEdit_Clicked(string DBId)
        {
            QuizInfo info = QuizRosterDatabase.GetQuizInfo(DBId);

            if (!CredentialManager.IsLoggedIn)
            {
                await this.DisplayAlert("Hold on!", "Before you can edit any quizzes, you have to login.", "Ok");
            }
            else if (info.SyncStatus == (int)SyncStatusEnum.NotDownloadedAndNeedDownload)
            {
                await this.DisplayAlert("Hold on!", "This quiz isn't on your device, download it before you try to edit it", "Ok");
            }
            else
            {
                CreateNewQuizPage quizPage = new CreateNewQuizPage(info); //Create the quizPage

                quizPage.SetQuizName(info.QuizName);
                Quiz quizDB = new Quiz(info.DBId);
                foreach (Question question in quizDB.GetQuestions())
                {
                    quizPage.AddNewQuestion(question);
                }
                await this.Navigation.PushAsync(quizPage);
            }
        }
Exemple #5
0
        /// <summary>
        /// Saves a quizinfo to the roster
        /// </summary>
        /// <param name="quizInfo">Quizinfo to save</param>
        public static void SaveQuizInfo(QuizInfo quizInfo)
        {
            RealmConfiguration threadConfig = App.realmConfiguration(RosterPath);
            Realm realmDB = Realm.GetInstance(threadConfig);

            realmDB.Write(() =>
            {
                realmDB.Add(quizInfo);
            });
        }
Exemple #6
0
        /// <summary>
        /// updates a quiz in the roster
        /// </summary>
        /// <param name="editedQuizInfo">quiz to update</param>
        public static void EditQuizInfo(QuizInfo editedQuizInfo)
        {
            RealmConfiguration threadConfig = App.realmConfiguration(RosterPath);
            Realm realmDB = Realm.GetInstance(threadConfig);

            realmDB.Write(() =>
            {
                realmDB.Add(editedQuizInfo, update: true);
            });
            realmDB.Dispose();
        }
Exemple #7
0
        /// <summary>
        /// Send a quiz to the server with the current user credentials.
        /// </summary>
        /// <param name="relativeQuizPath">The path to the quiz on the current device.</param>
        /// <returns>A bool wrapped in a task representing whether the quiz successfully sent or not.</returns>
        public async static Task <bool> SendQuiz(string relativeQuizPath)
        {
            try
            {
                string   realmFilePath = Directory.GetFiles(App.UserPath + relativeQuizPath, "*.realm").First();
                Realm    realm         = Realm.GetInstance(App.realmConfiguration(realmFilePath));
                QuizInfo info          = realm.All <QuizInfo>().First();

                if (await SendRealmFile(realmFilePath) != OperationReturnMessage.True)
                {
                    throw new Exception();
                }

                string[] imageFilePaths = Directory.GetFiles(App.UserPath + relativeQuizPath, "*.jpg");
                for (int i = 0; i < imageFilePaths.Length; i++)
                {
                    //[0] = path, [1] = fileName, [2] = dBId
                    string fileName = imageFilePaths[i].Split('/').Last().Split('.').First();
                    string dbID     = info.DBId;
                    OperationReturnMessage message = await SendImageFile(imageFilePaths[i], fileName, dbID);

                    if (message == OperationReturnMessage.False)
                    {
                        throw new Exception();
                    }
                }

                // When finished, confirm with server that quiz send has completed
                OperationReturnMessage finalizationMessage = (OperationReturnMessage)SendStringData(
                    $"{info.DBId}`{info.LastModifiedDate}`{imageFilePaths.Length + 1}`" +
                    $"{CredentialManager.Username}`{await SecureStorage.GetAsync("password")}`-",
                    ServerRequestTypes.FinalizeQuizSend);

                if (finalizationMessage == OperationReturnMessage.True)
                {
                    QuizInfo infoCopy = new QuizInfo(info)
                    {
                        SyncStatus = (int)SyncStatusEnum.Synced
                    };
                    QuizRosterDatabase.EditQuizInfo(infoCopy);
                    return(true);
                }
                else
                {
                    throw new Exception();
                }
            }
            catch (Exception ex)
            {
                string test = ex.ToString();
                // Alert server that quiz send failed Delete records
                return(false);
            }
        }
        /// <summary>
        /// Constructing from an already existing quiz
        /// </summary>
        /// <param name="originalName">    </param>
        /// <param name="originalAuthor">  </param>
        public CreateNewQuizPage(QuizInfo oldQuizInfo)
        {
            this.InitializeComponent();
            this.SetUpBar();
            this.originalCategory            = oldQuizInfo.Category;
            this.originalAuthor              = oldQuizInfo.AuthorName;
            this.originalName                = oldQuizInfo.QuizName;
            this.PickerCategory.SelectedItem = oldQuizInfo.Category;

            this.originalQuizInfo = oldQuizInfo;
        }
Exemple #9
0
        /// <summary>
        /// Creates a new QuizInfo based on the information in another
        /// </summary>
        /// <param name="quizInfoToCopy">The quizInfo to make a copy of</param>
        public QuizInfo(QuizInfo quizInfoToCopy)
        {
            this.DBId       = quizInfoToCopy.DBId;
            this.AuthorName = quizInfoToCopy.AuthorName;
            this.QuizName   = quizInfoToCopy.QuizName;
            this.Category   = quizInfoToCopy.Category;

            this.LastModifiedDate  = quizInfoToCopy.LastModifiedDate;
            this.SyncStatus        = quizInfoToCopy.SyncStatus;
            this.IsDeletedLocally  = quizInfoToCopy.IsDeletedLocally;
            this.IsDeletedOnServer = quizInfoToCopy.IsDeletedOnServer;

            this.SubscriberCount = quizInfoToCopy.SubscriberCount;
        }
Exemple #10
0
        /// <summary>
        /// Deletes the quiz from the roster
        /// </summary>
        private async Task ButtonDelete_Clicked(string DBId)
        {
            bool answer = await this.DisplayAlert("Are you sure you want to delete this quiz?", "This will delete the copy on your device and in the cloud. This is not reversable.", "Yes", "No");

            if (answer)
            {
                // Acquire QuizInfo from roster
                QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(DBId);

                string path = rosterInfo.RelativePath;

                if (rosterInfo != null)
                {
                    string dbId = rosterInfo.DBId;

                    // tell the roster that the quiz is deleted
                    QuizInfo rosterInfoUpdated = new QuizInfo(rosterInfo)
                    {
                        IsDeletedLocally = true,
                        LastModifiedDate = DateTime.Now.ToString()
                    };
                    QuizRosterDatabase.EditQuizInfo(rosterInfoUpdated);

                    // If connected, tell server to delete this quiz If not, it will tell server to delete next time it is connected in QuizRosterDatabase.UpdateLocalDatabase()
                    OperationReturnMessage returnMessage = await ServerOperations.DeleteQuiz(dbId);

                    if (returnMessage == OperationReturnMessage.True)
                    {
                        QuizRosterDatabase.DeleteQuizInfo(dbId);
                    }

                    if (System.IO.Directory.Exists(path))
                    {
                        Directory.Delete(path, true);
                    }

                    this.QuizNumber.Text =
                        "You have published a total of " +
                        await Task.Run(() => ServerOperations.GetNumberOfQuizzesByAuthorName(CredentialManager.Username)) +
                        " quizzes!";
                }
                else
                {
                    await DisplayAlert("Could not delete quiz", "This quiz could not be deleted at this time. Please try again later", "OK");
                }

                // Setup Page again after deletion
                await this.UpdateProfilePageAsync();
            }
        }
Exemple #11
0
        /// <summary>
        /// When a user wants to unsubscribe from a quiz
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void ImageButtonUnsubscribe_Clicked(object sender, EventArgs e)
        {
            if (CredentialManager.IsLoggedIn)
            {
                ImageButton button = (sender as ImageButton);
                string      dbId   = button.StyleId;
                bool        answer = await this.DisplayAlert("Are you sure you want to unsubscribe?", "You will no longer get updates of this quiz", "Yes", "No");

                if (answer)
                {
                    ActivityIndicator indicatorSyncing = (button.Parent as StackLayout).Children[(int)SubscribeUtils.SubscribeType.Syncing] as ActivityIndicator;
                    button.IsVisible           = false;
                    indicatorSyncing.IsVisible = true;
                    indicatorSyncing.IsRunning = true;
                    // get rosterInfo
                    QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(dbId);
                    // tell the roster that the quiz is deleted
                    QuizInfo rosterInfoUpdated = new QuizInfo(rosterInfo)
                    {
                        IsDeletedLocally = true,
                        LastModifiedDate = DateTime.Now.ToString()
                    };
                    QuizRosterDatabase.EditQuizInfo(rosterInfoUpdated);

                    OperationReturnMessage returnMessage = await SubscribeUtils.UnsubscribeFromQuizAsync(dbId);

                    if (returnMessage == OperationReturnMessage.True)
                    {
                        (button.Parent as StackLayout).Children[(int)SubscribeUtils.SubscribeType.Subscribe].IsVisible = true; // add in subscribe button
                        QuizRosterDatabase.DeleteQuizInfo(dbId);
                    }
                    else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials)
                    {
                        button.IsVisible = true;
                        await this.DisplayAlert("Invalid Credentials", "Your current login credentials are invalid. Please log in and try again.", "OK");
                    }
                    else
                    {
                        button.IsVisible = true;
                        await this.DisplayAlert("Unsubscribe Failed", "The unsubscription request could not be completed. Please try again.", "OK");
                    }
                    indicatorSyncing.IsVisible = false;
                    indicatorSyncing.IsRunning = false;
                }
            }
            else
            {
                await this.DisplayAlert("Hold on!", "Before you can subscribe to any quizzes, you have to login.", "Ok");
            }
        }
Exemple #12
0
        /// <summary>
        /// Saves updates to a quizInfo
        /// </summary>
        /// <param name="editedQuizInfo">the new version of the quizinfo to save</param>
        public void EditQuizInfo(QuizInfo editedQuizInfo)
        {
            Realm realmDB = Realm.GetInstance(App.realmConfiguration(this.dbPath));

            realmDB.Write(() =>
            {
                realmDB.Add(editedQuizInfo, update: true);
            });

            QuizInfo rosterCopy = new QuizInfo(editedQuizInfo)
            {
                SyncStatus = (int)SyncStatusEnum.NeedUpload // Default to 1, meaning "needs upload" in roster
            };

            QuizRosterDatabase.EditQuizInfo(rosterCopy);
        }
Exemple #13
0
        /// <summary>
        /// Convert List of String arrays containing quiz data (from server) to QuizInfo objects
        /// </summary>
        /// <param name="quizData"></param>
        private static List <QuizInfo> ListOfDataToQuizInfo(List <string[]> quizDatas)
        {
            List <QuizInfo> toReturn = new List <QuizInfo>();

            foreach (string[] quizData in quizDatas)
            {
                QuizInfo newInfo = new QuizInfo();
                newInfo.DBId            = quizData[0];
                newInfo.AuthorName      = quizData[1];
                newInfo.QuizName        = quizData[2];
                newInfo.Category        = quizData[3];
                newInfo.SubscriberCount = int.Parse(quizData[4]);
                toReturn.Add(newInfo);
            }
            return(toReturn);
        }
Exemple #14
0
        /// <summary>
        /// Called when the user tries to download a quiz
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void SyncDownload_Clicked(object sender, EventArgs e)
        {
            // this.serverConnected = true;
            ImageButton button   = sender as ImageButton;
            string      dbId     = button.ClassId;
            QuizInfo    quizInfo = QuizRosterDatabase.GetQuizInfo(dbId);

            // DOES THIS WORK?
            while (quizInfo == null && Plugin.Connectivity.CrossConnectivity.Current.IsConnected)
            {
                await QuizRosterDatabase.UpdateLocalDatabaseAsync();

                quizInfo = QuizRosterDatabase.GetQuizInfo(dbId);
            }

            string authorName = quizInfo.AuthorName;
            string quizName   = quizInfo.QuizName;
            string category   = quizInfo.Category;

            ActivityIndicator indicatorSyncing = (button.Parent as StackLayout).Children[(int)UISyncStatus.Syncing] as ActivityIndicator;
            string            quizPath         = button.ClassId;

            button.IsVisible           = false;
            indicatorSyncing.IsVisible = true;
            indicatorSyncing.IsRunning = true;
            if (await Task.Run(() => ServerOperations.GetQuiz(dbId, category)))
            {
                ImageButton buttonSyncNoChange = (button.Parent as StackLayout).Children[(int)UISyncStatus.NoChange] as ImageButton;
                indicatorSyncing.IsVisible   = false;
                buttonSyncNoChange.IsVisible = true;

                (((button.Parent as StackLayout).Parent as StackLayout).Parent as Frame).StyleId = "Local";
            }
            else // If it failed to download
            {
                indicatorSyncing.IsVisible = false;
                button.IsVisible           = true;
                await this.DisplayAlert("Quiz Download Failed",
                                        "This quiz could not be downloaded from the server. Please try again.",
                                        "OK");
            }
            indicatorSyncing.IsRunning = false;
            await this.UpdateProfileContentAsync(
                this.SelectedCategory);
        }
Exemple #15
0
        /// <summary>
        /// Subscribes to a quiz given the ID
        /// </summary>
        /// <param name="dbId">the ID of the quiz to sub to</param>
        /// <param name="quizzesSearched">the quizzes currently displayed (used to get info about the quiz from the dbid)</param>
        /// <returns>If the subscription was successful</returns>
        public static async Task <OperationReturnMessage> SubscribeToQuizAsync(string dbId, List <QuizInfo> quizzesSearched)
        {
            if (QuizRosterDatabase.GetQuizInfo(dbId) == null) // make sure it isn't in yet
            {
                OperationReturnMessage returnMessage = await Task.Run(async() => await ServerOperations.SubscribeToQuiz(dbId));

                if (returnMessage == OperationReturnMessage.True)
                {
                    QuizInfo quiz             = quizzesSearched.Where(quizInfo => quizInfo.DBId == dbId).First();
                    string   lastModifiedDate = await Task.Run(() => ServerOperations.GetLastModifiedDate(dbId));

                    QuizInfo newInfo = new QuizInfo
                    {
                        DBId             = quiz.DBId,
                        AuthorName       = quiz.AuthorName,
                        QuizName         = quiz.QuizName,
                        Category         = quiz.Category,
                        LastModifiedDate = lastModifiedDate,
                        SyncStatus       = (int)SyncStatusEnum.NotDownloadedAndNeedDownload // 4 to represent not present in local directory and need download
                    };
                    QuizRosterDatabase.SaveQuizInfo(newInfo);
                    return(returnMessage);
                }
                else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials)
                {
                    CredentialManager.IsLoggedIn = false;
                    return(returnMessage);
                }
                else
                {
                    return(returnMessage);
                }
            }
            else
            {
                return(OperationReturnMessage.False);
            }
        }
Exemple #16
0
        /// <summary>
        /// Create a new quizinfo and adds it to the Quiz DB.
        /// A copy is stored in the device quiz roster.
        /// </summary>
        /// <param name="authorName">Author</param>
        /// <param name="quizName">Quiz name</param>
        /// <param name="category">Category</param>
        public void NewQuizInfo(string authorName, string quizName, string category)
        {
            QuizInfo newQuizInfo = new QuizInfo(authorName, quizName, category)
            {
                // Sync status is irrelevant in a Quiz Database's copy of the QuizInfo
                SyncStatus = -1
            };

            this.QuizInfo = newQuizInfo;

            Realm realmDB = Realm.GetInstance(App.realmConfiguration(this.dbPath));

            realmDB.Write(() =>
            {
                realmDB.Add(newQuizInfo);
            });

            QuizInfo rosterCopy = new QuizInfo(newQuizInfo)
            {
                SyncStatus = (int)SyncStatusEnum.NeedUpload // Default to 1, meaning "needs upload" in roster
            };

            QuizRosterDatabase.SaveQuizInfo(rosterCopy);
        }
        /// <summary>
        /// Handle when user presses "three dot" icon on the quiz tab
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void ImageButtonMenu_Clicked(object sender, EventArgs e)
        {
            string   DBId       = ((ImageButton)sender).ClassId;
            QuizInfo quizInfo   = QuizRosterDatabase.GetQuizInfo(DBId);
            string   quizName   = quizInfo.QuizName;
            string   author     = quizInfo.AuthorName;
            string   deleteText = "Delete";

            if (author != CredentialManager.Username)
            {
                deleteText = "Unsubscribe";
            }

            string action = await this.DisplayActionSheet(quizName, "Back", null, deleteText, "Edit");

            if (action == deleteText)
            {
                this.ButtonDelete_Clicked(((ImageButton)sender).StyleId, ((ImageButton)sender).ClassId);
            }
            else if (action == "Edit")
            {
                this.ButtonEdit_Clicked(DBId);
            }
        }
Exemple #18
0
        /// <summary>
        /// Download a quiz from the server.
        /// </summary>
        /// <param name="dBId">The DBId of the quiz to download</param>
        /// <param name="category">The category the quiz belongs in.</param>
        /// <returns></returns>
        public static bool GetQuiz(string dBId, string category)
        {
            // TO DO: CHECK IF quizName or category changed and save accordingly
            string tempPath     = App.UserPath + "/" + "temp" + "/" + dBId + "/";
            string tempFilePath = tempPath + "/" + realmFileExtension;

            // Store the realm file into a temporary directory in order the retrieve information from it
            // (Information regarding the images in order to retrieve them from the server)
            Directory.CreateDirectory(tempPath);
            byte[] realmFile = (byte[])SendStringData($"{dBId}/-", ServerRequestTypes.GetRealmFile);
            if (realmFile.Length > 0)
            {
                File.WriteAllBytes(tempFilePath, realmFile);
            }
            else
            {
                return(false);
            }

            // Retrieve info regarding the images from the realm file from its temporary location
            Realm realmDB = Realm.GetInstance(App.realmConfiguration(tempFilePath));
            IQueryable <Question> questionsWithPictures = realmDB.All <Question>().Where(question => question.NeedsPicture);

            foreach (Question question in questionsWithPictures)
            {
                byte[] jpegFile     = (byte[])SendStringData($"{question.QuestionId}/{dBId}/-", ServerRequestTypes.GetJPEGImage);
                string jpegFilePath = tempPath + "/" + question.QuestionId + jpegFileExtension;
                if (jpegFile.Length > 0)
                {
                    File.WriteAllBytes(jpegFilePath, jpegFile);
                }
                else
                {
                    return(false);
                }
            }

            QuizInfo info               = realmDB.All <QuizInfo>().First();
            string   newQuizName        = info.QuizName;
            string   newCategory        = info.Category;
            string   newLastModfiedDate = info.LastModifiedDate;

            string quizPath      = info.RelativePath;
            string realmFilePath = quizPath + "/" + info.DBId + realmFileExtension;

            Directory.CreateDirectory(quizPath);

            string[] imageFilePaths = Directory.GetFiles(tempPath, "*.jpg");
            string[] realmFilePaths = Directory.GetFiles(tempPath, "*.realm");
            foreach (string path in realmFilePaths)
            {
                File.Copy(path, quizPath + "/" + info.DBId + realmFileExtension, true);
            }

            foreach (string path in imageFilePaths)
            {
                string imageName = path.Split('/').Last();
                File.Copy(path, quizPath + "/" + imageName, true);
            }

            if (category != newCategory)
            {
                DeleteDirectory(info.RelativePath, true);
            }

            DeleteDirectory(tempPath, true);

            QuizInfo infoCopy = new QuizInfo(QuizRosterDatabase.GetQuizInfo(dBId))
            {
                SyncStatus       = (int)SyncStatusEnum.Synced,
                QuizName         = newQuizName,
                Category         = newCategory,
                LastModifiedDate = newLastModfiedDate
            };

            QuizRosterDatabase.EditQuizInfo(infoCopy);

            return(true);
        }
Exemple #19
0
        /// <summary>
        /// Updates the local database by syncing with the server
        /// </summary>
        /// <returns>an awaitable task for the completion of syncing</returns>
        public static async Task UpdateLocalDatabaseAsync()
        {
            if (App.Path != null && App.UserPath.Length > 2)
            {
                RealmConfiguration threadConfig = App.realmConfiguration(RosterPath);
                Realm threadInstance            = Realm.GetInstance(threadConfig);

                List <QuizInfo> QuizInfos = new List <QuizInfo>(threadInstance.All <QuizInfo>());
                if (CrossConnectivity.Current.IsConnected)
                {
                    for (int i = 0; i < QuizInfos.Count(); i++)
                    {
                        if (CredentialManager.IsLoggedIn)
                        {
                            if (QuizInfos[i].IsDeletedLocally)
                            {
                                if (await ServerOperations.DeleteQuiz(QuizInfos[i].DBId) == OperationReturnMessage.True)
                                {
                                    string toDeleteDBId = QuizInfos[i].DBId;
                                    QuizInfos.Remove(QuizInfos[i]);
                                    DeleteQuizInfo(toDeleteDBId);
                                }
                            }
                            else if (QuizInfos[i].SyncStatus != (int)SyncStatusEnum.NotDownloadedAndNeedDownload)
                            {
                                string lastModifiedDate = ServerOperations.GetLastModifiedDate(QuizInfos[i].DBId);
                                if (lastModifiedDate == "") // returns empty string could not reach server
                                {
                                    QuizInfo copy = new QuizInfo(QuizInfos[i])
                                    {
                                        SyncStatus = (int)SyncStatusEnum.Offline // 3 represents offline
                                    };
                                    EditQuizInfo(copy, threadInstance);
                                }
                                else
                                {
                                    // Server returns "false" if quiz is not already on the server
                                    if (lastModifiedDate == "false" || lastModifiedDate == null)
                                    {
                                        QuizInfo copy = new QuizInfo(QuizInfos[i])
                                        {
                                            SyncStatus = (int)SyncStatusEnum.NeedUpload // 1 represents need upload
                                        };
                                        EditQuizInfo(copy, threadInstance);
                                    }
                                    else
                                    {
                                        DateTime localModifiedDateTime  = Convert.ToDateTime(QuizInfos[i].LastModifiedDate);
                                        DateTime serverModifiedDateTime = Convert.ToDateTime(lastModifiedDate);
                                        if (localModifiedDateTime > serverModifiedDateTime)
                                        {
                                            QuizInfo copy = new QuizInfo(QuizInfos[i])
                                            {
                                                SyncStatus = (int)SyncStatusEnum.NeedUpload // 1 represents need upload
                                            };
                                            EditQuizInfo(copy, threadInstance);
                                        }
                                        else if (localModifiedDateTime < serverModifiedDateTime)
                                        {
                                            QuizInfo copy = new QuizInfo(QuizInfos[i])
                                            {
                                                SyncStatus = (int)SyncStatusEnum.NeedDownload // 0 represents needs download
                                            };
                                            EditQuizInfo(copy, threadInstance);
                                        }
                                        else if (localModifiedDateTime == serverModifiedDateTime)
                                        {
                                            QuizInfo copy = new QuizInfo(QuizInfos[i])
                                            {
                                                SyncStatus = (int)SyncStatusEnum.Synced // 2 represents in sync
                                            };
                                            EditQuizInfo(copy, threadInstance);
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            QuizInfo copy = new QuizInfo(QuizInfos[i])
                            {
                                SyncStatus = (int)SyncStatusEnum.Synced // 2 represents in sync
                            };
                            EditQuizInfo(copy, threadInstance);
                        }
                    }

                    string[] dbIds = new string[QuizInfos.Count];
                    for (int i = 0; i < dbIds.Length; i++)
                    {
                        dbIds[i] = QuizInfos[i].DBId;
                    }

                    List <string[]> missingQuizs = ServerOperations.GetMissingQuizzesByAuthorName(CredentialManager.Username, dbIds);
                    foreach (string[] missingQuiz in missingQuizs)
                    {
                        QuizInfo info = new QuizInfo
                        {
                            DBId             = missingQuiz[0],
                            AuthorName       = missingQuiz[1],
                            QuizName         = missingQuiz[2],
                            Category         = missingQuiz[3],
                            LastModifiedDate = missingQuiz[4],
                            SubscriberCount  = int.Parse(missingQuiz[5]),
                            SyncStatus       = (int)SyncStatusEnum.NotDownloadedAndNeedDownload
                        };
                        threadInstance.Write(() =>
                        {
                            threadInstance.Add(info);
                        });
                    }
                }
                else
                {
                    for (int i = 0; i < QuizInfos.Count; i++)
                    {
                        QuizInfo copy = new QuizInfo(QuizInfos[i])
                        {
                            SyncStatus = (int)SyncStatusEnum.Offline // 3 represents offline
                        };
                        EditQuizInfo(copy, threadInstance);
                    }
                }
            }
        }
        /// <summary>
        /// Generate a frame (card-like button) for the UI based on a QuizInfo
        /// </summary>
        /// <param name="quizInfo">QuizInfo of the quiz to generate a frame for</param>
        /// <returns></returns>
        private Frame GenerateFrame(QuizInfo quizInfo)
        {
            Frame frame = new Frame()
            {
                VerticalOptions   = LayoutOptions.Start,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                CornerRadius      = 10
            };

            StackLayout frameStack = new StackLayout // 1st Child of frameLayout
            {
                FlowDirection = FlowDirection.LeftToRight,
                Orientation   = StackOrientation.Vertical,
                Padding       = 10
            };

            StackLayout topStack = new StackLayout
            {
                FlowDirection     = FlowDirection.LeftToRight,
                Orientation       = StackOrientation.Horizontal,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            Label title = new Label // 0
            {
                Text              = quizInfo.QuizName,
                FontSize          = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                FontAttributes    = FontAttributes.Bold,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.FillAndExpand //,
                                                                //HeightRequest = 45
            };

            topStack.Children.Add(title);

            // Add the sync buttons, We create one for each sync action to keep correct formatting and fix a sizing bug.
            ImageButton SyncOffline = new ImageButton // 1
            {
                IsVisible         = false,
                Source            = "ic_cloud_off_black_48dp.png",
                HeightRequest     = 25,
                WidthRequest      = 25,
                BackgroundColor   = Color.White,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
                ClassId           = quizInfo.DBId,
                StyleId           = quizInfo.Category
            };

            SyncOffline.Clicked += this.SyncOffline_Clicked;
            topStack.Children.Add(SyncOffline);

            ImageButton SyncUpload = new ImageButton // 2
            {
                IsVisible         = false,
                Source            = "ic_cloud_upload_black_48dp.png",
                HeightRequest     = 25,
                WidthRequest      = 25,
                BackgroundColor   = Color.White,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
                ClassId           = quizInfo.DBId,
                StyleId           = quizInfo.Category
            };

            SyncUpload.Clicked += this.SyncUpload_Clicked;
            topStack.Children.Add(SyncUpload);

            ImageButton SyncDownload = new ImageButton // 3
            {
                IsVisible         = false,
                Source            = "ic_cloud_download_black_48dp.png",
                HeightRequest     = 25,
                WidthRequest      = 25,
                BackgroundColor   = Color.White,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
                ClassId           = quizInfo.DBId,
                StyleId           = quizInfo.Category
            };

            SyncDownload.Clicked += this.SyncDownload_Clicked;
            topStack.Children.Add(SyncDownload);

            ImageButton SyncNoChange = new ImageButton // 4
            {
                IsVisible         = false,
                Source            = "ic_cloud_done_black_48dp.png",
                HeightRequest     = 25,
                WidthRequest      = 25,
                BackgroundColor   = Color.White,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
                ClassId           = quizInfo.DBId,
                StyleId           = quizInfo.Category
            };

            SyncNoChange.Clicked += this.SyncNoChange_Clicked;
            topStack.Children.Add(SyncNoChange);

            ActivityIndicator Syncing = new ActivityIndicator // 5
            {
                IsVisible         = false,
                Color             = Color.Accent,
                HeightRequest     = 25,
                WidthRequest      = 25,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
            };

            topStack.Children.Add(Syncing);

            ImageButton imageButtonMenu = new ImageButton // 6
            {
                Source            = "ic_more_vert_black_48dp.png",
                HeightRequest     = 35,
                WidthRequest      = 35,
                BackgroundColor   = Color.White,
                VerticalOptions   = LayoutOptions.StartAndExpand,
                HorizontalOptions = LayoutOptions.End,
                ClassId           = quizInfo.DBId
            };

            imageButtonMenu.Clicked += this.ImageButtonMenu_Clicked;
            topStack.Children.Add(imageButtonMenu);

            if (CredentialManager.Username == quizInfo.AuthorName)
            {
                imageButtonMenu.StyleId = "Delete";
            }
            else
            {
                imageButtonMenu.StyleId = "Unsubscribe";
            }

            frameStack.Children.Add(topStack);

            BoxView Seperator = new BoxView // 1
            {
                Color             = Color.LightGray,
                CornerRadius      = 1,
                HeightRequest     = 2,
                WidthRequest      = Application.Current.MainPage.Width - 75,
                HorizontalOptions = LayoutOptions.CenterAndExpand,
                VerticalOptions   = LayoutOptions.CenterAndExpand
            };

            frameStack.Children.Add(Seperator);

            Label Author = new Label // 2
            {
                Text              = "Created by: " + quizInfo.AuthorName,
                FontSize          = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
                VerticalOptions   = LayoutOptions.End,
                HorizontalOptions = LayoutOptions.StartAndExpand
            };

            frameStack.Children.Add(Author);

            // The sync button thats active in the current frame
            ImageButton activeSync;

            if (quizInfo.SyncStatus == (int)SyncStatusEnum.Offline) // SyncOffline
            {
                SyncOffline.IsVisible = true;
                activeSync            = SyncOffline;
            }
            else if (quizInfo.SyncStatus == (int)SyncStatusEnum.Synced) // SyncNoChange
            {
                SyncNoChange.IsVisible = true;
                activeSync             = SyncNoChange;
            }
            else if (quizInfo.SyncStatus == (int)SyncStatusEnum.NeedUpload && quizInfo.AuthorName == CredentialManager.Username) // SyncUpload
            {
                SyncUpload.IsVisible = true;
                activeSync           = SyncUpload;
            }
            else if (quizInfo.SyncStatus == (int)SyncStatusEnum.NeedDownload ||
                     quizInfo.SyncStatus == (int)SyncStatusEnum.NotDownloadedAndNeedDownload) // SyncDownload
            {
                SyncDownload.IsVisible = true;
                activeSync             = SyncDownload;
                if (quizInfo.SyncStatus == (int)SyncStatusEnum.NotDownloadedAndNeedDownload) // Sync Download & notLocal yet
                {
                    frame.StyleId = "notLocal";
                }
            }
            else
            {
                SyncOffline.IsVisible = true;
                activeSync            = SyncOffline;
            }

            TapGestureRecognizer recognizer = new TapGestureRecognizer();

            recognizer.Tapped += async(object sender, EventArgs e) =>
            {
                if (frame.StyleId != "notLocal")
                {
                    frame.GestureRecognizers.Remove(recognizer);
                    frame.BackgroundColor           = Color.LightGray;
                    Seperator.Color                 = Color.Gray;
                    imageButtonMenu.BackgroundColor = Color.LightGray;
                    activeSync.BackgroundColor      = Color.LightGray;

                    // Load the quiz associated with this DBId
                    Quiz newQuiz = new Quiz(quizInfo.DBId);
                    //await this.RemoveMenu(frameMenu);
                    await this.Navigation.PushAsync(new Game(newQuiz));

                    frame.BackgroundColor           = Color.Default;
                    Seperator.Color                 = Color.LightGray;
                    imageButtonMenu.BackgroundColor = Color.White;
                    activeSync.BackgroundColor      = Color.White;
                    frame.GestureRecognizers.Add(recognizer);
                }
                else
                {
                    await this.DisplayAlert("Hold on!", "In order to study with this quiz, you must download it first", "OK");
                }
            };

            frame.GestureRecognizers.Add(recognizer);
            frame.Content = frameStack;

            return(frame);
        }
        /// <summary>
        /// Saves the user created quiz
        /// </summary>
        /// <param name="sender">  </param>
        /// <param name="e">       </param>
        private async void ButtonCreateQuiz_Clicked(object sender, EventArgs e)
        {
            this.Done.IsEnabled = false;
            if (string.IsNullOrWhiteSpace(this.EditorQuizName.Text))
            {
                await this.DisplayAlert("Couldn't Create Quiz", "Please give your quiz a name.", "OK");
            }
            else if (this.StackLayoutQuestionStack.Children.Count < 2)
            {
                await this.DisplayAlert("Couldn't Create Quiz", "Please create at least two questions", "OK");
            }
            else if (this.PickerCategory.SelectedIndex == -1)
            {
                await this.DisplayAlert("Couldn't Create Quiz", "Please give your quiz a category", "OK");
            }
            else
            {
                List <Question> previousQuestions = new List <Question>();

                List <Question> NewQuestions = new List <Question>();  // A list of questions the user wants to add to the database

                // Loops through each question frame on the screen
                foreach (Frame frame in this.StackLayoutQuestionStack.Children)
                {
                    // A list of all the children of the current frame
                    IList <View> children = ((StackLayout)frame.Content).Children;

                    Question addThis;
                    //The answers to the question
                    string[] answers = { ((Editor)children[2]).Text?.Trim(),   //Correct answer
                                         ((Editor)children[3]).Text?.Trim(),   // Incorect answer
                                         ((Editor)children[4]).Text?.Trim(),   // Incorect answer
                                         ((Editor)children[5]).Text?.Trim() }; // Incorect answer

                    // Checks if there is a question set
                    if (string.IsNullOrWhiteSpace(((Editor)children[1]).Text))
                    {
                        await this.DisplayAlert("Couldn't Create Quiz", "Every question must have a question set", "OK");

                        goto exit;
                    }

                    if (((ImageButton)children[6]).IsVisible) // if the question needs an image
                    {
                        addThis = new Question(
                            ((Editor)children[1]).Text?.Trim(),                        // The Question
                            ((ImageButton)children[6]).Source.ToString().Substring(6), // adds image using the image source
                            answers)
                        {
                            NeedsPicture = true
                        };
                    }
                    else // if the question does not need an image
                    {
                        addThis = new Question(
                            ((Editor)children[1]).Text?.Trim(),
                            answers);
                    }

                    string questionType = ((Button)((StackLayout)children[0]).Children[0]).Text;

                    // Sets the question type

                    if (questionType == "Question Type: Multiple choice")
                    {
                        int size = 0;
                        foreach (string answer in answers)
                        {
                            if (!string.IsNullOrWhiteSpace(answer))
                            {
                                size++;
                            }
                        }
                        if (size < 2 || string.IsNullOrWhiteSpace(answers[0]))
                        {
                            await this.DisplayAlert("Couldn't Create Quiz", "Mulitple choice questions must have a correct answer and at least one wrong answer", "OK");

                            goto exit;
                        }

                        addThis.QuestionType = 0;
                    }
                    else
                    {
                        if (string.IsNullOrWhiteSpace(answers[0]))
                        {
                            await this.DisplayAlert("Couldn't Create Quiz", "Text answer questions must have an answer", "OK");

                            goto exit;
                        }

                        if (questionType == "Question Type: Text answer")
                        {
                            addThis.QuestionType = 1;
                        }
                        else
                        {
                            addThis.QuestionType = 2;
                        }
                    }

                    addThis.QuestionId = frame.StyleId; // Set the questionId

                    NewQuestions.Add(addThis);
                }

                Quiz database;
                // If editing their own quiz
                if (this.originalQuizInfo != null && this.originalAuthor == CredentialManager.Username)
                {
                    database = new Quiz(this.originalQuizInfo.DBId);

                    // Set previousQuestions to the correct previous questions
                    previousQuestions = database.GetQuestions();
                }
                else // If new quiz
                {
                    database = new Quiz(
                        CredentialManager.Username,
                        this.EditorQuizName.Text.Trim(),
                        this.PickerCategory.Items[this.PickerCategory.SelectedIndex]);
                }

                // Add if it doesn't already exist, delete if it doesn't exist anymore, update the ones that need to be updated, and do nothing to the others
                if (previousQuestions.Count == 0 || originalAuthor != CredentialManager.Username)
                {
                    // if the user created this for the first time

                    // Save a new QuizInfo into the quiz database, which also adds this QuizInfo to the device quiz roster
                    database.AddQuestions(NewQuestions.ToArray());
                }
                else // edit
                {
                    string   currentDirectory = database.DBFolderPath;
                    QuizInfo updatedQuizInfo  = new QuizInfo(database.QuizInfo)
                    {
                        QuizName         = this.EditorQuizName.Text?.Trim(),
                        LastModifiedDate = DateTime.Now.ToString(),
                        Category         = this.PickerCategory.Items[this.PickerCategory.SelectedIndex]
                    };
                    database.EditQuizInfo(updatedQuizInfo);
                    if (currentDirectory != updatedQuizInfo.RelativePath)
                    {
                        Directory.CreateDirectory(updatedQuizInfo.RelativePath);
                        Directory.Delete(updatedQuizInfo.RelativePath, true);
                        Directory.Move(currentDirectory, updatedQuizInfo.RelativePath);
                    }

                    // Logic for how to save each question.
                    for (int i = 0; i <= previousQuestions.Count() - 1; i++)
                    {
                        bool DBIdSame = true;
                        // test each old question with each new question
                        foreach (Question newQuestion in NewQuestions)
                        {
                            if (previousQuestions[i].QuestionId == newQuestion.QuestionId)
                            {
                                DBIdSame = true;
                                // the same question, but changed, so update
                                database.EditQuestion(newQuestion);
                                NewQuestions.Remove(newQuestion);
                                break;
                            }
                            else
                            {
                                DBIdSame = false;
                            }
                        }

                        if (!DBIdSame) // if the question doesn't exist in the new list. delete it
                        {
                            database.DeleteQuestions(previousQuestions[i]);
                        }
                    }

                    // Add all the questions that aren't eddited
                    database.AddQuestions(NewQuestions.ToArray());
                }

                File.Create(database.DBFolderPath + ".nomedia");

                // Returns user to front page of QuizEditor and refreshed database
                await this.Navigation.PopAsync(true);
            }
            exit :;
            this.Done.IsEnabled = true;
        }