Esempio n. 1
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);
        }
Esempio n. 2
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);
        }