scroll indactor playbacks web
This commit is contained in:
@@ -1,6 +1,19 @@
|
|||||||
import { useIsFocused, useRoute } from "@react-navigation/native";
|
import { useIsFocused, useRoute } from "@react-navigation/native";
|
||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, {
|
||||||
import { FlatList, StyleSheet, View, useWindowDimensions } from "react-native";
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import {
|
||||||
|
FlatList,
|
||||||
|
Image,
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
useWindowDimensions,
|
||||||
|
} from "react-native";
|
||||||
|
import { icons } from "../../assets";
|
||||||
import { projectsRef } from "../../config/firebase";
|
import { projectsRef } from "../../config/firebase";
|
||||||
import useDataFromRef from "../../hooks/useDataFromRef";
|
import useDataFromRef from "../../hooks/useDataFromRef";
|
||||||
import { useUser } from "../../providers/UserDataProvider";
|
import { useUser } from "../../providers/UserDataProvider";
|
||||||
@@ -17,7 +30,12 @@ const Playbacks = () => {
|
|||||||
const userCache = useRef(new Map());
|
const userCache = useRef(new Map());
|
||||||
const { getUserByUid } = useUser() || {};
|
const { getUserByUid } = useUser() || {};
|
||||||
const isFocused = useIsFocused();
|
const isFocused = useIsFocused();
|
||||||
const { data: playbacks = [], loadMore } = useDataFromRef({
|
const {
|
||||||
|
data: playbacks = [],
|
||||||
|
loadMore,
|
||||||
|
hasMore,
|
||||||
|
loading,
|
||||||
|
} = useDataFromRef({
|
||||||
ref: projectsRef.where("playbackUrl", "!=", null),
|
ref: projectsRef.where("playbackUrl", "!=", null),
|
||||||
simpleRef: false,
|
simpleRef: false,
|
||||||
listener: false,
|
listener: false,
|
||||||
@@ -213,6 +231,47 @@ const Playbacks = () => {
|
|||||||
[windowHeight]
|
[windowHeight]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const total = playbacks.length;
|
||||||
|
const indicatorItems = useMemo(() => {
|
||||||
|
if (total <= 0) return [];
|
||||||
|
const maxVisible = 7;
|
||||||
|
let start = 0;
|
||||||
|
let end = total - 1;
|
||||||
|
if (total > maxVisible) {
|
||||||
|
const half = Math.floor(maxVisible / 2);
|
||||||
|
start = activeIndex - half;
|
||||||
|
end = start + maxVisible - 1;
|
||||||
|
if (start < 0) {
|
||||||
|
end += -start;
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
if (end >= total) {
|
||||||
|
const overshoot = end - (total - 1);
|
||||||
|
start = Math.max(0, start - overshoot);
|
||||||
|
end = total - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const items = [];
|
||||||
|
for (let i = start; i <= end; i += 1) {
|
||||||
|
items.push({
|
||||||
|
key: `indicator-${i}`,
|
||||||
|
isActive: i === activeIndex,
|
||||||
|
isPast: i < activeIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}, [total, activeIndex]);
|
||||||
|
|
||||||
|
const canScrollUp = total > 0 && activeIndex > 0;
|
||||||
|
const atLastLoaded = total > 0 && activeIndex >= total - 1;
|
||||||
|
const canScrollDown = total > 0 && (!atLastLoaded || hasMore);
|
||||||
|
const showIndicators = total > 0;
|
||||||
|
const indicatorLabel = useMemo(() => {
|
||||||
|
if (total <= 0) return null;
|
||||||
|
if (hasMore || loading) return `${activeIndex + 1}+`;
|
||||||
|
return `${activeIndex + 1}/${total}`;
|
||||||
|
}, [total, activeIndex, hasMore, loading]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.screen}>
|
<View style={styles.screen}>
|
||||||
{activeVideoUrl ? (
|
{activeVideoUrl ? (
|
||||||
@@ -264,6 +323,50 @@ const Playbacks = () => {
|
|||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
scrollEventThrottle={16}
|
scrollEventThrottle={16}
|
||||||
/>
|
/>
|
||||||
|
{showIndicators && (
|
||||||
|
<View style={styles.indicatorContainer} pointerEvents="none">
|
||||||
|
<Image
|
||||||
|
source={icons.chevronDown}
|
||||||
|
resizeMode="contain"
|
||||||
|
style={[
|
||||||
|
styles.indicatorArrow,
|
||||||
|
styles.indicatorArrowUp,
|
||||||
|
!canScrollUp && styles.indicatorArrowDisabled,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<View style={styles.indicatorDotsWrapper}>
|
||||||
|
{indicatorItems.map((item, index) => (
|
||||||
|
<View
|
||||||
|
key={item.key}
|
||||||
|
style={[
|
||||||
|
styles.indicatorDot,
|
||||||
|
item.isActive && styles.indicatorDotActive,
|
||||||
|
item.isPast && styles.indicatorDotPast,
|
||||||
|
index < indicatorItems.length - 1
|
||||||
|
? styles.indicatorDotSpacing
|
||||||
|
: null,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{canScrollDown && hasMore && (
|
||||||
|
<View
|
||||||
|
style={[styles.indicatorMoreDot, styles.indicatorDotSpacing]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
{/* {indicatorLabel ? (
|
||||||
|
<Text style={styles.indicatorLabel}>{indicatorLabel}</Text>
|
||||||
|
) : null} */}
|
||||||
|
<Image
|
||||||
|
source={icons.chevronDown}
|
||||||
|
resizeMode="contain"
|
||||||
|
style={[
|
||||||
|
styles.indicatorArrow,
|
||||||
|
!canScrollDown && styles.indicatorArrowDisabled,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
// </Page>
|
// </Page>
|
||||||
);
|
);
|
||||||
@@ -319,4 +422,57 @@ const styles = StyleSheet.create({
|
|||||||
fontFamily: FONT_FAMILY.InterMedium,
|
fontFamily: FONT_FAMILY.InterMedium,
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
},
|
},
|
||||||
|
indicatorContainer: {
|
||||||
|
position: "absolute",
|
||||||
|
left: 20,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
indicatorArrow: {
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
tintColor: Palette.white,
|
||||||
|
opacity: 0.8,
|
||||||
|
},
|
||||||
|
indicatorArrowUp: {
|
||||||
|
transform: [{ rotate: "180deg" }],
|
||||||
|
},
|
||||||
|
indicatorArrowDisabled: {
|
||||||
|
opacity: 0.25,
|
||||||
|
},
|
||||||
|
indicatorDotsWrapper: {
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
indicatorDot: {
|
||||||
|
width: 6,
|
||||||
|
height: 12,
|
||||||
|
borderRadius: 3,
|
||||||
|
backgroundColor: "rgba(255,255,255,0.3)",
|
||||||
|
},
|
||||||
|
indicatorDotPast: {
|
||||||
|
backgroundColor: "rgba(255,255,255,0.55)",
|
||||||
|
},
|
||||||
|
indicatorDotActive: {
|
||||||
|
backgroundColor: Palette.white,
|
||||||
|
height: 20,
|
||||||
|
},
|
||||||
|
indicatorDotSpacing: {
|
||||||
|
marginVertical: 5,
|
||||||
|
},
|
||||||
|
indicatorMoreDot: {
|
||||||
|
width: 4,
|
||||||
|
height: 4,
|
||||||
|
borderRadius: 2,
|
||||||
|
backgroundColor: Palette.white,
|
||||||
|
opacity: 0.7,
|
||||||
|
},
|
||||||
|
indicatorLabel: {
|
||||||
|
color: Palette.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: FONT_FAMILY.InterMedium,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const uploadSourceRecording = async ({ uri, uid, projectId }) => {
|
|||||||
|
|
||||||
const extension = guessExtension(uri);
|
const extension = guessExtension(uri);
|
||||||
const sourcePath = `users/${uid}/projects/${projectId}/recordings/source-${Date.now()}.${extension}`;
|
const sourcePath = `users/${uid}/projects/${projectId}/recordings/source-${Date.now()}.${extension}`;
|
||||||
|
console.log("source path : ", sourcePath);
|
||||||
console.log("[DownloadSongs] uploadSourceRecording source path", {
|
console.log("[DownloadSongs] uploadSourceRecording source path", {
|
||||||
extension,
|
extension,
|
||||||
sourcePath,
|
sourcePath,
|
||||||
|
|||||||
Reference in New Issue
Block a user