-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Prod Trigger] Migration for Thiruvasagam #98
Closed
Closed
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The elapsed timing is likely wrong though, that's why the resume play doesn't work well.
* Foundations of the CLI * Fixing Finch Behaviour for Escripts * Wayback Fallback * File Storage and Chalisa.json done * Support fork for escripts vs application runtime --------- Co-authored-by: ks0m1c_dharma <sakiyamuni@sams.ara> Co-authored-by: Ritesh Kumar <ritesh@emerald.pink>
Also keeps voice within playback in the player_live's assigns state. Still yet to shift other playback content responsibilities to media lib.
There are a few bugs: 1. [minor] the current time display is not updating properly 2. [unsure] the emphasis is not happening at exact times, unsure if it's data issue (i.e. origin values are incorrect) or state-handling issue 3. [CSS - unsure] the sticky player is sticking to its own container div, hence it won't stick atop the container that contains all the page's contents 4. [unsure] if you use a system control to control the HTML5 player's playback, then the playback is correctly controlled but the application doesn't listen to this event, so state updates don't sync up
* shifted playback functions from medium to playback.ex * added guard in audio player for no-events case * reintroduced req as a dep because the corpus/engine/fallback.ex uses that lib
- extracted out to components within player_live - hid the next and prev buttons on the player - added other minor player "fixes" like the current playing time and - such
Media Player + Ramayanam Scraper
Minor changes
rtshkmr
changed the title
Migration for Thiruvasagam
[Prod Trigger] Migration for Thiruvasagam
Sep 1, 2024
This is a big commit, commit messages to signpost will be added to this. Essentially, we want DM to be a mediator and therefore all the mode-specific logic should be taken out of the DM and into the mode-specific content module. ReadingContent is the component that shall be slotted in for the "read" mode. This particular commit is not a complete refactor, but takes the following steps towards that direction: 1. shifts the read-mode-specific data loading to the content module. this means all the apply actions have been updated. 2. adhere to the pattern where content livecomponent is it's own source of truth (this part is not fully refactored yet, so DM still injects some state into the content livecomponent). This particular pattern seems to actually follow [known Phoenix patterns actually](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveComponent.html#module-livecomponent-as-the-source-of-truth). * the liveview only prop-passes the id * comms b/w liveview and livecomponent happen using =send_update()=, this is why the =id= for the livecomponent is imporant 3. update event emitters within HEEX strings such that all the events are targetted. For example, the "clickVerseToSeek" will target dom id = `#reading-content`. This adheres to the pattern where mode-specific functionalities happen within their respective components. In this example, VerseMatrix is a nested child of verse, which is a child of the reading_content live component. Since this particular event has nothign to do with other generic slots (e.g. actionBar), then there's no need for DM to be involved with the handling of this event. 4. DM shall keep things generic, Content is a new slot, and arguments for it shall be provided by the 5. NOTE: the MediaBridge will be reworked in the next few PRs, which would simplify how the handshakes happen. For now, this commit actually introduces some regression bug in the handshake actually. We could spend a short 30min trying to debug it, but it should be alright to ignore this regression bug until we get to the point where MediaBridge is getting refactored, during which we can fix it altogether. Next Steps: 1. complete point 1 above, there's still the hoverrune and other read-mode specific events that are yet to be ported.
******* HoverRune hook expects parent id * HoverRune is a generic hook and should work in a manner specific to the mode we are currently in * HoverRune shall expect a parent id to be provided + this gets supplied by the heex template like so #+begin_src html <div id="verses" phx-update="stream" phx-hook="HoveRune" data-parent-id="reading-content"> #+end_src + this allows us to target the event pushed from client to the server #+begin_src js this.pushEventTo(`#${this.parentId}`, "bindHoveRune", { binding: binding, }); #+end_src + so if in reading mode, then parentId = "reading-content" and so VyasaWeb.Content.ReadingContent can handle the bindHoverRune event. <a id="orgfcd7294"></a> - HoverRune is a generic hook and should work in a manner specific to the mode we are currently in - HoverRune shall expect a parent id to be provided - this gets supplied by the heex template like so ```html <div id="verses" phx-update="stream" phx-hook="HoveRune" data-parent-id="reading-content"> ``` - this allows us to target the event pushed from client to the server ```js this.pushEventTo(`#${this.parentId}`, "bindHoveRune", { binding: binding, }); ``` - so if in reading mode, then parentId = “reading-content” and so VyasaWeb.Content.ReadingContent can handle the bindHoverRune event.
This commit offers a good example of what the communication patterns b/w parent liveview and child livecomponent can happen when we choose to keep child livecomponents as the source of truth for data specific to a user_mode. <a id="orgc6f88a0"></a> Here are some points to consider: - since the parent live view is a live view, it can subscribe to topics on the pubsub system and do the necessary handle<sub>info</sub>(). If the effect is mode-agnostic then the parent handles it, else it shall delegate to the child. If the child needs to communicate to the parent, then it shall just message-pass to the parent via a `send()`. This actually follows a documented pattern in LiveView in which (nested) LiveComponents are the source of (data) truth [[ref](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveComponent.html#module-livecomponent-as-the-source-of-truth)]. let’s use an example to describe how this communication b/w parent and child is doneand: 1. parent receives message for :media<sub>handshake</sub>::init 2. parent calls `send_update(ReadingContent, id: "reading-content", sess_id: sess_id)`, which allows the parent to target the specific child that it needs to delegate to. As we can observe, this example is hardcoded (i.e. ReadingContent is NOT generic). In reality, we expect the parent to refer to names generically. For example: `send_update(@mode.Content.Component, id: @mode.Content.id, sess_id: sess_id)` 3. on the child’s side, the update() or update<sub>many</sub>() function can be pattern-matched for this specific delegation-action. For example: ```elixir @impl true # received updates from parent liveview when a handshake is init, does a pub for the voice to use def update( %{id: "reading-content", sess_id: sess_id} = _props, %{ assigns: %{ session: %{"id" => sess_id}, chap: %Chapter{no: c_no, source_id: src_id} } } = socket ) do case Medium.get_voice(src_id, c_no, @default_voice_lang) do %Voice{} = v -> Vyasa.PubSub.publish( v, :voice_ack, sess_id ) _ -> nil end {:ok, socket} end ``` 4. Separately, if the child wishes to communicate to the parent, then it shall message-pass like so: ```elixir @impl true def handle_event( "verses::focus_toggle_on_quick_mark_drafting", %{"is_focusing?" => is_focusing?} = _payload, %Socket{} = socket ) do send(self(), {:change_ui, "update_media_bridge_visibility", [is_focusing?]}) {:noreply, socket} end ``` - The message passing from the child to the parent may involve triggering some other functions to trigger a separate pipeline of effects. Here, we may want to use a dynamic handle<sub>info</sub>() on the parent’s side that would allow us the flexibility to apply whatever action(function) we want. This would allow the child to trigger functions within the parent. For example, 1. say the child component wants to update the `%UiState{}`, which is the held by the parent. ```elixir # within the child: @impl true def handle_event( "verses::focus_toggle_on_quick_mark_drafting", %{"is_focusing?" => is_focusing?} = _payload, %Socket{} = socket ) do send(self(), {:change_ui, "update_media_bridge_visibility", [is_focusing?]}) {:noreply, socket} end ``` 2. then on the parent side, we could handle it like so: ```elixir # parent liveview: @impl true def handle_info({:change_ui, function_name, args}, socket) when is_binary(function_name) and is_list(args) do with :ok <- validate_function_name(function_name, UiState) do func = String.to_existing_atom(function_name) updated_socket = apply(UiState, func, [socket | args]) {:noreply, updated_socket} else {:error, reason} -> IO.puts("Error: #{reason}") {:noreply, socket} end end ```
Nothing special here, same patterns as before.
The selectors are hydrated dynamically
The `%UserMode{}` struct expects slots to be defined within it. This will be either nil or components (defined by their Module name e.g. `control_panel_component: VyasaWeb.ControlPanel`). The slots expected are defined within `@component_slots` e.g. ``` elixir @component_slots [:action_bar_component, :control_panel_component, :mode_context_component] ``` The struct is dynamically defined, like so: ``` elixir @derive Jason.Encoder defstruct [ :mode, :default_ui_state, :mode_icon_name, :quick_actions, :control_panel_modes, :mode_actions, :action_bar_actions, :action_bar_info_types ] ++ Enum.flat_map(@component_slots, fn slot -> [{slot, nil}, {:"#{slot}_selector", @default_slot_selector}] end) ``` So every `<SLOT>` will have an associated `<SLOT>_selector` For this to work, the selectors have to be hydrated. A little annoying but `%UserMode{}` should not be defined by itself, it should only be accessed via the exposed `get_mode()` functions, which automatically handle the hydration of selectors: ``` elixir def get_initial_mode() do "read" |> get_mode() end def get_mode(mode_name) when is_map_key(@defs, mode_name) do struct(UserMode, @defs[mode_name]) |> maybe_hydrate_component_selectors() end def get_mode(_) do get_initial_mode() end ``` If used correctly, after page-load, the `%UserMode{}` will look like this: ``` elixir %Vyasa.Display.UserMode{ mode: "read", default_ui_state: %Vyasa.Display.UiState{ show_media_bridge?: true, show_action_bar?: true }, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Content.ReadingContent, mode_context_component_selector: "reading-content" } ``` So, this is an example of where it gets used: ``` elixir <.live_component module={@mode.mode_context_component} id={@mode.mode_context_component_selector} user_mode={@mode} url_params={@url_params} live_action={@live_action} session={@session} /> ``` or ``` elixir attr :user_mode, UserMode, required: true @impl true def render(assigns) do ~H""" <div id="hoverune" class="z-10 absolute hidden top-0 left-0 max-w-max group-hover:flex items-center bg-white/90 rounded-lg shadow-lg border border-gray-200 transition-all duration-300 ease-in-out p-1" > <%= for action <- @user_mode.quick_actions do %> <.hover_rune_quick_action action_event={get_quick_action_click_event(action)} action_icon_name={get_quick_action_icon_name(action)} action_target={@user_mode.mode_context_component_selector} /> <% end %> </div> """ end ```
Co-authored-by: Ritesh Kumar <ritesh@emerald.pink> Signed-off-by: a/vivekbala <avivekbala@gmail.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.