wip volume change modal

This commit is contained in:
Nuwan 2025-11-13 02:07:55 +05:30
parent dc98da5c58
commit c3c0022e7e
7 changed files with 355 additions and 3 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -26,6 +26,7 @@ import FalconCardHeader from '../common/FalconCardHeader';
import SessionTrackVU from './SessionTrackVU.js';
import JKSessionSettingsModal from './JKSessionSettingsModal.js';
import JKSessionInviteModal from './JKSessionInviteModal.js';
import JKSessionVolumeModal from './JKSessionVolumeModal.js';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals.js';
import { toast } from 'react-toastify';
@ -462,7 +463,7 @@ const JKSessionScreen = () => {
<div className="d-flex flex-nowrap overflow-auto" style={{ gap: '0.5rem' }}>
<Button className='btn-custom-outline' outline size="md" onClick={() => setShowSettingsModal(true)}>Settings</Button>
<Button className='btn-custom-outline' outline size="md" onClick={() => setShowInviteModal(true)}>Invite</Button>
<Button className='btn-custom-outline' outline size="md">Volume</Button>
<Button className='btn-custom-outline' outline size="md" onClick={() => setShowVolumeModal(true)}>Volume</Button>
<Button className='btn-custom-outline' outline size="md">Video</Button>
<Button className='btn-custom-outline' outline size="md">Record</Button>
<Button className='btn-custom-outline' outline size="md">Broadcast</Button>
@ -698,6 +699,11 @@ const JKSessionScreen = () => {
}
}}
/>
<JKSessionVolumeModal
isOpen={showVolumeModal}
toggle={() => setShowVolumeModal(!showVolumeModal)}
/>
</Card>
)
}

View File

@ -0,0 +1,114 @@
import React from 'react';
import {
Button,
Modal,
ModalHeader,
ModalBody,
ModalFooter,
Input,
Row,
Col
} from 'reactstrap';
import SessionTrackVU from './SessionTrackVU';
import VolumeSlider from './VolumeSlider'
import VuMeter from './VuMeter';
import { useMixersContext } from '../../context/MixersContext';
const JKSessionVolumeModal = ({ isOpen, toggle }) => {
const mixerHelper = useMixersContext();
const mixers = mixerHelper.myTracks[0]?.mixers;
const handleCancel = () => {
toggle();
};
return (
<Modal isOpen={isOpen} toggle={handleCancel} modalClassName="theme-modal" contentClassName="border" size="md">
<ModalHeader toggle={handleCancel} className="bg-light d-flex flex-between-center border-bottom-0">
Volume
</ModalHeader>
<ModalBody>
<div className='d-flex' style={{ paddingRight: '0px', marginLeft: '0px' }}>
<div style={{ borderRight: '1px #ddd solid', marginRight: '1rem' }}>
<h6>Music Volume</h6>
<div className='d-flex'>
<div className='mr-2'>
<VolumeSlider initialValue={75} minValue={0} maxValue={100} />
</div>
{/* <div className='d-flex align-items-end mr-2'>
<div className='vu mr-1'>
<div className="d-flex flex-column" style={{ height: '140px' }}>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
</div>
</div>
<div className='vu'>
<div className="d-flex flex-column" style={{ height: '140px' }}>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
</div>
</div>
</div> */}
<VuMeter />
<div style={{ marginTop: '1.5rem' }}>
<small className="d-block">Use this slider to control the volume of all the music in your session mix.</small>
<small className="d-block">This will not affect the volume for other musicians in the session.</small>
</div>
</div>
</div>
<div>
<h6>Chat Volume</h6>
<div>
<div className='d-flex'>
<div className='mr-2'>
<VolumeSlider initialValue={55} minValue={0} maxValue={100} />
</div>
<VuMeter />
<div style={{ marginTop: '1.5rem' }}>
<small className="d-block">Use this slider to control the volume of all the music in your session mix.</small>
<small className="d-block">This will not affect the volume for other musicians in the session.</small>
</div>
</div>
</div>
</div>
</div>
</ModalBody>
</Modal>
);
};
export default JKSessionVolumeModal;

View File

@ -0,0 +1,70 @@
.vertical-slider-container {
height: 140px; /* Define the height of the slider area */
width: 20px;
display: flex;
justify-content: center;
padding: 1px 0;
cursor: pointer; /* Makes the container clickable */
}
.horizontal-slider-container {
height: 20px; /* Define the height of the slider area */
width: 140px;
display: flex;
align-items: center;
padding: 0 1px;
cursor: pointer; /* Makes the container clickable */
}
.slider-track {
width: 8px;
height: 100%;
background-color: #ddd;
position: relative;
border-radius: 4px;
}
.slider-fill {
position: absolute;
bottom: 0; /* Fill starts from the bottom */
width: 100%;
background-color: #8e9090;
/* Height is controlled by JavaScript/React */
}
.slider-fill.horizontal {
bottom: auto;
left: 0; /* Fill starts from the left */
height: 100%;
width: auto; /* Width controlled by JavaScript/React */
}
.slider-thumb {
position: absolute;
bottom: 0; /* Thumb starts at the bottom */
left: 50%;
transform: translateX(-50%);
width: 18px;
height: 18px;
background-color: #8e9090;
border-radius: 50%;
cursor: grab;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
transition: transform 0.1s ease; /* Optional: smooth movement */
}
.slider-thumb.horizontal {
bottom: 50%;
left: 0; /* Thumb starts at the left */
transform: translateY(-50%);
}
.slider-thumb.dragging {
cursor: grabbing;
}
#slider-value {
margin-top: 2px;
text-align: center;
}

View File

@ -0,0 +1,110 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';
import './VolumeSlider.css'; // We will put the CSS here
const VolumeSlider = ({ initialValue = 50, minValue = 0, maxValue = 100, orientation = 'vertical' }) => {
const [value, setValue] = useState(initialValue);
const sliderTrackRef = useRef(null);
const sliderThumbRef = useRef(null);
const sliderFillRef = useRef(null);
// Function to calculate and update the slider's position and value
const updateSlider = useCallback((clientPos) => {
if (!sliderTrackRef.current) return;
const trackRect = sliderTrackRef.current.getBoundingClientRect();
let positionInTrack, trackSize;
if (orientation === 'vertical') {
// Calculate position from the BOTTOM of the track
positionInTrack = trackRect.bottom - clientPos;
trackSize = trackRect.height;
} else {
// Calculate position from the LEFT of the track
positionInTrack = clientPos - trackRect.left;
trackSize = trackRect.width;
}
// Clamp the position within the valid track bounds (0 to trackSize)
const clampedPosition = Math.max(0, Math.min(positionInTrack, trackSize));
// Calculate the percentage and the actual value
const percentage = clampedPosition / trackSize;
const newValue = Math.round(minValue + (maxValue - minValue) * percentage);
// Update state and UI
setValue(newValue);
// Directly manipulating the DOM for immediate visual updates during drag
if (orientation === 'vertical') {
sliderThumbRef.current.style.bottom = `${clampedPosition}px`;
sliderFillRef.current.style.height = `${clampedPosition}px`;
} else {
sliderThumbRef.current.style.left = `${clampedPosition}px`;
sliderFillRef.current.style.width = `${clampedPosition}px`;
}
}, [minValue, maxValue, orientation]);
// Mouse Move and Up Handlers (Global listeners)
const handleMouseMove = useCallback((e) => {
e.preventDefault(); // Prevent text selection
updateSlider(orientation === 'vertical' ? e.clientY : e.clientX);
}, [updateSlider, orientation]);
const handleMouseUp = useCallback(() => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
if (sliderThumbRef.current) {
sliderThumbRef.current.classList.remove('dragging');
}
}, [handleMouseMove]);
// Mouse Down Handler (Starts the drag)
const handleMouseDown = (e) => {
e.preventDefault();
// Add global listeners when dragging starts
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
if (sliderThumbRef.current) {
sliderThumbRef.current.classList.add('dragging');
}
};
// Click on Track Handler (Jump to value)
const handleTrackClick = (e) => {
updateSlider(orientation === 'vertical' ? e.clientY : e.clientX);
};
// Initialize the slider position when the component mounts or values change
useEffect(() => {
const initialPercentage = (initialValue - minValue) / (maxValue - minValue);
if (orientation === 'vertical') {
const trackHeight = sliderTrackRef.current.clientHeight;
const initialClampedPosition = trackHeight * initialPercentage;
sliderThumbRef.current.style.bottom = `${initialClampedPosition}px`;
sliderFillRef.current.style.height = `${initialClampedPosition}px`;
} else {
const trackWidth = sliderTrackRef.current.clientWidth;
const initialClampedPosition = trackWidth * initialPercentage;
sliderThumbRef.current.style.left = `${initialClampedPosition}px`;
sliderFillRef.current.style.width = `${initialClampedPosition}px`;
}
}, [initialValue, minValue, maxValue, orientation]);
return (
<div>
<div id="slider-value"><small>{value}db</small></div>
<div className={orientation === 'vertical' ? "vertical-slider-container" : "horizontal-slider-container"} onClick={handleTrackClick}>
<div className="slider-track" ref={sliderTrackRef}>
<div className={`slider-fill ${orientation === 'horizontal' ? 'horizontal' : ''}`} ref={sliderFillRef}></div>
<div
className={`slider-thumb ${orientation === 'horizontal' ? 'horizontal' : ''}`}
ref={sliderThumbRef}
onMouseDown={handleMouseDown}
></div>
</div>
</div>
</div>
);
};
export default VolumeSlider;

View File

@ -0,0 +1,52 @@
import React from 'react'
const VuMeter = () => {
return (
<div className='d-flex align-items-end mr-2'>
<div className='vu mr-1'>
<div className="d-flex flex-column" style={{ height: '140px' }}>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
</div>
</div>
<div className='vu'>
<div className="d-flex flex-column" style={{ height: '140px' }}>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-secondary" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-danger" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-warning" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
<div className="bg-success" style={{ height: '10px', width: '15px', marginTop: '1px', borderRadius: '2px' }}></div>
</div>
</div>
</div>
)
}
export default VuMeter