From ee09760163d12d15ddaf70cb5164bff77c1c50d3 Mon Sep 17 00:00:00 2001 From: Erudition Date: Sun, 12 Nov 2023 04:02:39 -0600 Subject: [PATCH] Finish TimeTracker migration, add clock ticks --- elm-to-be-migrated/TimeTracker.elm | 299 ----------------------------- elm/Layouts/AppFrame.elm | 13 +- elm/Pages/TimeTracker.elm | 24 ++- elm/Shared.elm | 5 +- elm/Shared/Msg.elm | 2 + 5 files changed, 33 insertions(+), 310 deletions(-) delete mode 100644 elm-to-be-migrated/TimeTracker.elm diff --git a/elm-to-be-migrated/TimeTracker.elm b/elm-to-be-migrated/TimeTracker.elm deleted file mode 100644 index 9303f82e..00000000 --- a/elm-to-be-migrated/TimeTracker.elm +++ /dev/null @@ -1,299 +0,0 @@ -module TimeTracker exposing (Msg(..), ViewState(..), defaultView, routeView, update, urlTriggers, view) - -import Activity.Activity as Activity exposing (..) -import Activity.HistorySession as Timeline exposing (HistorySession, Timeline) -import Activity.Template -import Browser -import Browser.Dom -import Css exposing (..) -import Date -import Dict -import External.Commands as Commands exposing (..) -import External.Tasker as Tasker -import Helpers exposing (..) -import Html.Styled exposing (..) -import Html.Styled.Attributes exposing (..) -import Html.Styled.Events exposing (..) -import Html.Styled.Keyed as Keyed -import Html.Styled.Lazy exposing (..) -import ID -import Incubator.IntDict.Extra as IntDict -import IntDict -import Json.Decode as OldDecode -import Json.Decode.Exploration as Decode -import Json.Decode.Exploration.Pipeline as Pipeline exposing (..) -import Json.Encode as Encode exposing (..) -import Json.Encode.Extra as Encode2 exposing (..) -import Profile exposing (..) -import Refocus -import Replicated.Change as Change exposing (ChangeSet) -import Replicated.Reducer.RepList as RepList exposing (RepList) -import OldShared.Model exposing (..) -import SmartTime.Duration as Duration exposing (..) -import SmartTime.Human.Clock as Clock exposing (TimeOfDay) -import SmartTime.Human.Duration as HumanDuration exposing (..) -import SmartTime.Human.Moment as HumanMoment -import SmartTime.Moment as Moment exposing (Moment) -import SmartTime.Period as Period exposing (Period) -import Task as Job -import Task.Layers -import Time -import TimeTrackable exposing (TimeTrackable) -import Url.Parser as P exposing ((), (), Parser, fragment, int, map, oneOf, s, string) -import Url.Parser.Query as PQ -import VirtualDom -import VitePluginHelper - - - --- MM MM OOOOO DDDDD EEEEEEE LL --- MMM MMM OO OO DD DD EE LL --- MM MM MM OO OO DD DD EEEEE LL --- MM MM OO OO DD DD EE LL --- MM MM OOOO0 DDDDDD EEEEEEE LLLLLLL - - -type ViewState - = Normal - - - --- ::: ::: ::::::::::: :::::::::: ::: ::: --- :+: :+: :+: :+: :+: :+: --- +:+ +:+ +:+ +:+ +:+ +:+ --- +#+ +:+ +#+ +#++:++# +#+ +:+ +#+ --- +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ --- #+#+#+# #+# #+# #+#+# #+#+# --- ### ########### ########## ### ### - - -routeView : Parser (ViewState -> a) a -routeView = - P.map Normal (P.s "timetracker") - - -defaultView : ViewState -defaultView = - Normal - - -view : ViewState -> Profile -> Shared -> Html Msg -view state app env = - case state of - Normal -> - div - [] - [ section - [ class "activity-screen" ] - [ lazy2 viewActivities ( env.time, env.timeZone ) app - ] - , section [ css [ opacity (num 0.1) ] ] - [ text "Quite Ambitious." - ] - ] - - -viewActivities : ( Moment, HumanMoment.Zone ) -> Profile -> Html Msg -viewActivities ( time, timeZone ) app = - section - [ class "main" ] - [ ul [ class "activity-list" ] <| - List.map (viewActivity app ( time, timeZone )) (Activity.allUnhidden app.activities) - ] - - - --- VIEW INDIVIDUAL ENTRIES --- viewKeyedActivity : Profile -> Shared -> Activity -> ( String, Html Msg ) --- viewKeyedActivity app env activity = --- let --- key = --- Activity.getName activity ++ active --- --- active = --- if currentActivityID app.timeline == activity.id then --- String.fromInt <| totalLive env.time app.timeline activity.id --- --- else --- "" --- in --- ( key, viewActivity app env activity ) - - -viewActivity : Profile -> ( Moment, HumanMoment.Zone ) -> Activity -> Html Msg -viewActivity app ( time, timeZone ) activity = - let - describePeriod sesh = - Timeline.inHoursMinutes (Period.length sesh) ++ "\n" - - filterPeriod = - Period.between Moment.zero time - - trackingFlipID = - if Profile.currentActivityID app == Activity.getID activity then - attribute "data-flip-key" "current" - - else - class "not-current" - in - li - [ class "activity" ] - [ button - [ class "activity-button" - , classList [ ( "current", Profile.currentActivityID app == Activity.getID activity ) ] - , onClick (StartTracking (Activity.getID activity)) - , trackingFlipID - , title <| List.foldl (++) "" (List.map describePeriod (Timeline.periodsOfActivity filterPeriod (RepList.listValues app.timeline) (Activity.getID activity))) - ] - [ viewIcon (Activity.getIcon activity) - , div [] - [ text (writeActivityUsage app ( time, timeZone ) activity) - ] - , div [] - [ text (writeActivityToday app ( time, timeZone ) activity) - ] - , label - [] - [ text (Activity.getName activity) - ] - ] - ] - - -writeTime : Shared -> String -writeTime env = - let - nowClock = - HumanMoment.extractTime env.timeZone env.time - in - String.fromInt (Clock.hour nowClock) ++ ":" ++ String.fromInt (Clock.minute nowClock) - - -viewIcon : Activity.Icon -> Html Msg -viewIcon getIcon = - case getIcon of - File svgPath -> - img - [ class "activity-icon" - , src ("/media/icons/" ++ svgPath) - , css [ Css.float left ] - ] - [] - - Ion -> - text "" - - Other -> - text "" - - Emoji singleEmoji -> - text singleEmoji - - -writeActivityUsage : Profile -> ( Moment, HumanMoment.Zone ) -> Activity -> String -writeActivityUsage app ( time, timeZone ) activity = - let - maxTimeDenominator = - Tuple.second (Activity.getMaxTimePortion activity) - - lastPeriod = - Period.fromEnd time maxTimeDenominator - - total = - Timeline.activityTotalDuration lastPeriod (RepList.listValues app.timeline) (Activity.getID activity) - - totalMinutes = - Duration.inMinutesRounded total - in - if inMs total > 0 then - String.fromInt totalMinutes ++ "/" ++ String.fromInt (inMinutesRounded maxTimeDenominator) ++ "m" - - else - "" - - -writeActivityToday : Profile -> ( Moment, HumanMoment.Zone ) -> Activity -> String -writeActivityToday app ( time, timeZone ) activity = - Timeline.inHoursMinutes (Timeline.justTodayTotal (RepList.listValues app.timeline) ( time, timeZone ) (Activity.getID activity)) - - -exportActivityViewModel : Profile -> ( Moment, HumanMoment.Zone ) -> Encode.Value -exportActivityViewModel appData ( time, timeZone ) = - let - encodeActivityVM activity = - Encode.object - [ ( "name", Encode.string <| Activity.getName activity ) - , ( "excusedUsage", Encode.string <| writeActivityUsage appData ( time, timeZone ) activity ) - , ( "totalToday", Encode.string <| writeActivityUsage appData ( time, timeZone ) activity ) - ] - in - Encode.list encodeActivityVM <| - List.filter Activity.isShowing <| - Activity.allUnhidden appData.activities - - - --- _ _ ______ ______ ___ _____ _____ --- | | | || ___ \| _ \ / _ \ |_ _|| ___| --- | | | || |_/ /| | | |/ /_\ \ | | | |__ --- | | | || __/ | | | || _ | | | | __| --- | |_| || | | |/ / | | | | | | | |___ --- \___/ \_| |___/ \_| |_/ \_/ \____/ - - -type Msg - = NoOp - | StartTracking ActivityID - | ExportVM - - -update : Msg -> ViewState -> Profile -> ( Moment, HumanMoment.Zone ) -> ( Change.Frame, ViewState, Cmd Msg ) -update msg state profile ( time, timeZone ) = - case msg of - NoOp -> - ( Change.emptyFrame - , state - , Cmd.none - ) - - StartTracking activityId -> - let - projectLayers = - Task.Layers.buildLayerDatabase profile.projects - - newTrackable = - TimeTrackable.TrackedActivityID activityId - - ( changes, cmds ) = - Refocus.switchActivity newTrackable profile projectLayers ( time, timeZone ) - in - ( Change.saveChanges "Started tracking" changes - , state - , Cmd.batch - [ cmds - - -- , Tasker.variableOut ( "activities", Encode.encode 0 <| exportActivityViewModel updatedApp env ) - ] - ) - - ExportVM -> - ( Change.emptyFrame - , state - , Tasker.variableOut ( "activities", Encode.encode 0 <| exportActivityViewModel profile ( time, timeZone ) ) - ) - - -urlTriggers : Profile -> List ( String, Dict.Dict String Msg ) -urlTriggers app = - let - activitiesWithNames = - List.concat <| List.map entriesPerActivity (Activity.allUnhidden app.activities) - - entriesPerActivity activity = - List.map (\nm -> ( nm, StartTracking (Activity.getID activity) )) (Activity.getNames activity) - ++ List.map (\nm -> ( String.toLower nm, StartTracking (Activity.getID activity) )) (Activity.getNames activity) - in - [ ( "start", Dict.fromList activitiesWithNames ) - , ( "stop", Dict.fromList [ ( "stop", StartTracking Activity.unknown ) ] ) - , ( "export", Dict.fromList [ ( "all", ExportVM ) ] ) - ] diff --git a/elm/Layouts/AppFrame.elm b/elm/Layouts/AppFrame.elm index 5c667885..709bd6c9 100644 --- a/elm/Layouts/AppFrame.elm +++ b/elm/Layouts/AppFrame.elm @@ -55,6 +55,7 @@ import Replicated.Reducer.RepList as RepList exposing (RepList) import Route exposing (Route) import Route.Path import Shared +import Shared.Model import Shared.Msg exposing (..) import Shared.PopupType as PopupType import SmartTime.Duration as Duration @@ -84,7 +85,7 @@ layout props shared route = { init = init , update = update , view = view shared route - , subscriptions = subscriptions + , subscriptions = subscriptions shared } @@ -113,7 +114,8 @@ init _ = type Msg - = JustRunEffects (List (Effect Shared.Msg)) + = NoOp + | JustRunEffects (List (Effect Shared.Msg)) | EffectsAndLogError (List (Effect Shared.Msg)) String | SendSharedMsg Shared.Msg | AskAModel @@ -123,6 +125,9 @@ type Msg update : Msg -> Model -> ( Model, Effect Msg ) update msg model = case msg of + NoOp -> + ( model, Effect.none ) + JustRunEffects effects -> ( model , Effect.batch effects @@ -177,8 +182,8 @@ update msg model = ) -subscriptions : Model -> Sub Msg -subscriptions model = +subscriptions : Shared.Model.Model -> Model -> Sub Msg +subscriptions shared model = Sub.none diff --git a/elm/Pages/TimeTracker.elm b/elm/Pages/TimeTracker.elm index 1fd4c22e..0a48baaa 100644 --- a/elm/Pages/TimeTracker.elm +++ b/elm/Pages/TimeTracker.elm @@ -53,7 +53,7 @@ import VitePluginHelper page : Shared.Model -> Route () -> Page Model Msg page shared route = Page.new - { init = init + { init = init route , update = update shared , subscriptions = subscriptions , view = view shared route @@ -77,13 +77,28 @@ type alias Model = {} -init : () -> ( Model, Effect Msg ) -init () = +init : Route () -> () -> ( Model, Effect Msg ) +init route () = ( {} , Effect.none ) +urlTriggers : Profile -> List ( String, Dict.Dict String Msg ) +urlTriggers app = + let + activitiesWithNames = + List.concat <| List.map entriesPerActivity (Activity.allUnhidden app.activities) + + entriesPerActivity activity = + List.map (\nm -> ( nm, StartTracking (Activity.getID activity) )) (Activity.getNames activity) + ++ List.map (\nm -> ( String.toLower nm, StartTracking (Activity.getID activity) )) (Activity.getNames activity) + in + [ ( "start", Dict.fromList activitiesWithNames ) + , ( "stop", Dict.fromList [ ( "stop", StartTracking Activity.unknown ) ] ) + ] + + -- UPDATE @@ -138,9 +153,6 @@ view shared route model = [ class "activity-screen" ] [ lazy2 viewActivities ( shared.time, shared.timeZone ) shared.replica ] - , section [ css [ opacity (num 0.1) ] ] - [ text "Quite Ambitious." - ] ] } diff --git a/elm/Shared.elm b/elm/Shared.elm index ab3dcfa9..2c5f7dc5 100644 --- a/elm/Shared.elm +++ b/elm/Shared.elm @@ -119,6 +119,9 @@ update route msg shared = , Effect.none ) + Tick newTime -> + ( { shared | time = newTime }, Effect.none ) + ReplicatorUpdate replicatorMsg -> let { newReplicator, newReplica, cmd } = @@ -256,7 +259,7 @@ subscriptions route model = visibleOnlySubscriptions = if model.windowVisibility == Browser.Events.Visible then Sub.batch <| - [ HumanMoment.everyMinuteOnTheMinute model.time (\_ -> NoUpdate) + [ HumanMoment.everySecondOnTheSecond model.time Tick , Browser.Events.onResize (\width height -> ViewportResized width height) ] diff --git a/elm/Shared/Msg.elm b/elm/Shared/Msg.elm index b9984f73..bec01606 100644 --- a/elm/Shared/Msg.elm +++ b/elm/Shared/Msg.elm @@ -10,6 +10,7 @@ import NativeScript.Notification as Notif import Replicated.Change as Change import SmartTime.Human.Duration exposing (HumanDuration(..)) import SmartTime.Human.Moment exposing (Zone) +import SmartTime.Moment exposing (Moment) import TaskPort @@ -18,6 +19,7 @@ Naming Convention: Use "what happened" phrasing, not "action to take" (verb) phr -} type Msg = NoUpdate + | Tick Moment | ReplicatorUpdate Components.Replicator.Msg --| RunEffects (List (Effect.Effect Msg)) | WantsLogCleared