コード例 #1
0
        //DEAD CODE FOR NOW
        protected virtual bool WillFirstReminderBeRemoved(List <ReminderEntity> remindersToBeRemoved)
        {
            if (!ElapsedActiveReminders.Any())
            {
                //it will not be removed because it doesn't exist
                return(false);
            }

            ReminderEntity firstReminder = ElapsedActiveReminders.First();
            bool           firstReminderWillBeRemoved = remindersToBeRemoved.Any(rem => rem.Name == firstReminder.Name);

            return(firstReminderWillBeRemoved);
        }
コード例 #2
0
        /// <summary>
        /// Immediately fires next event if there is any reminder in the list, or goes to NoElapsedReminders state otherwise.
        /// </summary>
        protected virtual void GoToRingingOrIdleState(DateTime now)
        {
            if (ElapsedActiveReminders.Any())
            {
                var nextToRing = ElapsedActiveReminders.First();

                GoToRingingState(nextToRing.Name, now);
            }
            else
            {
                UserState = UserInteractionState.NoElapsedReminders;
                Log.Logger.Information($"No elapsed reminders in the list. GoToRingingOrIdleState method is setting state to NoElapsedReminders");
            }
        }
コード例 #3
0
        //TODO DP->SI: provide functionallity to run immediately all snooze reminders, not to bother user later with them. This will also be useful for IsOkToModifyReminder situation

        public virtual bool IsOkToModifyReminder(string reminderName)
        {
            bool     reminderIsInList = ElapsedActiveReminders.Any(rem => rem.Name == reminderName);
            DateTime now = DateTime.UtcNow;

            //TODO DP->SI: instead of running them now, it would be more polite to ask user if he wants to run the reminder now. It would be even better to just update the reminders immediately, but that is too complex for now (see UpdateReminderList method)
            if (reminderIsInList && UserState != UserInteractionState.Disabled)
            {
                Log.Logger.Information("Change of elapsed but not dismissed reminder was attempted. Running snoozed reminders now.");

                SnoozeTimer.Stop();
                GoToRingingOrIdleState(now); //TODO: this may be unsafe as maybe we are not in snooze state, but e.g. already waiting user reaction?
            }

            return(!reminderIsInList);
        }
コード例 #4
0
        /// <summary>
        /// Call this method when a reminder elapses. Robust to adding again elapsed reminders that are not yet dismissed.
        /// </summary>
        /// <param name="reminder"></param>
        public virtual void OnReminderElapsed(ReminderEntity reminder)
        {
            DateTime now = DateTime.UtcNow;

            if (reminder == null)
            {
                //just a redundant check so that this component has robust interface
                Log.Logger.Error($"OnReminderElapsed event fired with null reminder. Ignoring OnReminderElapsed event");
                return;
            }

            //TODO: duplicate reminder could be added as a consequence of change to the reminder entity. This would need to be handled, especially when the first reminder is changed.
            if (ElapsedActiveReminders.Any(rem => rem.Name == reminder.Name))
            {
                Log.Logger.Information($"ElapsedActiveReminders list already contains reminder [name = {reminder.Name}]. Ignoring OnReminderElapsed event.");
                return;
            }

            ElapsedActiveReminders.Add(reminder); //TODO: is some sorting needed or it is safe to always add it at the end? Otherwise, we would maybe need to handle change of first reminder.

            Log.Logger.Information($"Processing OnReminderElapsed event [name = {reminder.Name}, current component state = {UserState}].");
            switch (UserState)
            {
            case UserInteractionState.NoElapsedReminders:
                //start ringing
                GoToRingingState(reminder.Name, now);
                break;

            case UserInteractionState.WaitingUserResponse:
                //ignoring next reminder until previous remidner is handled
                //what to do when another event comes but previous is not yet handled by the user - just show them one by one, when handling previous is over, or update this one to show all?
                break;

            case UserInteractionState.SnoozeTime:
                //ignoring next reminder until previous remidner is handled
                //TODO: later add feature to force showing of both (or more) reminders in the same form window (forcing showing them one by one would be confusing as we don't respect snooze interval, and user is not aware that behing this reminder is another (potentially with higher priority))
                break;

            case UserInteractionState.Disabled:
                Log.Logger.Information($"OnReminderElapsed event [name = {reminder.Name}] will be handled just by adding reminder to the list because UserInteractionManager is currently not enabled.");
                break;
            }
        }
コード例 #5
0
        protected virtual void HandleSnoozeElapsed(DateTime now)
        {
            if (UserState != UserInteractionState.SnoozeTime)
            {
                //only expected to happen as a result of not well handled concurrency
                //this may put component in a deadlock probably! Will disable+enabled unblock the state?
                Log.Logger.Error($"UserState is {UserState} instead of {UserInteractionState.SnoozeTime} after snooze period elapsed. Ignoring timer event.");
                return;
            }

            var nextReminderToRing = ElapsedActiveReminders.FirstOrDefault();

            if (nextReminderToRing == null)
            {
                //only expected to happen as a result of not well handled concurrency
                Log.Logger.Error($"No reminder found after snooze period elapsed. Going to {UserInteractionState.NoElapsedReminders} state.");
                UserState = UserInteractionState.NoElapsedReminders;
                return;
            }

            GoToRingingState(nextReminderToRing.Name, now);
        }
コード例 #6
0
        //todo: all these return statements are risky, they prevent the only chance for the user the make next step and don't give him another chance. e.g. if snooze feautre is disabled while ringing form is open, and than user clicks snooze
        //todo: when component is disabled we skip all processing, not just going to next state, review this once more to bse sure that this is ok. Same for snooze, snooze elapsed,
        //todo: hide snooze button if that feature is disabled(Ringer can call service via WCF webservice to check is snooze is enabled), we will probably need to handle closing the form as dismiss, not snooze. We also need to prevent accidental closing of form on escape button.
        //todo: validation if reminders as paramters to dismiss and snooze, are indeed excepted (or we first expect some other), or just remove them (less safe)
        public void DismissReminder(ReminderEntity reminderEntity)
        {
            DateTime now = DateTime.UtcNow;

            if (UserState != UserInteractionState.WaitingUserResponse)
            {
                Log.Logger.Error($"Ignoring attempt to dismiss reminder [name = {reminderEntity.Name}] because current scheduler state is {UserState} instead od WaitingUserResponse");
                return;
            }

            // Protection of some kind of double dismis request (maybe by multiple ringing windows or something else) that would cause next occurance of reminder to be skipped
            if (!ValidateReminderShouldBeRinging(reminderEntity, now))
            {
                return;
            }

            if (reminderEntity.IsRepeatable())
            {
                //setting next ringing of the reminder on its first next occurence by its schedule
                DateTime nextReminderRinging = new NextReminderOccurenceCalculator().GetNextReminderOccurence(reminderEntity, now).Value;
                reminderEntity.ScheduledTime = nextReminderRinging;
            }
            else
            {
                reminderEntity.Dismissed = true;
            }

            ElapsedActiveReminders.RemoveAll(r => r.Name == reminderEntity.Name);

            //TODO: test this - we are here potenitally calling ringer again before response for Dismissing is returned.
            GoToRingingOrIdleState(now);

            //indirectly also triggers UpdateReminderList on this object //TODO: what are effects of that, probably none?
            //TODO: immediate notifying of this change to NextReminderNOtifier is not needed. Should it be prevented or it produces no harm, as it only gives us duplicate reminders here?
            FilePersistenceAdapters.RemiderFilePersistence.OnEntitesChanged();
        }
コード例 #7
0
        //DEAD CODE FOR NOW
        /// <summary>
        /// We are not introducing new reminders through this method, we are just filtering out timers that are possibly not for ringing any more (and that are deleted) or modifying the existing ones
        /// </summary>
        public virtual void UpdateReminderList(IList <ReminderEntity> upToDateReminders)
        {
            Log.Logger.Information("Updating list of reminders in UserInteractionManger");

            DateTime now = DateTime.UtcNow; //good to be constant in a variable during this analysis in method so that it doesn't change during analysis. It could make some kind of timer deadlock where timer would never ring.

            //pause timer util we decide when should it ring again
            if (UserState != UserInteractionState.Disabled)
            {
                Log.Logger.Information("Pausing UserInteractionManger timer (if it is running at all)");
                SnoozeTimer.Stop();
            }

            List <ReminderEntity> remindersToBeRemoved = new List <ReminderEntity>();

            //finding elapsed reminders that don't exist anymore
            foreach (ReminderEntity elapsedReminder in ElapsedActiveReminders)
            {
                ReminderEntity upToDateVersionOfElapsedReminder = upToDateReminders.FirstOrDefault(rem => rem.Name == elapsedReminder.Name);
                bool           elapsedReminderStillExists       = upToDateVersionOfElapsedReminder == null;

                if (elapsedReminderStillExists)
                {
                    //TODO: elapsed reminder still exists but it could be changed. Maybe it is not for ringing anymore or some other its parameter was modified? Should we event prevent this kind of changes during snooze period?
                }
                else
                {
                    remindersToBeRemoved.Add(elapsedReminder);
                }
            }

            bool willFirstReminderBeRemoved = WillFirstReminderBeRemoved(remindersToBeRemoved);

            if (willFirstReminderBeRemoved)
            {
                //handle state change
            }

            foreach (ReminderEntity reminderToBeRemoved in remindersToBeRemoved)
            {
                ElapsedActiveReminders.RemoveAll(r => r.Name == reminderToBeRemoved.Name);
            }


            //foreach (ReminderEntity upToDateReminder in upToDateReminders)
            //{
            //    ReminderEntity elapsedVersionOfUpToDateReminder = ElapsedActiveReminders.FirstOrDefault(rem => rem.Name == upToDateReminder.Name);

            //    if (elapsedVersionOfUpToDateReminder == null)
            //    {
            //        //new reminder is detected, but we can ignore this because it will first be processed by NextReminderNotifier, and if it is elapsed it will fire an event for that reminder
            //    }
            //}


            //if scheduler is enabled continue timer (if there is need for this at all after change of reminders)
            if (UserState != UserInteractionState.Disabled)
            {
                //TryToScheduleNextReminder(now);
            }

            Log.Logger.Information("Updating list of reminders in ReminderScheduler done");
        }