summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore39
-rw-r--r--assignment-7/appointments.icl54
-rw-r--r--assignment-7/assignment-7.tex117
-rw-r--r--assignment-7/make.pngbin0 -> 63307 bytes
-rw-r--r--assignment-7/propose-avail.pngbin0 -> 79841 bytes
-rw-r--r--assignment-7/propose-manage.pngbin0 -> 90049 bytes
-rw-r--r--assignment-7/propose.pngbin0 -> 74644 bytes
-rw-r--r--assignment-7/show-list.pngbin0 -> 69840 bytes
-rw-r--r--assignment-7/show-svg.pngbin0 -> 83684 bytes
-rw-r--r--assignment-7/user-early.pngbin0 -> 62760 bytes
-rw-r--r--assignment-7/user-task.pngbin0 -> 62347 bytes
11 files changed, 186 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 3239f60..8fc9c95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+# Clean
Clean\ System\ Files/
a.out
*-www/
@@ -5,3 +6,41 @@ a.out
*-data/
assignment-5/skeleton5
assignment-6/multiplechoice
+
+# TeX
+*-blx.bib
+*.acn
+*.acr
+*.alg
+*.aux
+*.bbl
+*.bcf
+*.blg
+*.dvi
+*.ent
+*.fdb_latexmk
+*.fls
+*.fmt
+*.glg
+*.glo
+*.gls
+*.idx
+*.ilg
+*.ind
+*.ist
+*.lof
+*.log
+*.lot
+*.maf
+*.mtc
+*.mtc1
+*.nav
+*.out
+*.pdf
+*.run.xml
+*.snm
+*.swp
+*.synctex.gz
+*.toc
+_minted-*/
+*-tags.tex
diff --git a/assignment-7/appointments.icl b/assignment-7/appointments.icl
index 54b2d86..c65ed71 100644
--- a/assignment-7/appointments.icl
+++ b/assignment-7/appointments.icl
@@ -45,16 +45,19 @@ derive class iTask Appointment
derive JSEncode Appointment, User, Time, DateTime, Maybe
instance == Appointment where == a b = a === b
+// Some examples. Change the day fields (+7) if working later than 2017-11-18.
+// For these tasks, no user tasks are created (this is done in addAppointment).
+// They are just here to make it easier to develop the SVG calendar.
appointments :: Shared [Appointment]
appointments = sharedStore "appointments"
- [ {title="Advanced Programming", when={DateTime|year=2017,mon=11,day= 6,hour=10,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Information Retrieval", when={DateTime|year=2017,mon=11,day= 6,hour=15,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Cultural Contacts", when={DateTime|year=2017,mon=11,day= 7,hour=13,min= 0,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Historical Grammar", when={DateTime|year=2017,mon=11,day= 7,hour=15,min= 0,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Text Mining", when={DateTime|year=2017,mon=11,day= 8,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Testing Techniques", when={DateTime|year=2017,mon=11,day= 8,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Testing Techniques", when={DateTime|year=2017,mon=11,day=10,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
- , {title="Advanced Programming", when={DateTime|year=2017,mon=11,day=10,hour=10,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ [ {title="Advanced Programming", when={DateTime|year=2017,mon=11,day=13,hour=10,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Information Retrieval", when={DateTime|year=2017,mon=11,day=13,hour=15,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Cultural Contacts", when={DateTime|year=2017,mon=11,day=14,hour=13,min= 0,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Historical Grammar", when={DateTime|year=2017,mon=11,day=14,hour=15,min= 0,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Text Mining", when={DateTime|year=2017,mon=11,day=15,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Testing Techniques", when={DateTime|year=2017,mon=11,day=15,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Testing Techniques", when={DateTime|year=2017,mon=11,day=17,hour= 8,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
+ , {title="Advanced Programming", when={DateTime|year=2017,mon=11,day=17,hour=10,min=30,sec=0}, duration={Time|hour=2,min=0,sec=0}, owner=AuthenticatedUser "root" ["admin","manager"] (Just "Root user"), participants=[]}
]
belongsTo :: User Appointment -> Bool
@@ -85,8 +88,10 @@ where
finishTask :: Task ()
finishTask =
wait (Title "Wait for the start of this appointment") (\now -> now >= app.when) currentDateTime >>= \_ ->
- viewInformation (Title app.Appointment.title) [] "Click 'Done' to finish this task." >>*
- [OnAction (Action "Done") (always $ return ())]
+ viewSharedInformation (Title app.Appointment.title) [ViewAs (const "Click 'Done' to finish this task.")] currentDateTime >>*
+ [ OnAction (Action "Done") (always $ return ())
+ , OnValue (ifValue (\now -> now >= addTime app.duration app.when) (const $ return ()))
+ ]
attrs :: User -> TaskAttributes
attrs u = workerAttributes u
@@ -129,7 +134,8 @@ addProposedAppointment papp=:{appointment={Appointment|title}} =
where
chooseTask :: Int User -> Task (Int, 'M'.Map Int ProposedAppointment)
chooseTask idx user =
- allTasks [updateInformation (toString w) [] Maybe \\ (w,_) <- papp.startOptions] >>= \avail ->
+ viewSharedInformation (Title title) [ViewUsing (fromJust o 'M'.get idx o snd) proposalViewer] proposedAppointments
+ ||- allTasks [updateInformation (toString w) [] Maybe \\ (w,_) <- papp.startOptions] >>= \avail ->
upd (second $ 'M'.alter (fmap (setAvailability user avail)) idx) proposedAppointments
where
setAvailability :: User [Availability] ProposedAppointment -> ProposedAppointment
@@ -156,13 +162,19 @@ where
]
) $> ()
where
- proposalViewer :: Editor ProposedAppointment
- proposalViewer = comapEditorValue toTuple $ container4
- (withLabelAttr "Title" gEditor{|*|})
- (withLabelAttr "Duration" gEditor{|*|})
- (withLabelAttr "Participants" usersViewer)
- (withLabelAttr "Start options" grid)
+ schedule start = addAppointment {papp.appointment & when=start} >>| cancel
+ cancel =
+ allTasks (map (flip removeTask topLevelTasks) chooseTasks) >>|
+ upd (second $ 'M'.del idx) proposedAppointments
+
+ proposalViewer :: Editor ProposedAppointment
+ proposalViewer = comapEditorValue toTuple $ container4
+ (withLabelAttr "Title" gEditor{|*|})
+ (withLabelAttr "Duration" gEditor{|*|})
+ (withLabelAttr "Participants" usersViewer)
+ (withLabelAttr "Start options" grid)
+ where
toTuple :: ProposedAppointment -> (String, Time, [User], (ChoiceGrid, [Int]))
toTuple papp =
( papp.appointment.Appointment.title
@@ -179,12 +191,6 @@ where
)
)
- schedule start = addAppointment {papp.appointment & when=start} >>| cancel
-
- cancel =
- allTasks (map (flip removeTask topLevelTasks) chooseTasks) >>|
- upd (second $ 'M'.del idx) proposedAppointments
-
manageAttrs :: User -> TaskAttributes
manageAttrs u = workerAttributes u
[ ("title", "Manage " +++ title)
@@ -214,7 +220,7 @@ showAppointments =
appointments
where
editor = listEditor Nothing False False Nothing (bijectEditorValue toTuple fromTuple tupEdit)
- tupEdit = toolbar5 gEditor{|*|} gEditor{|*|} gEditor{|*|} userViewer usersViewer
+ tupEdit = listitem5 gEditor{|*|} gEditor{|*|} gEditor{|*|} userViewer usersViewer <<@ directionAttr Horizontal
userViewer = comapEditorValue toString gEditor{|*|}
toTuple app = (app.Appointment.title, app.when, app.duration, app.owner, app.participants)
fromTuple (t,w,d,o,p) = {title=t, when=w, duration=d, owner=o, participants=p}
diff --git a/assignment-7/assignment-7.tex b/assignment-7/assignment-7.tex
new file mode 100644
index 0000000..bb0dd17
--- /dev/null
+++ b/assignment-7/assignment-7.tex
@@ -0,0 +1,117 @@
+\documentclass[a4paper,english]{article}
+
+\title{Making Appointments\\\Large{Advanced Programming assignment 7}}
+\author{Camil Staps}
+
+\usepackage[margin=25mm,bottom=35mm]{geometry}
+\usepackage{graphicx}
+\usepackage[hidelinks]{hyperref}
+\usepackage{cleveref}
+\usepackage{csquotes}
+\usepackage{minted}
+
+\begin{document}
+
+\maketitle
+
+\noindent\emph{The screenshots included here are also in higher resolution included in the tarball.}
+
+\section{Showing appointments}
+There are two ways of showing appointments.
+All future appointments can be shown in a list (\cref{fig:show-list}).
+The appointments for the current week can be shown in an SVG calendar (\cref{fig:show-svg}).
+This can of course be extended to see other weeks as well, but it was really just to try out SVG.
+
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{show-list}
+ \caption{Showing future appointments as a list.\label{fig:show-list}}
+\end{figure}
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{show-svg}
+ \caption{Showing current week as an SVG calendar.\label{fig:show-svg}}
+\end{figure}
+
+\section{Making appointments}
+The default start time is the next whole hour.
+Other than that, this part is not much different than the screenshot in the assignment.
+It was not clear to me what the \enquote{scheduled appointments} field should do, so I omitted it.
+Users are not automatically participants in their own appointment which is the decision that gives most user freedom.
+See \cref{fig:make}.
+
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{make}
+ \caption{Making a new appointment.\label{fig:make}}
+\end{figure}
+
+\section{Proposing appointments}
+Proposed appointments are stored in a new type and stored in a separate share.
+
+\inputminted[firstline=114,lastline=117]{clean}{appointments.icl}
+\inputminted[firstline=102,lastline=105]{clean}{appointments.icl}
+
+The interface for creating an appointment proposal is straightforward (\cref{fig:propose}).
+Participants get tasks to indicate their availability (\enquote{Yes}, \enquote{No} or \enquote{Maybe}; \cref{fig:propose-avail}).
+The owner can always pick a start time or cancel the appointment (\cref{fig:propose-manage}).
+In both cases, the tasks to indicate availability are removed;
+ in the first case, tasks to finish the appointment are created (see \cref{sec:user-tasks}).
+
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{propose}
+ \caption{Proposing an appointment.\label{fig:propose}}
+\end{figure}
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{propose-avail}
+ \caption{Indicating availability for a proposed appointment.\label{fig:propose-avail}}
+\end{figure}
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{propose-manage}
+ \caption{Managing a proposed appointment.\label{fig:propose-manage}}
+\end{figure}
+
+\section{User tasks}
+\label{sec:user-tasks}
+User tasks are visible from the moment that they are created,
+ but can only be finished
+ (properly; they can always be deleted due to the usage of \texttt{loginAndManageWorkList})
+ after the start time (\cref{fig:user-early}).
+During the appointment, the user can finish a task by clicking \enquote{Done} (\cref{fig:user-task}).
+User tasks disappear after the end time.
+
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{user-early}
+ \caption{View when the user opens a task which does not start yet.\label{fig:user-early}}
+\end{figure}
+\begin{figure}[b]
+ \includegraphics[width=\textwidth]{user-task}
+ \caption{View to finish a task.\label{fig:user-task}}
+\end{figure}
+
+\section{Overall design \& feedback requests}
+I tried to separate model and view/controller.
+For instance, there are \texttt{addAppointment :: Appointment -> Task Appointment} and
+ \texttt{addProposedAppointment :: ProposedAppointment -> Task Int} which do not handle user interaction
+ but add a (proposed) appointment to the right share and start up related tasks.
+The relevant interaction tasks, \texttt{makeAppointment} and \texttt{proposeAppointment},
+ are just wrappers around the model tasks.
+I think something like this may be possible with lenses, i.e.,
+ change the addition function of the shares to add the user tasks.
+I have not tried to find this out, but would like some feedback on that.
+
+Also, you can see that to update start options users modify the map of availabilities of the proposed appointment.
+For this they also need to be able to find the appointment in the list of proposed appointment,
+ so the proposed appointments share is a tuple of an index for the next proposed appointment and a \texttt{Map Int ProposedAppointment} for the proposed apointments themselves.
+I expect that this can be done neater as well, possibly with lenses, so would like feedback on that as well.
+
+\section{Known bugs}
+This program is affected by bug \href{https://gitlab.science.ru.nl/clean-and-itasks/iTasks-SDK/issues/181}{\#181}.
+
+It was affected by \href{https://gitlab.science.ru.nl/clean-and-itasks/iTasks-SDK/issues/188}{\#188},
+ but this has been resolved. So, make sure to run with the latest version (this program has been tested with 2017-11-12).
+
+Some workarounds were needed for \href{https://gitlab.science.ru.nl/clean-and-itasks/iTasks-SDK/issues/190}{\#190}.
+Particularly, that bug made it difficult to do client-side date handling.
+This required me to give the \texttt{editor} and \texttt{draw} functions in \texttt{showCalendar} a \texttt{[Date]} argument,
+ thereby moving the \texttt{take 7 \$ iterate nextDay \$ previous Sunday date} to the server.
+I would find it preferable to move that computation to the \texttt{draw} function.
+
+\end{document}
diff --git a/assignment-7/make.png b/assignment-7/make.png
new file mode 100644
index 0000000..b30b4d6
--- /dev/null
+++ b/assignment-7/make.png
Binary files differ
diff --git a/assignment-7/propose-avail.png b/assignment-7/propose-avail.png
new file mode 100644
index 0000000..5e3ae80
--- /dev/null
+++ b/assignment-7/propose-avail.png
Binary files differ
diff --git a/assignment-7/propose-manage.png b/assignment-7/propose-manage.png
new file mode 100644
index 0000000..1bf3421
--- /dev/null
+++ b/assignment-7/propose-manage.png
Binary files differ
diff --git a/assignment-7/propose.png b/assignment-7/propose.png
new file mode 100644
index 0000000..7f1f58a
--- /dev/null
+++ b/assignment-7/propose.png
Binary files differ
diff --git a/assignment-7/show-list.png b/assignment-7/show-list.png
new file mode 100644
index 0000000..c6b93c9
--- /dev/null
+++ b/assignment-7/show-list.png
Binary files differ
diff --git a/assignment-7/show-svg.png b/assignment-7/show-svg.png
new file mode 100644
index 0000000..1514a0b
--- /dev/null
+++ b/assignment-7/show-svg.png
Binary files differ
diff --git a/assignment-7/user-early.png b/assignment-7/user-early.png
new file mode 100644
index 0000000..dfea658
--- /dev/null
+++ b/assignment-7/user-early.png
Binary files differ
diff --git a/assignment-7/user-task.png b/assignment-7/user-task.png
new file mode 100644
index 0000000..56c4c5b
--- /dev/null
+++ b/assignment-7/user-task.png
Binary files differ