diff --git a/schedule/src/Decoders.elm b/schedule/src/Decoders.elm index 44d469ac..837ecdf6 100644 --- a/schedule/src/Decoders.elm +++ b/schedule/src/Decoders.elm @@ -57,8 +57,8 @@ eventDecoder = |> required "slug" string |> required "abstract" string |> required "speaker_slugs" (list string) - |> required "video_recording" bool - |> optional "video_url" string "" + |> required "video_state" string + |> optional "video_url" (nullable string) Nothing |> required "event_type" string @@ -89,8 +89,8 @@ eventInstanceDecoder = |> required "timeslots" float |> required "location" string |> required "location_icon" string - |> required "video_recording" bool - |> optional "video_url" string "" + |> required "video_state" string + |> optional "video_url" (nullable string) Nothing |> optional "is_favorited" (nullable bool) Nothing diff --git a/schedule/src/Models.elm b/schedule/src/Models.elm index 53be6e49..3c23cac1 100644 --- a/schedule/src/Models.elm +++ b/schedule/src/Models.elm @@ -66,7 +66,9 @@ type alias Filter = type alias VideoRecordingFilter = - { name : String, slug : String, filter : EventInstance -> Bool } + { name : String + , slug : String + } type alias Day = @@ -99,8 +101,8 @@ type alias EventInstance = , timeslots : Float , location : String , locationIcon : String - , videoRecording : Bool - , videoUrl : String + , videoState : String + , videoUrl : Maybe String , isFavorited : Maybe Bool } @@ -110,8 +112,8 @@ type alias Event = , slug : EventSlug , abstract : String , speakerSlugs : List SpeakerSlug - , videoRecording : Bool - , videoUrl : String + , videoState : String + , videoUrl : Maybe String , eventType : String } diff --git a/schedule/src/Views/EventDetail.elm b/schedule/src/Views/EventDetail.elm index aae9f710..47e67005 100644 --- a/schedule/src/Views/EventDetail.elm +++ b/schedule/src/Views/EventDetail.elm @@ -100,11 +100,11 @@ eventDetailSidebar event model = let videoRecordingLink = case event.videoUrl of - "" -> + Nothing -> [] - _ -> - [ a [ href event.videoUrl, classList [ ( "btn", True ), ( "btn-success", True ) ] ] + Just url -> + [ a [ href url, classList [ ( "btn", True ), ( "btn-success", True ) ] ] [ i [ classList [ ( "fa", True ), ( "fa-film", True ) ] ] [] , text " Watch recording here!" ] @@ -134,20 +134,30 @@ eventDetailSidebar event model = eventMetaDataSidebar : Event -> Html Msg eventMetaDataSidebar event = let - videoRecording = - case event.videoRecording of - True -> - "Yes" + ( showVideoRecoring, videoRecording ) = + case event.videoState of + "to-be-recorded" -> + ( True, "Yes" ) - False -> - "No" + "not-to-be-recorded" -> + ( True, "No" ) + + _ -> + ( False, "" ) in div [] [ h4 [] [ text "Metadata" ] , ul [] - [ li [] [ strong [] [ text "Type: " ], text event.eventType ] - , li [] [ strong [] [ text "Recording: " ], text videoRecording ] - ] + ([ li [] [ strong [] [ text "Type: " ], text event.eventType ] + ] + ++ (case showVideoRecoring of + True -> + [ li [] [ strong [] [ text "Recording: " ], text videoRecording ] ] + + False -> + [] + ) + ) ] diff --git a/schedule/src/Views/FilterView.elm b/schedule/src/Views/FilterView.elm index a6e4700d..3cfc1686 100644 --- a/schedule/src/Views/FilterView.elm +++ b/schedule/src/Views/FilterView.elm @@ -3,7 +3,7 @@ module Views.FilterView exposing (filterSidebar, applyFilters, parseFilterFromQu -- Local modules import Messages exposing (Msg(..)) -import Models exposing (Model, EventInstance, Filter, Day, FilterQuery, Route(OverviewFilteredRoute), VideoRecordingFilter) +import Models exposing (Model, EventInstance, Filter, Day, FilterQuery, Route(OverviewFilteredRoute), VideoRecordingFilter, EventType, EventLocation) import Routing exposing (routeToString) @@ -14,7 +14,7 @@ import Regex -- External modules -import Html exposing (Html, text, div, ul, li, span, i, h4) +import Html exposing (Html, text, div, ul, li, span, i, h4, small) import Html.Attributes exposing (class, classList) import Html.Events exposing (onClick) import Date.Extra exposing (Interval(..), equalBy) @@ -23,29 +23,22 @@ import Date.Extra exposing (Interval(..), equalBy) applyFilters : Day -> Model -> List EventInstance applyFilters day model = let - types = - List.map (\eventType -> eventType.slug) - (if List.isEmpty model.filter.eventTypes then - model.eventTypes + slugs default filters = + List.map .slug + (if List.isEmpty filters then + default else - model.filter.eventTypes + filters ) + types = + slugs model.eventTypes model.filter.eventTypes + locations = - List.map (\eventLocation -> eventLocation.slug) - (if List.isEmpty model.filter.eventLocations then - model.eventLocations - else - model.filter.eventLocations - ) + slugs model.eventLocations model.filter.eventLocations videoFilters = - List.map (\filter -> filter.filter) - (if List.isEmpty model.filter.videoRecording then - videoRecordingFilters - else - model.filter.videoRecording - ) + slugs videoRecordingFilters model.filter.videoRecording filteredEventInstances = List.filter @@ -54,7 +47,7 @@ applyFilters day model = && (Date.Extra.equalBy Date.Extra.Day eventInstance.from day.date) && List.member eventInstance.location locations && List.member eventInstance.eventType types - && applyVideoRecordingFilters videoFilters eventInstance + && List.member eventInstance.videoState videoFilters ) model.eventInstances in @@ -74,70 +67,84 @@ filterSidebar model = ] [ h4 [] [ text "Filter" ] , div [ class "form-group" ] - [ filterView "Type" model.eventTypes model.filter.eventTypes ToggleEventTypeFilter - , filterView "Location" model.eventLocations model.filter.eventLocations ToggleEventLocationFilter - , filterView "Video" videoRecordingFilters model.filter.videoRecording ToggleVideoRecordingFilter + [ filterView + "Type" + model.eventTypes + model.filter.eventTypes + ToggleEventTypeFilter + model.eventInstances + .eventType + , filterView + "Location" + model.eventLocations + model.filter.eventLocations + ToggleEventLocationFilter + model.eventInstances + .location + , filterView + "Video" + videoRecordingFilters + model.filter.videoRecording + ToggleVideoRecordingFilter + model.eventInstances + .videoState ] ] -notRecordedFilter : EventInstance -> Bool -notRecordedFilter eventInstance = - eventInstance.videoRecording == False - - -recordedFilter : EventInstance -> Bool -recordedFilter eventInstance = - eventInstance.videoRecording == True - - -hasRecordingFilter : EventInstance -> Bool -hasRecordingFilter eventInstance = - eventInstance.videoUrl /= "" - - videoRecordingFilters : List VideoRecordingFilter videoRecordingFilters = - [ { name = "Will not be recorded", slug = "not-to-be-recorded", filter = notRecordedFilter } - , { name = "Will recorded", slug = "to-be-recorded", filter = recordedFilter } - , { name = "Has recording", slug = "has-recording", filter = hasRecordingFilter } + [ { name = "Will not be recorded", slug = "not-to-be-recorded" } + , { name = "Will recorded", slug = "to-be-recorded" } + , { name = "Has recording", slug = "has-recording" } ] -applyVideoRecordingFilters : List (EventInstance -> Bool) -> EventInstance -> Bool -applyVideoRecordingFilters filters eventInstance = - let - results = - List.map (\filter -> filter eventInstance) filters - in - List.member True results - - filterView : String - -> List { a | name : String } - -> List { a | name : String } - -> ({ a | name : String } -> Msg) + -> List { a | name : String, slug : String } + -> List { a | name : String, slug : String } + -> ({ a | name : String, slug : String } -> Msg) + -> List EventInstance + -> (EventInstance -> String) -> Html Msg -filterView name possibleFilters currentFilters action = +filterView name possibleFilters currentFilters action eventInstances slugLike = div [] [ text (name ++ ":") - , ul [] (List.map (\filter -> filterChoiceView filter currentFilters action) possibleFilters) + , ul [] + (possibleFilters + |> List.map + (\filter -> + filterChoiceView + filter + currentFilters + action + eventInstances + slugLike + ) + ) ] filterChoiceView : - { a | name : String } - -> List { a | name : String } - -> ({ a | name : String } -> Msg) + { a | name : String, slug : String } + -> List { a | name : String, slug : String } + -> ({ a | name : String, slug : String } -> Msg) + -> List EventInstance + -> (EventInstance -> String) -> Html Msg -filterChoiceView filter currentFilters action = +filterChoiceView filter currentFilters action eventInstances slugLike = let active = List.member filter currentFilters notActive = not active + + eventInstanceCount = + eventInstances + |> List.filter (\eventInstance -> slugLike eventInstance == filter.slug) + |> List.length in li [] [ div @@ -151,6 +158,7 @@ filterChoiceView filter currentFilters action = [ span [] [ i [ classList [ ( "fa", True ), ( "fa-minus", active ), ( "fa-plus", notActive ) ] ] [] , text (" " ++ filter.name) + , small [] [ text <| " (" ++ (toString eventInstanceCount) ++ ")" ] ] ] ] diff --git a/schedule/src/Views/ScheduleOverview.elm b/schedule/src/Views/ScheduleOverview.elm index e99a55c7..c1d7206b 100644 --- a/schedule/src/Views/ScheduleOverview.elm +++ b/schedule/src/Views/ScheduleOverview.elm @@ -77,12 +77,21 @@ dayEventInstanceIcons : EventInstance -> List (Html Msg) dayEventInstanceIcons eventInstance = let videoIcon = - if eventInstance.videoUrl /= "" then - [ i [ classList [ ( "fa", True ), ( "fa-film", True ), ( "pull-right", True ) ] ] [] ] - else if eventInstance.videoRecording then - [ i [ classList [ ( "fa", True ), ( "fa-video-camera", True ), ( "pull-right", True ) ] ] [] ] - else - [] + case eventInstance.videoState of + "has-recording" -> + [ i + [ classList [ ( "fa", True ), ( "fa-film", True ), ( "pull-right", True ) ] ] + [] + ] + + "to-be-recorded" -> + [ i + [ classList [ ( "fa", True ), ( "fa-video-camera", True ), ( "pull-right", True ) ] ] + [] + ] + + _ -> + [] in [ i [ classList [ ( "fa", True ), ( "fa-" ++ eventInstance.locationIcon, True ), ( "pull-right", True ) ] ] [] ] diff --git a/src/program/models.py b/src/program/models.py index b5e8187b..1dc7c270 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -439,12 +439,18 @@ class Event(CampRelatedModel): speaker.slug for speaker in self.speakers.all() ], - 'video_recording': self.video_recording, 'event_type': self.event_type.name, } if self.video_url: + video_state = 'has-recording' data['video_url'] = self.video_url + elif self.video_recording: + video_state = 'to-be-recorded' + elif not self.video_recording: + video_state = 'not-to-be-recorded' + + data['video_state'] = video_state return data @@ -525,11 +531,17 @@ class EventInstance(CampRelatedModel): 'location': self.location.slug, 'location_icon': self.location.icon, 'timeslots': self.timeslots, - 'video_recording': self.event.video_recording, } if self.event.video_url: + video_state = 'has-recording' data['video_url'] = self.event.video_url + elif self.event.video_recording: + video_state = 'to-be-recorded' + elif not self.event.video_recording: + video_state = 'not-to-be-recorded' + + data['video_state'] = video_state if user and user.is_authenticated: is_favorited = user.favorites.filter(event_instance=self).exists()