Ejemplo n.º 1
0
        internal void Reload()
        {
            var range    = new NSRange(0, TimeEntriesLogTableView.NumberOfSections());
            var indexSet = NSIndexSet.FromNSRange(range);

            TimeEntriesLogTableView.ReloadSections(indexSet, UITableViewRowAnimation.None);
        }
Ejemplo n.º 2
0
        public void HideRatingView()
        {
            if (ratingView == null)
            {
                return;
            }

            ratingView.RemoveFromSuperview();
            ratingView.Dispose();
            ratingView = null;

            //We have to scroll a little to update the header size.
            //Using LayoutSubviews(), SetNeedsLayout(), LayoutIfNeeded() etc. does not work.
            var offset = TimeEntriesLogTableView.ContentOffset;
            var rect   = new CGRect
            {
                X = offset.X,
                Y = offset.Y == 0
                    ? TimeEntriesLogTableView.Frame.Height + 1
                    : offset.Y - 1,
                Width  = 1,
                Height = 1
            };

            TimeEntriesLogTableView.ScrollRectToVisible(rect, true);
        }
Ejemplo n.º 3
0
        //Spider is added in code, because IB doesn't allow adding subviews
        //to a UITableView and the spider needs to be a subview of the table
        //view so it reacts to pulling down to refresh
        private void prepareSpiderViews()
        {
            var spiderHinge = new UIView();

            spiderHinge.Layer.CornerRadius = spiderHingeCornerRadius;
            spiderHinge.TranslatesAutoresizingMaskIntoConstraints = false;
            spiderHinge.BackgroundColor = Color.Main.SpiderHinge.ToNativeColor();
            spiderContainerView.TranslatesAutoresizingMaskIntoConstraints = false;
            spiderBroView.TranslatesAutoresizingMaskIntoConstraints       = false;
            spiderContainerView.BackgroundColor = UIColor.Clear;

            spiderContainerView.AddSubview(spiderHinge);
            spiderContainerView.AddSubview(spiderBroView);
            TimeEntriesLogTableView.AddSubview(spiderContainerView);

            //Container constraints
            spiderContainerView.WidthAnchor.ConstraintEqualTo(TimeEntriesLogTableView.WidthAnchor).Active     = true;
            spiderContainerView.HeightAnchor.ConstraintEqualTo(TimeEntriesLogTableView.HeightAnchor).Active   = true;
            spiderContainerView.CenterYAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterYAnchor).Active = true;
            spiderContainerView.CenterXAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterXAnchor).Active = true;

            //Hinge constraints
            spiderHinge.WidthAnchor.ConstraintEqualTo(spiderHingeWidth).Active                    = true;
            spiderHinge.HeightAnchor.ConstraintEqualTo(spiderHingeHeight).Active                  = true;
            spiderHinge.TopAnchor.ConstraintEqualTo(spiderContainerView.TopAnchor).Active         = true;
            spiderHinge.CenterXAnchor.ConstraintEqualTo(spiderContainerView.CenterXAnchor).Active = true;

            //Spider constraints
            spiderBroView.TopAnchor.ConstraintEqualTo(spiderContainerView.TopAnchor).Active         = true;
            spiderBroView.WidthAnchor.ConstraintEqualTo(spiderContainerView.WidthAnchor).Active     = true;
            spiderBroView.BottomAnchor.ConstraintEqualTo(spiderContainerView.BottomAnchor).Active   = true;
            spiderBroView.CenterXAnchor.ConstraintEqualTo(spiderContainerView.CenterXAnchor).Active = true;
        }
Ejemplo n.º 4
0
        public override void ViewDidLayoutSubviews()
        {
            base.ViewDidLayoutSubviews();

            TimeEntriesLogTableView.ContentInset = new UIEdgeInsets(
                top: -TimeEntriesLogViewSource.SpaceBetweenSections,
                left: 0,
                bottom: (nfloat)System.Math.Max(CurrentTimeEntryCard.Frame.Height, StartTimeEntryButton.Frame.Height),
                right: 0);

            TimeEntriesLogTableView.BringSubviewToFront(TimeEntriesLogTableView.TableHeaderView);

            if (viewInitialized)
            {
                return;
            }

            viewInitialized = true;

            ViewModel.IsTimeEntryRunning
            .Where(visible => visible)
            .Subscribe(_ => showTimeEntryCard())
            .DisposedBy(disposeBag);

            ViewModel.IsTimeEntryRunning
            .Where(visible => !visible)
            .Subscribe(_ => hideTimeEntryCard())
            .DisposedBy(disposeBag);
        }
Ejemplo n.º 5
0
        public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
        {
            base.TraitCollectionDidChange(previousTraitCollection);
            traitCollectionSubject.OnNext(Unit.Default);
            TimeEntriesLogTableView.ReloadData();

            TableShadow.Hidden = TraitCollection.HorizontalSizeClass != UIUserInterfaceSizeClass.Regular;
        }
Ejemplo n.º 6
0
        private void prepareEmptyStateView()
        {
            emptyStateView.BackgroundColor = UIColor.Clear;
            emptyStateView.TranslatesAutoresizingMaskIntoConstraints = false;

            TimeEntriesLogTableView.AddSubview(emptyStateView);

            emptyStateView.WidthAnchor.ConstraintEqualTo(TimeEntriesLogTableView.WidthAnchor).Active                 = true;
            emptyStateView.HeightAnchor.ConstraintEqualTo(TimeEntriesLogTableView.HeightAnchor).Active               = true;
            emptyStateView.CenterYAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterYAnchor).Active             = true;
            emptyStateView.TopAnchor.ConstraintEqualTo(TimeEntriesLogTableView.TopAnchor, emptyViewTopMargin).Active = true;
        }
Ejemplo n.º 7
0
        private void updateTooltipPositions()
        {
            if (firstTimeEntry == null)
            {
                return;
            }

            var position = TimeEntriesLogTableView.ConvertRectToView(
                firstTimeEntry.Frame, TimeEntriesLogTableView.Superview);

            TapToEditBubbleViewTopConstraint.Constant = position.Bottom + tooltipOffset;
            SwipeLeftTopConstraint.Constant           = position.Y - SwipeLeftBubbleView.Frame.Height - tooltipOffset;
            SwipeRightTopConstraint.Constant          = position.Y - SwipeRightBubbleView.Frame.Height - tooltipOffset;
        }
Ejemplo n.º 8
0
        private void updateTooltipPositions()
        {
            if (TapToEditBubbleView.Hidden)
            {
                return;
            }
            if (firstTimeEntryCell == null)
            {
                return;
            }

            var position = TimeEntriesLogTableView.ConvertRectToView(
                firstTimeEntryCell.Frame, TimeEntriesLogTableView.Superview);

            TapToEditBubbleViewTopConstraint.Constant = position.Bottom + tooltipOffset;
        }
Ejemplo n.º 9
0
        //Spider is added in code, because IB doesn't allow adding subviews
        //to a UITableView and the spider needs to be a subview of the table
        //view so it reacts to pulling down to refresh
        private void prepareWelcomeBackViews()
        {
            // Welcome back view must be placed inside of the time entries
            // log table view below the spider so that it does not overlay
            // the spider at any time.
            WelcomeBackView.RemoveFromSuperview();
            TimeEntriesLogTableView.AddSubview(WelcomeBackView);
            NSLayoutConstraint.ActivateConstraints(new[]
            {
                WelcomeBackView.CenterXAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterXAnchor),
                WelcomeBackView.TopAnchor.ConstraintEqualTo(TimeEntriesLogTableView.TopAnchor, welcomeViewTopDistance),
                WelcomeBackView.LeadingAnchor.ConstraintEqualTo(TimeEntriesLogTableView.LeadingAnchor, welcomeViewSideMargin),
                WelcomeBackView.TrailingAnchor.ConstraintEqualTo(TimeEntriesLogTableView.TrailingAnchor, welcomeViewSideMargin)
            });

            var spiderHinge = new UIView();

            spiderHinge.Layer.CornerRadius = spiderHingeCornerRadius;
            spiderHinge.TranslatesAutoresizingMaskIntoConstraints = false;
            spiderHinge.BackgroundColor = Colors.Main.SpiderHinge.ToNativeColor();
            spiderContainerView.TranslatesAutoresizingMaskIntoConstraints = false;
            spiderBroView.TranslatesAutoresizingMaskIntoConstraints       = false;
            spiderContainerView.BackgroundColor = UIColor.Clear;

            spiderContainerView.AddSubview(spiderHinge);
            spiderContainerView.AddSubview(spiderBroView);
            TimeEntriesLogTableView.AddSubview(spiderContainerView);

            //Container constraints
            spiderContainerView.WidthAnchor.ConstraintEqualTo(TimeEntriesLogTableView.WidthAnchor).Active     = true;
            spiderContainerView.HeightAnchor.ConstraintEqualTo(TimeEntriesLogTableView.HeightAnchor).Active   = true;
            spiderContainerView.CenterYAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterYAnchor).Active = true;
            spiderContainerView.CenterXAnchor.ConstraintEqualTo(TimeEntriesLogTableView.CenterXAnchor).Active = true;

            //Hinge constraints
            spiderHinge.WidthAnchor.ConstraintEqualTo(spiderHingeWidth).Active                    = true;
            spiderHinge.HeightAnchor.ConstraintEqualTo(spiderHingeHeight).Active                  = true;
            spiderHinge.TopAnchor.ConstraintEqualTo(spiderContainerView.TopAnchor).Active         = true;
            spiderHinge.CenterXAnchor.ConstraintEqualTo(spiderContainerView.CenterXAnchor).Active = true;

            //Spider constraints
            spiderBroView.TopAnchor.ConstraintEqualTo(spiderContainerView.TopAnchor).Active         = true;
            spiderBroView.WidthAnchor.ConstraintEqualTo(spiderContainerView.WidthAnchor).Active     = true;
            spiderBroView.BottomAnchor.ConstraintEqualTo(spiderContainerView.BottomAnchor).Active   = true;
            spiderBroView.CenterXAnchor.ConstraintEqualTo(spiderContainerView.CenterXAnchor).Active = true;
        }
Ejemplo n.º 10
0
        public override void ViewDidLayoutSubviews()
        {
            base.ViewDidLayoutSubviews();

            TimeEntriesLogTableView.ContentInset = new UIEdgeInsets(-TimeEntriesLogViewSource.SpaceBetweenSections, 0,
                                                                    StartTimeEntryButton.Frame.Height, 0);
            TimeEntriesLogTableView.BringSubviewToFront(TimeEntriesLogTableView.TableHeaderView);

            if (TimeEntriesLogTableView.TableHeaderView != null)
            {
                var header = TimeEntriesLogTableView.TableHeaderView;
                var size   = header.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
                if (header.Frame.Size.Height != size.Height)
                {
                    var headerRect = new CGRect
                    {
                        X      = header.Frame.X,
                        Y      = header.Frame.Y,
                        Width  = header.Frame.Width,
                        Height = size.Height
                    };
                    header.Frame = headerRect;
                }
                TimeEntriesLogTableView.TableHeaderView = header;
                TimeEntriesLogTableView.SetNeedsLayout();
            }

            if (viewInitialized)
            {
                return;
            }

            viewInitialized = true;

            ViewModel.IsTimeEntryRunning
            .Where(visible => visible)
            .Subscribe(_ => showTimeEntryCard())
            .DisposedBy(disposeBag);

            ViewModel.IsTimeEntryRunning
            .Where(visible => !visible)
            .Subscribe(_ => hideTimeEntryCard())
            .DisposedBy(disposeBag);
        }
Ejemplo n.º 11
0
        public override void ViewDidLayoutSubviews()
        {
            base.ViewDidLayoutSubviews();

            if (TimeEntriesLogTableView.TableHeaderView != null)
            {
                var header = TimeEntriesLogTableView.TableHeaderView;
                var size   = header.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
                if (header.Frame.Size.Height != size.Height)
                {
                    var headerRect = new CGRect
                    {
                        X      = header.Frame.X,
                        Y      = header.Frame.Y,
                        Width  = header.Frame.Width,
                        Height = size.Height
                    };
                    header.Frame = headerRect;
                }
                TimeEntriesLogTableView.TableHeaderView = header;
                TimeEntriesLogTableView.SetNeedsLayout();
            }

            if (viewInitialized)
            {
                return;
            }

            viewInitialized = true;

            ViewModel.IsTimeEntryRunning
            .ObserveOn(SynchronizationContext.Current)
            .Where(visible => visible)
            .VoidSubscribe(showTimeEntryCard)
            .DisposedBy(disposeBag);

            ViewModel.IsTimeEntryRunning
            .ObserveOn(SynchronizationContext.Current)
            .Where(visible => !visible)
            .VoidSubscribe(hideTimeEntryCard)
            .DisposedBy(disposeBag);
        }
Ejemplo n.º 12
0
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            SwipeRightBubbleLabel.Text         = Resources.SwipeRightToContinue;
            SwipeLeftBubbleLabel.Text          = Resources.SwipeLeftToDelete;
            WelcomeBackLabel.Text              = Resources.LogEmptyStateTitle;
            WelcomeBackDescriptionLabel.Text   = Resources.LogEmptyStateText;
            CreatedFirstTimeEntryLabel.Text    = Resources.YouHaveCreatedYourFirstTimeEntry;
            TapToEditItLabel.Text              = Resources.TapToEditIt;
            StartTimerBubbleLabel.Text         = Resources.TapToStartTimer;
            TapToStopTimerLabel.Text           = Resources.TapToStopTimer;
            FeedbackSentSuccessTitleLabel.Text = Resources.DoneWithExclamationMark.ToUpper();
            FeedbackSentDescriptionLabel.Text  = Resources.ThankYouForTheFeedback;

            prepareViews();
            prepareOnboarding();
            setupTableViewHeader();

            tableViewSource = new TimeEntriesLogViewSource();

            TimeEntriesLogTableView.Source = tableViewSource;

            ViewModel.TimeEntries
            .Subscribe(TimeEntriesLogTableView.Rx().AnimateSections <MainLogSection, DaySummaryViewModel, LogItemViewModel, IMainLogKey>(tableViewSource))
            .DisposedBy(disposeBag);

            ViewModel.ShouldReloadTimeEntryLog
            .WithLatestFrom(ViewModel.TimeEntries, (_, timeEntries) => timeEntries)
            .Subscribe(TimeEntriesLogTableView.Rx().ReloadSections(tableViewSource))
            .DisposedBy(disposeBag);

            tableViewSource.ToggleGroupExpansion
            .Subscribe(ViewModel.TimeEntriesViewModel.ToggleGroupExpansion.Inputs)
            .DisposedBy(disposeBag);

            tableViewSource.FirstCell
            .Subscribe(f =>
            {
                onFirstTimeEntryChanged(f);
                firstTimeEntryCell = f;
            })
            .DisposedBy(DisposeBag);

            tableViewSource.Rx().Scrolled()
            .Subscribe(onTableScroll)
            .DisposedBy(DisposeBag);

            tableViewSource.ContinueTap
            .Select(item => timeEntryContinuation(item, false))
            .Subscribe(ViewModel.ContinueTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.SwipeToContinue
            .Select(item => timeEntryContinuation(item, true))
            .Subscribe(ViewModel.ContinueTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.SwipeToDelete
            .Select(logItem => logItem.RepresentedTimeEntriesIds)
            .Subscribe(ViewModel.TimeEntriesViewModel.DelayDeleteTimeEntries.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.Rx().ModelSelected()
            .Select(editEventInfo)
            .Subscribe(ViewModel.SelectTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            ViewModel.TimeEntriesViewModel.TimeEntriesPendingDeletion
            .Subscribe(toggleUndoDeletion)
            .DisposedBy(DisposeBag);

            tableViewSource.SwipeToContinue
            .Subscribe(_ => swipeRightStep.Dismiss())
            .DisposedBy(disposeBag);

            tableViewSource.SwipeToDelete
            .Subscribe(_ => swipeLeftStep.Dismiss())
            .DisposedBy(disposeBag);

            // Refresh Control
            var refreshControl = new RefreshControl(
                ViewModel.SyncProgressState,
                tableViewSource.Rx().Scrolled(),
                tableViewSource.IsDragging);

            refreshControl.Refresh
            .Subscribe(ViewModel.Refresh.Inputs)
            .DisposedBy(DisposeBag);
            TimeEntriesLogTableView.CustomRefreshControl = refreshControl;

            //Actions
            settingsButton.Rx().BindAction(ViewModel.OpenSettings).DisposedBy(DisposeBag);
            syncFailuresButton.Rx().BindAction(ViewModel.OpenSyncFailures).DisposedBy(DisposeBag);
            StopTimeEntryButton.Rx().BindAction(ViewModel.StopTimeEntry, _ => TimeEntryStopOrigin.Manual).DisposedBy(DisposeBag);

            StartTimeEntryButton.Rx().BindAction(ViewModel.StartTimeEntry, _ => true).DisposedBy(DisposeBag);
            StartTimeEntryButton.Rx().BindAction(ViewModel.StartTimeEntry, _ => false, ButtonEventType.LongPress).DisposedBy(DisposeBag);

            CurrentTimeEntryCard.Rx().Tap()
            .WithLatestFrom(ViewModel.CurrentRunningTimeEntry, (_, te) => te)
            .Where(te => te != null)
            .Select(te => (new[] { te.Id }, EditTimeEntryOrigin.RunningTimeEntryCard))
            .Subscribe(ViewModel.SelectTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            //Visibility
            var shouldWelcomeBack = ViewModel.ShouldShowWelcomeBack;

            ViewModel.ShouldShowEmptyState
            .Subscribe(visible => emptyStateView.Hidden = !visible)
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(WelcomeBackView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(spiderContainerView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(visible =>
            {
                if (visible)
                {
                    spiderBroView.Show();
                }
                else
                {
                    spiderBroView.Hide();
                }
            })
            .DisposedBy(DisposeBag);

            //Text
            ViewModel.CurrentRunningTimeEntry
            .Select(te => te?.Description)
            .Subscribe(CurrentTimeEntryDescriptionLabel.Rx().Text())
            .DisposedBy(DisposeBag);

            ViewModel.ElapsedTime
            .Subscribe(CurrentTimeEntryElapsedTimeLabel.Rx().Text())
            .DisposedBy(DisposeBag);

            var capHeight   = CurrentTimeEntryProjectTaskClientLabel.Font.CapHeight;
            var clientColor = Colors.Main.CurrentTimeEntryClientColor.ToNativeColor();

            ViewModel.CurrentRunningTimeEntry
            .Select(te => te?.ToFormattedTimeEntryString(capHeight, clientColor, shouldColorProject: true))
            .Subscribe(CurrentTimeEntryProjectTaskClientLabel.Rx().AttributedText())
            .DisposedBy(DisposeBag);

            //The start button
            var trackModeImage  = UIImage.FromBundle("playIcon");
            var manualModeImage = UIImage.FromBundle("manualIcon");

            ViewModel.IsInManualMode
            .Select(isInManualMode => isInManualMode ? manualModeImage : trackModeImage)
            .Subscribe(image => StartTimeEntryButton.SetImage(image, UIControlState.Normal))
            .DisposedBy(DisposeBag);

            //The sync failures button
            ViewModel.NumberOfSyncFailures
            .Select(numberOfSyncFailures => numberOfSyncFailures > 0)
            .Subscribe(syncFailuresButton.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            ViewModel.RatingViewModel.IsFeedbackSuccessViewShowing
            .Subscribe(SendFeedbackSuccessView.Rx().AnimatedIsVisible())
            .DisposedBy(DisposeBag);

            SendFeedbackSuccessView.Rx().Tap()
            .Subscribe(ViewModel.RatingViewModel.CloseFeedbackSuccessView)
            .DisposedBy(DisposeBag);

            ViewModel.ShouldShowRatingView
            .Subscribe(showHideRatingView)
            .DisposedBy(disposeBag);

            // Suggestion View
            suggestionsView.SuggestionTapped
            .Subscribe(ViewModel.SuggestionsViewModel.StartTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            ViewModel.SuggestionsViewModel.IsEmpty.Invert()
            .Subscribe(suggestionsView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            ViewModel.SuggestionsViewModel.Suggestions
            .ReemitWhen(traitCollectionSubject)
            .Subscribe(suggestionsView.OnSuggestions)
            .DisposedBy(DisposeBag);

            View.SetNeedsLayout();
            View.LayoutIfNeeded();

            NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidBecomeActiveNotification, onApplicationDidBecomeActive);
        }
Ejemplo n.º 13
0
 public void ScrollToTop()
 {
     TimeEntriesLogTableView.SetContentOffset(CGPoint.Empty, true);
 }
Ejemplo n.º 14
0
        void ReleaseDesignerOutlets()
        {
            if (CurrentTimeEntryCard != null)
            {
                CurrentTimeEntryCard.Dispose();
                CurrentTimeEntryCard = null;
            }

            if (CurrentTimeEntryDescriptionLabel != null)
            {
                CurrentTimeEntryDescriptionLabel.Dispose();
                CurrentTimeEntryDescriptionLabel = null;
            }

            if (CurrentTimeEntryElapsedTimeLabel != null)
            {
                CurrentTimeEntryElapsedTimeLabel.Dispose();
                CurrentTimeEntryElapsedTimeLabel = null;
            }

            if (CurrentTimeEntryProjectTaskClientLabel != null)
            {
                CurrentTimeEntryProjectTaskClientLabel.Dispose();
                CurrentTimeEntryProjectTaskClientLabel = null;
            }

            if (EditTimeEntryButton != null)
            {
                EditTimeEntryButton.Dispose();
                EditTimeEntryButton = null;
            }

            if (RunningEntryDescriptionFadeView != null)
            {
                RunningEntryDescriptionFadeView.Dispose();
                RunningEntryDescriptionFadeView = null;
            }

            if (StartTimeEntryButton != null)
            {
                StartTimeEntryButton.Dispose();
                StartTimeEntryButton = null;
            }

            if (StartTimeEntryOnboardingBubbleView != null)
            {
                StartTimeEntryOnboardingBubbleView.Dispose();
                StartTimeEntryOnboardingBubbleView = null;
            }

            if (StopTimeEntryButton != null)
            {
                StopTimeEntryButton.Dispose();
                StopTimeEntryButton = null;
            }

            if (TapToEditBubbleView != null)
            {
                TapToEditBubbleView.Dispose();
                TapToEditBubbleView = null;
            }

            if (TapToEditBubbleViewTopConstraint != null)
            {
                TapToEditBubbleViewTopConstraint.Dispose();
                TapToEditBubbleViewTopConstraint = null;
            }

            if (StopTimeEntryOnboardingBubbleView != null)
            {
                StopTimeEntryOnboardingBubbleView.Dispose();
                StopTimeEntryOnboardingBubbleView = null;
            }

            if (TimeEntriesLogTableView != null)
            {
                TimeEntriesLogTableView.Dispose();
                TimeEntriesLogTableView = null;
            }

            if (TopConstraint != null)
            {
                TopConstraint.Dispose();
                TopConstraint = null;
            }

            if (TopSeparator != null)
            {
                TopSeparator.Dispose();
                TopSeparator = null;
            }

            if (WelcomeBackView != null)
            {
                WelcomeBackView.Dispose();
                WelcomeBackView = null;
            }

            if (SendFeedbackSuccessView != null)
            {
                SendFeedbackSuccessView.Dispose();
                SendFeedbackSuccessView = null;
            }

            if (SwipeRightBubbleView != null)
            {
                SwipeRightBubbleView.Dispose();
                SwipeRightBubbleView = null;
            }

            if (SwipeLeftBubbleView != null)
            {
                SwipeLeftBubbleView.Dispose();
                SwipeLeftBubbleView = null;
            }

            if (SwipeLeftTopConstraint != null)
            {
                SwipeLeftTopConstraint.Dispose();
                SwipeLeftTopConstraint = null;
            }

            if (SwipeRightTopConstraint != null)
            {
                SwipeRightTopConstraint.Dispose();
                SwipeRightTopConstraint = null;
            }
        }
Ejemplo n.º 15
0
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            TableShadow.Layer.MasksToBounds = false;
            TableShadow.Layer.ShadowColor   = UIColor.Black.CGColor;
            TableShadow.Layer.ShadowOffset  = new CGSize(0, 0);
            TableShadow.Layer.ShadowOpacity = 0.1f;
            TableShadow.Layer.ShadowRadius  = 4;
            TableShadow.Hidden = TraitCollection.HorizontalSizeClass != UIUserInterfaceSizeClass.Regular;

            var separator = NavigationController.NavigationBar.InsertSeparator();

            separator.BackgroundColor = ColorAssets.OpaqueSeparator;

            WelcomeBackLabel.Text              = Resources.LogEmptyStateTitle;
            WelcomeBackDescriptionLabel.Text   = Resources.LogEmptyStateText;
            CreatedFirstTimeEntryLabel.Text    = Resources.YouHaveCreatedYourFirstTimeEntry;
            TapToEditItLabel.Text              = Resources.TapToEditIt;
            StartTimerBubbleLabel.Text         = Resources.TapToStartTimer;
            TapToStopTimerLabel.Text           = Resources.TapToStopTimer;
            FeedbackSentSuccessTitleLabel.Text = Resources.DoneWithExclamationMark.ToUpper();
            FeedbackSentDescriptionLabel.Text  = Resources.ThankYouForTheFeedback;

            StartTimeEntryButton.AccessibilityLabel = Resources.StartTimeEntry;
            StopTimeEntryButton.AccessibilityLabel  = Resources.StopCurrentlyRunningTimeEntry;

            tableViewSource = new TimeEntriesLogViewSource();

            prepareViews();
            prepareOnboarding();
            setupTableViewHeader();

            ViewModel.SwipeActionsEnabled
            .Subscribe(tableViewSource.SetSwipeActionsEnabled)
            .DisposedBy(disposeBag);

            TimeEntriesLogTableView.Source          = tableViewSource;
            TimeEntriesLogTableView.BackgroundColor = ColorAssets.TableBackground;

            ViewModel.TimeEntries
            .Subscribe(TimeEntriesLogTableView.Rx().AnimateSections <MainLogSection, DaySummaryViewModel, LogItemViewModel, IMainLogKey>(tableViewSource))
            .DisposedBy(disposeBag);

            ViewModel.ShouldReloadTimeEntryLog
            .WithLatestFrom(ViewModel.TimeEntries, (_, timeEntries) => timeEntries)
            .Subscribe(TimeEntriesLogTableView.Rx().ReloadSections(tableViewSource))
            .DisposedBy(disposeBag);

            tableViewSource.ToggleGroupExpansion
            .Subscribe(ViewModel.TimeEntriesViewModel.ToggleGroupExpansion.Inputs)
            .DisposedBy(disposeBag);

            tableViewSource.FirstCell
            .Subscribe(onFirstTimeEntryChanged)
            .DisposedBy(DisposeBag);

            tableViewSource.Rx().Scrolled()
            .Subscribe(onTableScroll)
            .DisposedBy(DisposeBag);

            tableViewSource.ContinueTap
            .Select(item => timeEntryContinuation(item, false))
            .Subscribe(ViewModel.ContinueTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.SwipeToContinue
            .Select(item => timeEntryContinuation(item, true))
            .Subscribe(ViewModel.ContinueTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.SwipeToDelete
            .Select(logItem => logItem.RepresentedTimeEntriesIds)
            .Subscribe(ViewModel.TimeEntriesViewModel.DelayDeleteTimeEntries.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.Rx().ModelSelected()
            .Select(editEventInfo)
            .Subscribe(ViewModel.SelectTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            tableViewSource.Rx().ItemsChanged()
            .Subscribe(updateTooltipPositions)
            .DisposedBy(DisposeBag);

            ViewModel.TimeEntriesViewModel.TimeEntriesPendingDeletion
            .Subscribe(toggleUndoDeletion)
            .DisposedBy(DisposeBag);

            // Refresh Control
            var refreshControl = new RefreshControl(
                ViewModel.SyncProgressState,
                tableViewSource.Rx().Scrolled(),
                tableViewSource.IsDragging);

            refreshControl.Refresh
            .Subscribe(ViewModel.Refresh.Inputs)
            .DisposedBy(DisposeBag);
            TimeEntriesLogTableView.CustomRefreshControl = refreshControl;

            //Actions
            settingsButton.Rx().BindAction(ViewModel.OpenSettings).DisposedBy(DisposeBag);
            syncFailuresButton.Rx().BindAction(ViewModel.OpenSyncFailures).DisposedBy(DisposeBag);
            StopTimeEntryButton.Rx().BindAction(ViewModel.StopTimeEntry, _ => TimeEntryStopOrigin.Manual).DisposedBy(DisposeBag);

            StartTimeEntryButton.Rx().BindAction(ViewModel.StartTimeEntry, _ => true).DisposedBy(DisposeBag);
            StartTimeEntryButton.Rx().BindAction(ViewModel.StartTimeEntry, _ => false, ButtonEventType.LongPress, useFeedback: true).DisposedBy(DisposeBag);

            CurrentTimeEntryCard.Rx().Tap()
            .WithLatestFrom(ViewModel.CurrentRunningTimeEntry, (_, te) => te)
            .Where(te => te != null)
            .Select(te => new EditTimeEntryInfo(EditTimeEntryOrigin.RunningTimeEntryCard, te.Id))
            .Subscribe(ViewModel.SelectTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            //Visibility
            var shouldWelcomeBack = ViewModel.ShouldShowWelcomeBack;

            ViewModel.ShouldShowEmptyState
            .Subscribe(visible => emptyStateView.Hidden = !visible)
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(WelcomeBackView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(spiderContainerView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            shouldWelcomeBack
            .Subscribe(visible =>
            {
                if (visible)
                {
                    spiderBroView.Show();
                }
                else
                {
                    spiderBroView.Hide();
                }
            })
            .DisposedBy(DisposeBag);

            //Text
            ViewModel.CurrentRunningTimeEntry
            .Select(te => te?.Description)
            .Subscribe(CurrentTimeEntryDescriptionLabel.Rx().Text())
            .DisposedBy(DisposeBag);

            ViewModel.ElapsedTime
            .Subscribe(CurrentTimeEntryElapsedTimeLabel.Rx().Text())
            .DisposedBy(DisposeBag);

            var capHeight   = CurrentTimeEntryProjectTaskClientLabel.Font.CapHeight;
            var clientColor = ColorAssets.Text3;

            ViewModel.CurrentRunningTimeEntry
            .Select(te => te?.ToFormattedTimeEntryString(capHeight, clientColor, shouldColorProject: true))
            .Subscribe(CurrentTimeEntryProjectTaskClientLabel.Rx().AttributedText())
            .DisposedBy(DisposeBag);

            //Accessibility
            CurrentTimeEntryCard.IsAccessibilityElementFocused
            .CombineLatest(ViewModel.CurrentRunningTimeEntry,
                           (_, runningEntry) => createAccessibilityLabelForRunningEntryCard(runningEntry))
            .Subscribe(CurrentTimeEntryCard.Rx().AccessibilityLabel())
            .DisposedBy(disposeBag);

            //The start button
            var trackModeImage  = UIImage.FromBundle("playIcon");
            var manualModeImage = UIImage.FromBundle("manualIcon");

            ViewModel.IsInManualMode
            .Select(isInManualMode => isInManualMode ? manualModeImage : trackModeImage)
            .Subscribe(image => StartTimeEntryButton.SetImage(image, UIControlState.Normal))
            .DisposedBy(DisposeBag);

            //The sync failures button
            ViewModel.NumberOfSyncFailures
            .Select(numberOfSyncFailures => numberOfSyncFailures > 0)
            .Subscribe(syncFailuresButton.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            ViewModel.RatingViewModel.IsFeedbackSuccessViewShowing
            .Subscribe(SendFeedbackSuccessView.Rx().AnimatedIsVisible())
            .DisposedBy(DisposeBag);

            SendFeedbackSuccessView.Rx().Tap()
            .Subscribe(ViewModel.RatingViewModel.CloseFeedbackSuccessView)
            .DisposedBy(DisposeBag);

            ViewModel.ShouldShowRatingView
            .Subscribe(showHideRatingView)
            .DisposedBy(disposeBag);

            // Suggestion View
            suggestionsView.SuggestionTapped
            .Subscribe(ViewModel.SuggestionsViewModel.StartTimeEntry.Inputs)
            .DisposedBy(DisposeBag);

            ViewModel.SuggestionsViewModel.IsEmpty.Invert()
            .Subscribe(suggestionsView.Rx().IsVisible())
            .DisposedBy(DisposeBag);

            ViewModel.SuggestionsViewModel.Suggestions
            .ReemitWhen(traitCollectionSubject)
            .Subscribe(suggestions =>
            {
                suggestionsView.OnSuggestions(suggestions);
                layoutTableHeader();
            })
            .DisposedBy(DisposeBag);

            // Intent Donation
            IosDependencyContainer.Instance.IntentDonationService.SetDefaultShortcutSuggestions();

            Observable.Merge(
                ViewModel.ContinueTimeEntry.Elements,
                ViewModel.SuggestionsViewModel.StartTimeEntry.Elements
                )
            .Subscribe(IosDependencyContainer.Instance.IntentDonationService.DonateStartTimeEntry)
            .DisposedBy(DisposeBag);

            ViewModel.StopTimeEntry.Elements
            .Subscribe(IosDependencyContainer.Instance.IntentDonationService.DonateStopCurrentTimeEntry)
            .DisposedBy(DisposeBag);

            View.SetNeedsLayout();
            View.LayoutIfNeeded();

            NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidBecomeActiveNotification, onApplicationDidBecomeActive);
        }
Ejemplo n.º 16
0
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            prepareViews();
            prepareOnboarding();
            setupTableViewHeader();

            var visibilityConverter       = new MvxVisibilityValueConverter();
            var projectTaskClientCombiner = new ProjectTaskClientValueCombiner(
                CurrentTimeEntryProjectTaskClientLabel.Font.CapHeight,
                Color.Main.CurrentTimeEntryClientColor.ToNativeColor(),
                true
                );
            var startTimeEntryButtonManualModeIconConverter = new BoolToConstantValueConverter <UIImage>(
                UIImage.FromBundle("manualIcon"),
                UIImage.FromBundle("playIcon")
                );
            var durationCombiner = new DurationValueCombiner();

            var bindingSet = this.CreateBindingSet <MainViewController, MainViewModel>();

            // Table view
            tableViewSource = new TimeEntriesLogViewSource(ViewModel.TimeEntries, TimeEntriesLogViewCell.Identifier);
            TimeEntriesLogTableView
            .Rx()
            .Bind(tableViewSource)
            .DisposedBy(disposeBag);

            this.Bind(tableViewSource.FirstCell, f =>
            {
                onFirstTimeEntryChanged(f);
                firstTimeEntryCell = f;
            });

            this.Bind(tableViewSource.ScrollOffset, onTableScroll);

            var continueTimeEntry = Observable.Merge(
                tableViewSource.ContinueTap,
                tableViewSource.SwipeToContinue
                );

            this.Bind(continueTimeEntry, ViewModel.ContinueTimeEntry);
            this.Bind(tableViewSource.SwipeToDelete, ViewModel.TimeEntriesViewModel.DelayDeleteTimeEntry);
            this.Bind(tableViewSource.ItemSelected, ViewModel.SelectTimeEntry);
            this.Bind(ViewModel.TimeEntriesViewModel.ShouldShowUndo, toggleUndoDeletion);

            tableViewSource.SwipeToContinue
            .VoidSubscribe(() =>
            {
                swipeRightStep.Dismiss();
            })
            .DisposedBy(disposeBag);

            tableViewSource.SwipeToDelete
            .VoidSubscribe(() =>
            {
                swipeLeftStep.Dismiss();
            })
            .DisposedBy(disposeBag);

            // Refresh Control
            var refreshControl = new RefreshControl(ViewModel.SyncProgressState, tableViewSource);

            this.Bind(refreshControl.Refresh, ViewModel.RefreshAction);
            TimeEntriesLogTableView.CustomRefreshControl = refreshControl;

            //Commands
            bindingSet.Bind(settingsButton).To(vm => vm.OpenSettingsCommand);
            bindingSet.Bind(StopTimeEntryButton).To(vm => vm.StopTimeEntryCommand);
            bindingSet.Bind(StartTimeEntryButton).To(vm => vm.StartTimeEntryCommand);
            bindingSet.Bind(EditTimeEntryButton).To(vm => vm.EditTimeEntryCommand);
            bindingSet.Bind(syncFailuresButton).To(vm => vm.OpenSyncFailuresCommand);

            bindingSet.Bind(CurrentTimeEntryCard)
            .For(v => v.BindTap())
            .To(vm => vm.EditTimeEntryCommand);

            bindingSet.Bind(suggestionsView)
            .For(v => v.SuggestionTappedCommad)
            .To(vm => vm.SuggestionsViewModel.StartTimeEntryCommand);

            bindingSet.Bind(StartTimeEntryButton)
            .For(v => v.BindLongPress())
            .To(vm => vm.AlternativeStartTimeEntryCommand);

            //Visibility
            var shouldWelcomeBack = ViewModel.ShouldShowWelcomeBack;

            this.Bind(ViewModel.ShouldShowEmptyState, visible => emptyStateView.Hidden = !visible);
            this.Bind(shouldWelcomeBack, WelcomeBackView.Rx().IsVisible());
            this.Bind(shouldWelcomeBack, spiderContainerView.Rx().IsVisible());
            this.Bind(shouldWelcomeBack, visible =>
            {
                if (visible)
                {
                    spiderBroView.Show();
                }
                else
                {
                    spiderBroView.Hide();
                }
            });

            //Text
            bindingSet.Bind(CurrentTimeEntryDescriptionLabel).To(vm => vm.CurrentTimeEntryDescription);

            bindingSet.Bind(CurrentTimeEntryElapsedTimeLabel)
            .ByCombining(durationCombiner,
                         vm => vm.CurrentTimeEntryElapsedTime,
                         vm => vm.CurrentTimeEntryElapsedTimeFormat);

            bindingSet.Bind(CurrentTimeEntryProjectTaskClientLabel)
            .For(v => v.AttributedText)
            .ByCombining(projectTaskClientCombiner,
                         v => v.CurrentTimeEntryProject,
                         v => v.CurrentTimeEntryTask,
                         v => v.CurrentTimeEntryClient,
                         v => v.CurrentTimeEntryProjectColor);

            //The start button
            bindingSet.Bind(StartTimeEntryButton)
            .For(v => v.BindImage())
            .To(vm => vm.IsInManualMode)
            .WithConversion(startTimeEntryButtonManualModeIconConverter);

            //The sync failures button
            bindingSet.Bind(syncFailuresButton)
            .For(v => v.BindVisibility())
            .To(vm => vm.NumberOfSyncFailures)
            .WithConversion(visibilityConverter);

            bindingSet.Apply();

            this.Bind(ViewModel.RatingViewModel.IsFeedbackSuccessViewShowing,
                      SendFeedbackSuccessView.Rx().AnimatedIsVisible());
            this.BindVoid(SendFeedbackSuccessView.Rx().Tap(), ViewModel.RatingViewModel.CloseFeedbackSuccessView);

            ViewModel.ShouldReloadTimeEntryLog
            .VoidSubscribe(reload)
            .DisposedBy(disposeBag);

            View.SetNeedsLayout();
            View.LayoutIfNeeded();

            NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidBecomeActiveNotification, onApplicationDidBecomeActive);
        }
Ejemplo n.º 17
0
 public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
 {
     base.TraitCollectionDidChange(previousTraitCollection);
     traitCollectionSubject.OnNext(Unit.Default);
     TimeEntriesLogTableView.ReloadData();
 }
        void ReleaseDesignerOutlets()
        {
            if (CurrentTimeEntryCard != null)
            {
                CurrentTimeEntryCard.Dispose();
                CurrentTimeEntryCard = null;
            }

            if (CreatedFirstTimeEntryLabel != null)
            {
                CreatedFirstTimeEntryLabel.Dispose();
                CreatedFirstTimeEntryLabel = null;
            }

            if (CurrentTimeEntryDescriptionLabel != null)
            {
                CurrentTimeEntryDescriptionLabel.Dispose();
                CurrentTimeEntryDescriptionLabel = null;
            }

            if (CurrentTimeEntryElapsedTimeLabel != null)
            {
                CurrentTimeEntryElapsedTimeLabel.Dispose();
                CurrentTimeEntryElapsedTimeLabel = null;
            }

            if (CurrentTimeEntryProjectTaskClientLabel != null)
            {
                CurrentTimeEntryProjectTaskClientLabel.Dispose();
                CurrentTimeEntryProjectTaskClientLabel = null;
            }

            if (FeedbackSentDescriptionLabel != null)
            {
                FeedbackSentDescriptionLabel.Dispose();
                FeedbackSentDescriptionLabel = null;
            }

            if (FeedbackSentSuccessTitleLabel != null)
            {
                FeedbackSentSuccessTitleLabel.Dispose();
                FeedbackSentSuccessTitleLabel = null;
            }

            if (RunningEntryDescriptionFadeView != null)
            {
                RunningEntryDescriptionFadeView.Dispose();
                RunningEntryDescriptionFadeView = null;
            }

            if (SendFeedbackSuccessView != null)
            {
                SendFeedbackSuccessView.Dispose();
                SendFeedbackSuccessView = null;
            }

            if (StartTimeEntryButton != null)
            {
                StartTimeEntryButton.Dispose();
                StartTimeEntryButton = null;
            }

            if (StartTimeEntryOnboardingBubbleView != null)
            {
                StartTimeEntryOnboardingBubbleView.Dispose();
                StartTimeEntryOnboardingBubbleView = null;
            }

            if (StartTimerBubbleLabel != null)
            {
                StartTimerBubbleLabel.Dispose();
                StartTimerBubbleLabel = null;
            }

            if (StopTimeEntryButton != null)
            {
                StopTimeEntryButton.Dispose();
                StopTimeEntryButton = null;
            }

            if (StopTimeEntryOnboardingBubbleView != null)
            {
                StopTimeEntryOnboardingBubbleView.Dispose();
                StopTimeEntryOnboardingBubbleView = null;
            }

            if (TapToEditBubbleView != null)
            {
                TapToEditBubbleView.Dispose();
                TapToEditBubbleView = null;
            }

            if (TapToEditBubbleViewTopConstraint != null)
            {
                TapToEditBubbleViewTopConstraint.Dispose();
                TapToEditBubbleViewTopConstraint = null;
            }

            if (TapToEditItLabel != null)
            {
                TapToEditItLabel.Dispose();
                TapToEditItLabel = null;
            }

            if (TapToStopTimerLabel != null)
            {
                TapToStopTimerLabel.Dispose();
                TapToStopTimerLabel = null;
            }

            if (TimeEntriesLogTableView != null)
            {
                TimeEntriesLogTableView.Dispose();
                TimeEntriesLogTableView = null;
            }

            if (TimeEntriesLogTableViewBottomToTopCurrentEntryConstraint != null)
            {
                TimeEntriesLogTableViewBottomToTopCurrentEntryConstraint.Dispose();
                TimeEntriesLogTableViewBottomToTopCurrentEntryConstraint = null;
            }

            if (TopConstraint != null)
            {
                TopConstraint.Dispose();
                TopConstraint = null;
            }

            if (TopSeparator != null)
            {
                TopSeparator.Dispose();
                TopSeparator = null;
            }

            if (WelcomeBackDescriptionLabel != null)
            {
                WelcomeBackDescriptionLabel.Dispose();
                WelcomeBackDescriptionLabel = null;
            }

            if (WelcomeBackLabel != null)
            {
                WelcomeBackLabel.Dispose();
                WelcomeBackLabel = null;
            }

            if (WelcomeBackView != null)
            {
                WelcomeBackView.Dispose();
                WelcomeBackView = null;
            }
        }
        void ReleaseDesignerOutlets()
        {
            if (TopConstraint != null)
            {
                TopConstraint.Dispose();
                TopConstraint = null;
            }

            if (CurrentTimeEntryCard != null)
            {
                CurrentTimeEntryCard.Dispose();
                CurrentTimeEntryCard = null;
            }

            if (CurrentTimeEntryDescriptionLabel != null)
            {
                CurrentTimeEntryDescriptionLabel.Dispose();
                CurrentTimeEntryDescriptionLabel = null;
            }

            if (CurrentTimeEntryElapsedTimeLabel != null)
            {
                CurrentTimeEntryElapsedTimeLabel.Dispose();
                CurrentTimeEntryElapsedTimeLabel = null;
            }

            if (CurrentTimeEntryProjectTaskClientLabel != null)
            {
                CurrentTimeEntryProjectTaskClientLabel.Dispose();
                CurrentTimeEntryProjectTaskClientLabel = null;
            }

            if (EditTimeEntryButton != null)
            {
                EditTimeEntryButton.Dispose();
                EditTimeEntryButton = null;
            }

            if (RunningEntryDescriptionFadeView != null)
            {
                RunningEntryDescriptionFadeView.Dispose();
                RunningEntryDescriptionFadeView = null;
            }

            if (StartTimeEntryButton != null)
            {
                StartTimeEntryButton.Dispose();
                StartTimeEntryButton = null;
            }

            if (StopTimeEntryButton != null)
            {
                StopTimeEntryButton.Dispose();
                StopTimeEntryButton = null;
            }

            if (TimeEntriesLogTableView != null)
            {
                TimeEntriesLogTableView.Dispose();
                TimeEntriesLogTableView = null;
            }

            if (TopSeparator != null)
            {
                TopSeparator.Dispose();
                TopSeparator = null;
            }

            if (WelcomeBackView != null)
            {
                WelcomeBackView.Dispose();
                WelcomeBackView = null;
            }
        }