Slide 1

Slide 1 text

)BSVOB5TVKJUB !IBSVOBUTVKJUB   ,BJHJPO3BJMT )PUXJSFPS3FBDU d3FBDUͷ࿥ըػೳΛ)PUXJSFʹஔ͖׵͑ͯಘΒΕͨ஌ݟd

Slide 2

Slide 2 text

ࣗݾ঺հ !IBSVOBUTVKJUB ✦ˠגࣜձࣾΩϟλϧʢӳޠक़ΛӡӦʣ ✦όοΫΤϯυΤϯδχΞʢ3BJMTͱɺͨ·ʹ3FBDUʣ ✦ϥΠςΟϯάͷఴ࡟αʔϏεΛ։ൃ

Slide 3

Slide 3 text

ࠓ೔ͷςʔϚ ✦ϝΠϯ͸)PUXJSFɺಛʹ4UJNVMVTͷ࿩Ͱ͢ ✦ٕज़બఆʹؔ͢Δ࿩΋͠·͢ w ࢲ͸3FBDU΋޷͖Ͱ͢ w ຊ୊ͷલʹϓϩμΫτ΍νʔϜͷঢ়گΛ؆୯ʹڞ༗͠·͢

Slide 4

Slide 4 text

ϥΠςΟϯάͷఴ࡟αʔϏεͱ͸ʁ w ӳޠक़Ωϟλϧʹ௨͏ੜెʹఏڙ͍ͯ͠Δখن໛ͳΞϓϦέʔγϣϯ w 3VCZPO3BJMT෦෼తʹ3FBDUͰ41"Λ࣮ݱ ڭࢣ ੜె ӳޠͰϥΠςΟϯάΛॻ͘ɾఏग़ ఴ࡟ɾϑΟʔυόοΫ

Slide 5

Slide 5 text

3FBDUɺຊ౰ʹඞཁʁ ͜ͷ͘Β͍ͷن໛ͷαʔϏεʹ

Slide 6

Slide 6 text

w 3BJMTͷํ͕ಘҙͳόοΫΤϯυΤϯδχΞ໊͕։ൃ w ޠ਺Χ΢ϯτɾςΩετΤϦΞͷϋΠϥΠτͳͲͪΐͬͱͨ͠ՕॴΛ41"ʹ͍ͨ͠ ‣3FBDUͰॻ͔ΕͨՕॴ͕ঃʑʹෛ࠴Խ ‣ϝΠϯͷػೳ։ൃʹ͕͔͔࣌ؒͬͯ͠·͏  w ΍Γ͍ͨ͜ͱ͸)PUXJSFͰे෼࣮ݱͰ͖ΔͷͰ͸ʁ 3FBDUؔ࿈ͷ՝୊ .ZOBNFJT)BSVOB *`NGSPN5PLZP  େֻ͔Γͳ͜ͱ͸͍ͯ͠ͳ͍ʝ

Slide 7

Slide 7 text

3FBDUΛ΍Ίͯ)PUXJSFʹ͢Δͷ͸ා͍ʂʂʂ

Slide 8

Slide 8 text

ා͞ͷਖ਼ମʢͱࢥΘΕΔ΋ͷʣ 3FBDU ΤίγεςϜ΍஌ݟ͕ॆ࣮ʢͱ͘ʹ$IBLSB6*Λ࢖͍͍ͨʣ ॊೈʹ6*Λ࣮૷Ͱ͖Δ )PUXJSF 5VSCPͷΠϝʔδɾ$36%ૢ࡞Λ/P+4Ͱ41"ϥΠΫʹͰ͖Δ 
 ؅ཧػೳ͘Β͍ͷϓϩμΫτʹϑΟοτʁ 
 4UJNVMVTͷ৘ใ͕͋·Γͳͯ͘ະ஌਺ )PUXJSFͷΈͰे෼։ൃͰ͖Δʁ3FBDUΛख์ͯ͠ຊ౰ʹ͍͍ͷʁ

Slide 9

Slide 9 text

ٕज़ݕূ͢ΔՁ஋͸͋Γͦ͏ʂ w ݒ೦ͷҰͭ͸4UJNVMVT ‣͜Ε͕ϑΟοτ͠ͳ͚Ε͹)PUXJSFஔ͖׵͑ͷબ୒ࢶ͕ফ͑Δ w 3FBDUΛؤுΖ͏ʂͱܾҙͰ͖Δͷ͸νʔϜʹͱͬͯϓϥεͳ͸ͣ

Slide 10

Slide 10 text

࿥ըػೳΛஔ͖׵͑ͯΈΔ w ϑΟʔυόοΫಈըͷ࿥ըػೳ ‣ಈըσʔλͷอଘɾ࠶ੜɾ࡟আ ‣1$ͷΧϝϥɾϚΠΫͷૢ࡞͕ೖΔͨΊ ࣮֬ʹ4UJNVMVTΛ࢖͏ ‣ػೳվળ͕׆ൃʹߦΘΕͳ͍Օॴ 3FDPSE $MFBS

Slide 11

Slide 11 text

ஔ͖׵͑ͷલఏ৚݅ w 3FBDUͱ)PUXJSFͷҧ͍Λݕূ͢Δ͜ͱ͕໨త ‣طଘͷ6*69Λҡ࣋͠ɺ࢓༷͸มߋ͠ͳ͍

Slide 12

Slide 12 text

3FDPSE $MFBS

Slide 13

Slide 13 text

3FDPSE $MFBS 4UPQ $MFBS )J 3FDPSEˠ4UPQ ࿥ըελʔτ

Slide 14

Slide 14 text

3FDPSE $MFBS 4UPQ $MFBS )J 4UPQ $MFBS (PPEMVDL

Slide 15

Slide 15 text

3FDPSE $MFBS 4UPQ $MFBS )J 4UPQ $MFBS (PPEMVDL 3FDPSE $MFBS ಈը࠶ੜ EJTBCMFEղআ EJTBCMFEUSVF 1045

Slide 16

Slide 16 text

3FDPSE $MFBS 4UPQ $MFBS )J 4UPQ $MFBS (PPEMVDL 3FDPSE $MFBS 1045 %&-&5&

Slide 17

Slide 17 text

3FBDUͰͷ࣮૷Λݟ͍͖ͯ·͠ΐ͏

Slide 18

Slide 18 text

ݱঢ়ͷ࣮૷ 3FBDU ఴ࡟ϖʔδ 3FDPSE $MFBS // app/views/summaries/feedbacks/edit.html.haml -# লུ #summary-video-recorder{data: {'summary-id': @summary.id}} = javascript_include_tag ‘SummaryVideoRecorder' -# লུ w ఴ࡟ϖʔδͷWJFX͔Β3FBDUΛݺͼग़͢

Slide 19

Slide 19 text

w ಈըͷදࣔɾ3FDPSEϘλϯɾ$MFBSϘλϯ͕ίϯϙʔωϯτԽ w ϘλϯͷΫϦοΫΠϕϯτΛى఺ʹॲཧ͕࣮ߦ͞ΕΔ return ( <>

) } ݱঢ়ͷ࣮૷ 3FDPSE $MFBS

Slide 20

Slide 20 text

)PUXJSF4UJNVMVTͱ͸ʁ
Greet
// hello_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } } Ҿ༻ɿ)PUXJSF)BOECPPL 5VSCPͱ૬ੑͷΑ͍ +BWB4DSJQUϑϨʔϜϫʔΫ

Slide 21

Slide 21 text

)PUXJSF4UJNVMVTͱ͸ʁ
Greet
// hello_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } } Ҿ༻ɿ)PUXJSF)BOECPPL

Slide 22

Slide 22 text

)PUXJSF4UJNVMVTͱ͸ʁ
Greet
// hello_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } } Ҿ༻ɿ)PUXJSF)BOECPPL ΠϕϯτͰൃੜ͢ΔΞΫγϣϯΛࢦఆ

Slide 23

Slide 23 text

)PUXJSF4UJNVMVTͱ͸ʁ
Greet
// hello_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } } Ҿ༻ɿ)PUXJSF)BOECPPL )BSVOBͱೖྗͯ͠(SFFUϘλϯΛԡ͢ͱz)FMMP )BSVOBz͕ग़ྗ

Slide 24

Slide 24 text

)PUXJSF΁ஔ͖׵͑ // app/javascript/controllers/video_recorder_controller.js export default class extends Controller { static targets = ["video"] static values = { summaryId: Number } } -# app/views/summaries/feedbacks/edit.html.haml %div{data: {controller: "video-recorder", video_recorder_summary_id_value: @summary.id}} %video{data: {video_recorder_target: "video"}, controls: true, autoplay: true, muted: true} %button{data: {action: "click->video-recorder#startRecording"}} Record %button{data: {action: "click->video-recorder#stopRecording"} Stop %button{data: {action: "click->video-recorder#clearVideo"} Clear

Slide 25

Slide 25 text

)PUXJSF΁ஔ͖׵͑ ࣮૷్தͳͷʹɺͳΜ͔+BWB4DSJQU ͍ͬͺ͍ॻ͍ͯΔͧɾɾʁ // app/javascript/controllers/video_recorder_controller.js import { Controller } from "@hotwired/stimulus" // Connects to data-controller="feedback-video" export default class extends Controller { static targets = ["video", "recordButton", "stopButton", "clearButton"] static values = { summaryId: Number } async connect() { console.log(this.summaryIdValue) this.chunks = [] const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }) this.videoTarget.srcObject = stream this.videoTarget.play() this.mediaRecorder = new MediaRecorder(stream) this.mediaRecorder.ondataavailable = (event) => this.chunks.push(event.data) } startRecording() { try { console.log('start recording') this.mediaRecorder.start() } catch(error) { console.error('Error accessing media devices.', error) } } stopRecording() { console.log('stop recording') this.mediaRecorder.stop() this.mediaRecorder.onstop = this.handleStop.bind(this) } handleStop() { const blob = new Blob(this.chunks, { type: 'video/webm' }) const url = URL.createObjectURL(blob) this.videoTarget.src = url this.uploadVideo(blob) } async uploadVideo(blob) { const formData = new FormData() formData.append( 'summary_video[video]', blob, `summary_video_id${this.summaryIdValue}.webm` ) const response = await fetch(`/api/summaries/${this.summaryIdValue}/summary_feedback_videos`, { method: 'POST', body: formData, headers: { 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content } }) if (response.ok) { await response.json() console.log('Video uploaded') } else { console.error('Failed to upload video', await response.text()) } } clearVideo() { try { fetch(`/api/summaries/${this.summaryIdValue}/summary_feedback_videos`, { method: 'DELETE', headers: { 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content } }) } catch(error) { console.error('Error deleting video', error) } } } ˞த਎͸ಡ·ͳͯ͘େৎ෉ͳͷͰɺ ࠞಱͱͨ͠ײ͡Λ἞Έऔ͍͚ͬͯͨͩΔͱخ͍͠Ͱ͢ɻ

Slide 26

Slide 26 text

4UJNVMVTΛ৮ͬͯΈͨॴײ w ಈ࡞͸࣮ݱͰ͖ͦ͏ɻ w 4UJNVMVTࣗମʹॻ͖ͮΒ͞͸ͳ͍ɻ w Ͱ΋ɺͬ͘͠Γ͜ͳ͍ɻ ͱɺࢥ͍ͭͭνʔϜϝϯόʔʹ్தܦաΛڞ༗ͨ͠ͱ͜Ζɾɾɾ

Slide 27

Slide 27 text

ΰϦΰϦʹ+BWB4DSJQUॻ͘͜ͱʹͳͬͪΌ͏Ͷ ͜ΕͳΒ3FBDUͰྑ͍ͷͰ͸ʁ

Slide 28

Slide 28 text

ϓϩϙʔβϧఏग़࣌͸͜͏݁࿦Λग़͍ͯͨ͠

Slide 29

Slide 29 text

ຊ౰ʹ͜ΕͰɺྑ͍ͷ͔ɾɾʁʁʁ

Slide 30

Slide 30 text

ʢ࠶ܝʣ4UJNVMVTΛ৮ͬͯΈͨॴײ w ಈ࡞͸࣮ݱͰ͖ͦ͏ɻ w 4UJNVMVTࣗମʹॻ͖ͮΒ͞͸ͳ͍ɻˠ  w Ͱ΋ɺͬ͘͠Γ͜ͳ͍ɻ ͱɺࢥ͍ͭͭνʔϜϝϯόʔʹ్தܦաΛڞ༗ͨ͠ͱ͜Ζɾɾɾ

Slide 31

Slide 31 text

w 3FBDUʹؔ͢Δ஌ࣝʢVTF4UBUFͳͲͷ)PPLTʣ͕ඞཁͳ͍ ‣)PPLT͕Α͠ͳʹॲཧ͍ͯͨ͠ՕॴΛࣗ෼Ͱ࣮૷͢Δ͜ͱʹ w ָʹϑϩϯτΤϯυΛॻ͖͔ͨͬͨ͸ͣͳͷʹ ‎3FBDUΛ࢖༻͢ΔΑΓ΋+BWB4DSJQUͷίʔυ͕૿Ճ ॻ͖ͮΒ͕͞ͳ͍ɺͷਖ਼ମ͸ʁ

Slide 32

Slide 32 text

վળͷ༨஍Λ୳Δ w 4UJNVMVTίϯτϩʔϥʔʹա౓ͳ+BWB4DSJQUͷϩδοΫ͕ूத ‣ͦΕͳΒ͹3FBDU͕ྑ͍ w ͔͠͠ɺผͷՕॴͰ5VSCPΛ࢖࣮ͬͯ૷ͨ͠ͱ͖ ‣5VSCP͸νʔϜͰ޷ධͩͬͨ

Slide 33

Slide 33 text

࣮૷ํ਑Λݟ௚͢ w Ծઆ̍ɿ)PUXJSFͷࢫΈ͸5VSCPͳͷͰ͸ ‣5VSCPʹدͤΔ͜ͱͰɺ4UJNVMVTʹॻ͘+BWB4DSJQU͕ݮΔ͸ͣ w Ծઆ̎ɿ4UJNVMVTͷίϯτϩʔϥʔΛ੔ཧ͢Δͱҹ৅͕ҧ͏ͷͰ͸

Slide 34

Slide 34 text

)PUXJSF5VSCPͱ͸ʁ w $36%ૢ࡞Λத৺ͱͨ͠41"ϥΠΫͳମݧΛ+BWB4DSJQUΛॻ͔ͣʹ ࣮ݱͰ͖Δπʔϧ ങ͍෺ʹߦ͘ ݘʹ㕒Λ͋͛Δ

Slide 35

Slide 35 text

)PUXJSF5VSCPͱ͸ʁ w ϦΫΤετʹରͯ͠ɺαʔόʔ͸ࢦఆͨ͠Օॴͷ)5.-ΛϨεϙϯε ‣ը໘શମΛ࠶ඳը͠ͳ͍ͷͰ41"ϥΠΫͳಈ࡞Λ࣮ݱͰ͖Δ ങ͍෺ʹߦ͘ ݘʹ㕒Λ͋͛Δ

Slide 36

Slide 36 text

࿥ըػೳͷͲ͜Ͱ5VSCPΛ࢖͑Δʁ

Slide 37

Slide 37 text

 ˞ҎԼ,BJHJPO3BJMTαΠτ͔ΒҰ෦ൈਮ  41"ͱ)PUXJSFͰ͸ɺΞϓϦΛߏ੒͢ΔͨΊͷ෺ͷߟ͑ํ͕େ͖͘ҟͳΓ·͢ɻ )PUXJSFΛॎԣແਚʹ࢖͍౗ͨ͢Ίʹ͸ɺ)PUXJSFతͳߟ͑ํͰ࡞Δඞཁ͕͋ΔͷͰ͢ɻ ͜ͷɺ)PUXJSFతͳߟ͑ํʹઃܭࢦ਑ʹࢲ͸ʮ8FCࢴࣳډʯͱ͍͏໊લΛ͚ͭ·ͨ͠ɻ

Slide 38

Slide 38 text

3FDPSE $MFBS 4UPQ $MFBS )J 4UPQ $MFBS (PPEMVDL 3FDPSE $MFBS 1045 %&-&5& ը໘ͷྲྀΕʹԊ࣮ͬͯ૷͢Δͷ͸μϝͩͬͨɾɾ

Slide 39

Slide 39 text

ߟ͑ํΛม͑ͯΈΔʂ

Slide 40

Slide 40 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ʢ࠶ܝʣϘλϯͷΫϦοΫͰঢ়ଶ͕ભҠ͢Δ

Slide 41

Slide 41 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& %#ʹಈը σʔλͳ͠ %#ʹಈը σʔλ͋Γ ࿥ը։࢝  ऴྃ

Slide 42

Slide 42 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ᶃಈըσʔλͳ͠ ᶄಈըσʔλ͋Γ

Slide 43

Slide 43 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ᶃಈըσʔλͳ͠ ᶄಈըσʔλ͋Γ 5VSCPΛར༻Ͱ͖ͦ͏

Slide 44

Slide 44 text

ࢴࣳډͱͯ͠ߟ͑ͯΈΔ 3FDPSE ᶃಈըσʔλͳ͠ $MFBS ᶄಈըσʔλ͋Γ 1045 %&-&5& $MFBS 3FDPSE w $36%ૢ࡞͕͖͔͚ͬͰൃੜ͢Δը໘ͷ੾Γସ͑͸5VSCPʹ೚ͤΔ ˞ʰ8FCࢴࣳډʱͷτʔΫ͸ը໘શମΛຕͷࢴࣳډͱͯ͠ଊ͑Δ͓࿩ͳͷͰɺ τʔΫ͔ΒώϯτΛಘͨ͏͑ͰҟͳΔΞϓϩʔνΛ͍ͯ͠·͢

Slide 45

Slide 45 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ᶃಈըσʔλͳ͠ ᶄಈըσʔλ͋Γ ʁʁʁ ࿥ը։࢝ऴྃ Ϙλϯͷ%0.ૢ࡞ͳͲ

Slide 46

Slide 46 text

ࢴࣳډͱͯ͠ߟ͑ͯΈΔᶄ 4UPQ ᶃ $MFBS 3FDPSE w lࢴࣳډͷ࢓ֻ͚zͱଊ͑ͯΈΔ ‣3BJMTଆͰ੍ޚ͢Δͷ͸೉͍͠ ‣4UJNVMVTͰ࣮૷͢Δ

Slide 47

Slide 47 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ᶃಈըσʔλͳ͠ ᶄಈըσʔλ͋Γ 5VSCPͰ࣮૷

Slide 48

Slide 48 text

)PUXJSF΁ஔ͖׵͑d5VSCPΛ࢖͏d // app/views/summaries/feedbacks/_summary_feedback_video.html.haml = turbo_frame_tag 'summary-feedback-video' do %div{data: {controller: "video-recorder", {//stimulusίϯτϩʔϥ΁σʔλ౉͠}}} .is-flex.is-flex-direction-column.is-align-items-start - if summary_feedback_video.present? // ϏσΦσʔλ͕͋Δ࣌ͷॲཧ - else // ϏσΦσʔλ͕ͳ͍࣌ͷॲཧ // ఴ࡟ϖʔδͷview = render partial: 'summaries/feedbacks/summary_feedback_video', locals: { // লུ } ˣbTVNNBSZGFFECBDLWJEFP` ఴ࡟ϖʔδͷWJFX

Slide 49

Slide 49 text

// app/views/summaries/feedbacks/_summary_feedback_video.html.haml = turbo_frame_tag 'summary-feedback-video' do %div{data: {controller: "video-recorder", {// ίϯτϩʔϥʔ΁σʔλड͚౉͠}}} .is-flex.is-flex-direction-column.is-align-items-start - if summary_feedback_video.present? %video %source{src: summary_feedback_video.video_url, type: "video/webm"} = link_to 'Clear', summary_summary_feedback_videos_path(summary), data: { turbo_confirm: "ຊ౰ʹ࡟আ͠·͔͢ʁ", turbo_method: :delete } - else // ϏσΦσʔλ͕ͳ͍࣌ͷॲཧ ˞εϖʔεͷؔ܎ͰࢿྉͰ͸Ұ෦লུ͍ͯ͠ΔՕॴ͕͋Γ·͢ # app/controllers/summaries/summary_feedback_videos_controller.rb def destroy @summary = Summary.find(params[:summary_id]) @summary_feedback_video = @summary.summary_feedback_video @summary_feedback_video.destroy! end ˢ҉໧తʹUVSCP@TUSFBNΛSFOEFS ˠ5VSCPϦΫΤετˠ3BJMTίϯτϩʔϥʔ

Slide 50

Slide 50 text

// app/views/summaries/summary_feedback_videos/destroy.turbo_stream.haml = turbo_stream.replace 'summary-feedback-video', partial: 'summaries/feedbacks/summary_feedback_video', locals: { summary: @summary, summary_feedback_video: nil } ˠ5VSCPϦΫΤετˠ3BJMTίϯτϩʔϥʔˠUVSCP@TUSFBN ˣbTVNNBSZGFFECBDLWJEFP` ఴ࡟ϖʔδͷWJFX ˞εϖʔεͷؔ܎ͰࢿྉͰ͸վߦΛೖΕ͍ͯ·͢

Slide 51

Slide 51 text

// app/views/summaries/summary_feedback_videos/destroy.turbo_stream.haml = turbo_stream.replace 'summary-feedback-video', partial: 'summaries/feedbacks/summary_feedback_video', locals: { summary: @summary, summary_feedback_video: nil } ˠ5VSCPϦΫΤετˠ3BJMTίϯτϩʔϥʔˠUVSCP@TUSFBN // app/views/summaries/feedbacks/_summary_feedback_video.html.haml = turbo_frame_tag 'summary-feedback-video' do %div{data: {controller: "video-recorder", {// ίϯτϩʔϥʔ΁σʔλड͚౉͠}}} .is-flex.is-flex-direction-column.is-align-items-start - if summary_feedback_video.present? // ϏσΦσʔλ͕͋Δ࣌ͷॲཧ - else // ϏσΦσʔλ͕ͳ͍࣌ͷॲཧ ઌ΄Ͳ·Ͱ͸σʔλ͕ ͋ͬͨͷͰͪ͜Β

Slide 52

Slide 52 text

// app/views/summaries/summary_feedback_videos/destroy.turbo_stream.haml = turbo_stream.replace 'summary-feedback-video', partial: 'summaries/feedbacks/summary_feedback_video', locals: { summary: @summary, summary_feedback_video: nil } ˠ5VSCPϦΫΤετˠ3BJMTίϯτϩʔϥʔˠUVSCP@TUSFBNˠ // app/views/summaries/feedbacks/_summary_feedback_video.html.haml = turbo_frame_tag 'summary-feedback-video' do %div{data: {controller: "video-recorder", {// ίϯτϩʔϥʔ΁σʔλड͚౉͠}}} .is-flex.is-flex-direction-column.is-align-items-start - if summary_feedback_video.present? // ϏσΦσʔλ͕͋Δ࣌ͷॲཧ - else // ϏσΦσʔλ͕ͳ͍࣌ͷॲཧ σʔλ͕࡟আ͞Εͨ ͷͰͪ͜Β͕࣮ߦ͞ΕΔ ˣbTVNNBSZGFFECBDLWJEFP` ఴ࡟ϖʔδͷWJFX

Slide 53

Slide 53 text

3FDPSE ᶃಈըσʔλͳ͠ $MFBS ᶄಈըσʔλ͋Γ 1045 %&-&5& $MFBS 3FDPSE ʢ࠶ܝʣࢴࣳډͷجૅ͕ग़དྷ্͕Δ

Slide 54

Slide 54 text

3FDPSE $MFBS 4UPQ $MFBS (PPEMVDL 4UPQ $MFBS )J 3FDPSE $MFBS 1045 %&-&5& ᶃಈըσʔλͳ͠ ᶄಈըσʔλ͋Γ 4UJNVMVTͰ࣮૷

Slide 55

Slide 55 text

࿥ըʹؔ͢Δॲཧ͸τʔΫͷຊےͰ͸ͳ͍ͷͰɺ ίʔυΛ੔ཧͨ͠ํ๏ʹ͍͓ͭͯ࿩͠͠·͢

Slide 56

Slide 56 text

ʢ࠶ܝʣ࣮૷ํ਑Λݟ௚͢ w Ծઆ̍ɿ)PUXJSFͷࢫΈ͸5VSCPͳͷͰ͸ ‣5VSCPʹدͤΔ͜ͱͰɺ4UJNVMVTʹॻ͘+BWB4DSJQU͕ݮΔ͸ͣ w Ծઆ̎ɿ4UJNVMVTͷίϯτϩʔϥʔΛ੔ཧ͢Δͱҹ৅͕ҧ͏ͷͰ͸ ‣ϦϑΝΫλϦϯάํ๏͸·ͩ໛ࡧதͰ͕͢ɾɾ

Slide 57

Slide 57 text

// app/javascript/controllers/video_recorder_controller.js import { Controller } from "@hotwired/stimulus" import { // ར༻͢Δؔ਺ } from “./video_recorder_utils" export default class extends Controller { static targets = ["video", "recordButton"] static values = { writingId: Number, writingType: String, feedbackVideo: String, uploadUrl: String } async connect() { // ઀ଓ࣌ͷॲཧ } async startRecording() { // ࿥ը։࢝ͷॲཧ } stopRecording() { // ࿥ըऴྃͷॲཧ } }

Slide 58

Slide 58 text

// app/javascript/controllers/video_recorder_controller.js import { Controller } from "@hotwired/stimulus" import { initializeMediaStream, setupMediaRecorder, setStopButton, uploadData } from “./video_recorder_utils" // Connects to data-controller="video-recorder" export default class extends Controller { static targets = ["video", "recordButton"] static values = { writingId: Number, writingType: String, feedbackVideo: String, uploadUrl: String } async connect() { if (!this.feedbackVideoValue) { this.mediaStream = await initializeMediaStream() } } async startRecording() { if (!this.mediaStream) { this.mediaStream = await initializeMediaStream() if (!this.mediaStream) return } this.mediaRecorder = setupMediaRecorder(this.mediaStream) this.mediaRecorder.start() setStopButton(this.recordButtonTarget) this.mediaRecorder.ondataavailable = (event) => uploadData(event, this.writingTypeValue, this.writingIdValue, this.uploadUrlValue) } stopRecording() { this.mediaRecorder?.stop() this.mediaStream.getTracks().forEach(track => track.stop()) this.recordButtonTarget.disabled = true }} 5PUBMߦ

Slide 59

Slide 59 text

͜ΕͰஔ͖׵͑͸׬ྃͰ͢ʂ

Slide 60

Slide 60 text

13͸Ϛʔδ͞Ε·ͨ͠🎉 ٞ࿦ͷ݁Ռʜ

Slide 61

Slide 61 text

13͸Ϛʔδ͞Ε·ͨ͠🎉 ˞ࠩ෼ Ͱ͕͢ɺఴ࡟ը໘ͷ࿥ըػೳՕॴͷஔ͖׵͑Λ͓͜ͳ͍ɺ 3FBDUଆͰڞ௨Խ͞Ε͍ͯͳ͔ͬͨՕॴ͕ࠓճڞ௨Խ͞Εͯͷ݁ՌͳͷͰ Օॴͷ৔߹ɺݮগྔ͸ఔ౓ʹऩ·Γ·͢

Slide 62

Slide 62 text

)PUXJSFPS3FBDUʁ

Slide 63

Slide 63 text

$36%ͷΈ $36% +4 $36%ͳ͠ +4 )PUXJSFPS3FBDUʁ w $36%ૢ࡞͕ओମ ิॿతͳ+BWB4DSJQU͕ඞཁͳը໘ ‣ࢴࣳډ ͪΐͬͱͨ͠࢓ֻ͚͕͋Δ৔߹ w )PUXJSFͰे෼ରԠͰ͖Δɺੵۃతʹ࢖͍͖͍ͬͯͨ

Slide 64

Slide 64 text

w $36%ૢ࡞Λ൐ΘͣϦονͳΠϯλϥΫγϣϯ͕ඞཁͳը໘ ‣FYෳࡶͳεςʔτ؅ཧ͕ඞཁ w ࢲͷ୲౰ϓϩμΫτʹ͸֘౰͠ͳ͍ ‣3FBDUͷಘҙ෼໺ $36%ͷΈ $36% +4 $36%ͳ͠ +4 )PUXJSFPS3FBDUʁ

Slide 65

Slide 65 text

w $36%ΛؚΉߴ౓ͳ41"࣮૷͕ඞཁͳը໘ w $36%ͳ͠Ͱγϯϓϧͳ41"࣮૷͕ඞཁͳը໘ ‣୲౰ϓϩμΫτͰ͸ςΩετΤσΟλ͕֘౰ ‣͜ͷ͋ͨΓ͸ҙݟ͕෼͔ΕΔ )PUXJSFPS3FBDUʁ $36%ͷΈ $36% +4 $36%ͳ͠ +4

Slide 66

Slide 66 text

w $36%ͳ͠Ͱ41"࣮૷͕ඞཁͳը໘ ‣ଟ͘͸Ϣʔβʔ͕௕࣌ؒ଺ࡏ͢Δϖʔδ ‣ຕͷࢴࣳډͷதʹ࢓ֻ͚͕ͨ͘͞Μ͋Δ৔ॴ )PUXJSFPS3FBDUʁ $36%ͷΈ $36% +4 $36%ͳ͠ +4

Slide 67

Slide 67 text

)PUXJSFPS3FBDUʁ $36%ͳ͠ͷ 41"࣮૷Λ͢Δ৔߹ ✦3FBDU w )PPLT΍ΤίγεςϜͷਅՁΛൃش࢝͠ΊΔ ‣͔͠͠3FBDUʹର͢Δਂ͍ཧղ͕ඞཁ ✦)PUXJSF w αʔόʔαΠυʹ࣮૷ΛدͤΒΕͯѻ͍΍͍͢ ‣࣮૷ͷ޻෉ɾ)PUXJSFతઃܭ ‎࣮૷Λ$36%ʹམͱ͠ࠐΉඞཁ͕͋Δ $36%ͷΈ $36% +4 $36%ͳ͠ +4

Slide 68

Slide 68 text

)PUXJSFPS3FBDUʁ w 3FBDUͱ)PUXJSFɺͲͪΒ΋Ұ௕Ұ୹͋Γɺબ୒͢Δͷ͸೉͍͠ w ͨͩ͠ɺʰ)PUXJSFͰ࣮૷Ͱ͖ͦ͏͔ʁʱͱ͍͏ࢹ఺ͩͱ w ࣮૷Λ$36%ʹू໿Ͱ͖Δ͔Ͳ͏͔ɺ͕େ͖ͳϙΠϯτ

Slide 69

Slide 69 text

✦)PUXJSFతͳઃܭ͕Ͱ͖Ε͹ɺద༻ՄೳͳྖҬ͸૝૾ΑΓ޿͍ ✦)PUXJSFΛ࢖ͬͯΈΑ͏͔ͳɺͱࢥ͏ํ͕૿͑ͨΒخ͍͠Ͱ͢ʂ ·ͱΊ

Slide 70

Slide 70 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ

Slide 71

Slide 71 text

ࢀߟ w )PUXJSF)BOECPPLIUUQTIPUXJSFEEFW w 5VSCP)BOECPPLʢ೔ຊޠ༁ʣIUUQTFWFSZMFBGHJUIVCJP IPUXJSF@KBUVSCPIBOECPPLJOUSPEVDUJPO w ೣͰ΋Θ͔Δ)PUXJSFೖ໳5VSCPฤIUUQT[FOOEFWTIJUB CPPLTDBUIPUXJSFUVSCP w )PUXJSFతͳઃܭΛ௥ٻͯ͠ʮ8FCࢴࣳډʯʹߦ͖ண͍ͨ࿩IUUQT LBJHJPOSBJMTPSHUBMLTOBZ