Skip to content

Commit

Permalink
Merge pull request #89 from mykhailodanilenko/feature/device-info-spread
Browse files Browse the repository at this point in the history
Spread device capabilities view into all screens
  • Loading branch information
mykhailodanilenko authored Jun 27, 2024
2 parents 793f7e0 + 7cab0ae commit ce29bbb
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 74 deletions.
14 changes: 9 additions & 5 deletions OwnTube.tv/app/(home)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Link, useFocusEffect, useLocalSearchParams, useNavigation, useRouter } from "expo-router";
import { ROUTES, SOURCES, STORAGE } from "../../types";
import { readFromAsyncStorage, writeToAsyncStorage } from "../../utils";
import { Loader } from "../../components";
import { DeviceCapabilitiesModal, Loader } from "../../components";
import { useCallback, useState } from "react";
import Head from "expo-router/head";
import { HomeScreen } from "../../screens";
import { Feather } from "@expo/vector-icons";
import { useTheme } from "@react-navigation/native";
import { StyleSheet } from "react-native";
import { StyleSheet, View } from "react-native";

export default function index() {
const router = useRouter();
Expand Down Expand Up @@ -38,9 +38,12 @@ export default function index() {
navigation.setOptions({
title: `OwnTube.tv@${backend}`,
headerRight: () => (
<Link style={styles.headerButton} href={{ pathname: `/${ROUTES.SETTINGS}`, params: { backend } }}>
<Feather name="settings" size={24} color={theme.colors.primary} />
</Link>
<View style={styles.headerControls}>
<Link style={styles.headerButton} href={{ pathname: `/${ROUTES.SETTINGS}`, params: { backend } }}>
<Feather name="settings" size={24} color={theme.colors.primary} />
</Link>
<DeviceCapabilitiesModal />
</View>
),
});
}
Expand Down Expand Up @@ -68,4 +71,5 @@ const styles = StyleSheet.create({
headerButton: {
paddingHorizontal: 11,
},
headerControls: { alignItems: "center", flexDirection: "row", paddingRight: 11 },
});
3 changes: 2 additions & 1 deletion OwnTube.tv/components/BuildInfoToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Linking, StyleSheet, View } from "react-native";
import { Typography } from "./Typography";
import build_info from "../build-info.json";
import { useTheme } from "@react-navigation/native";
import { removeSecondsFromISODate } from "../utils";

export const BuildInfoToast = () => {
const { colors } = useTheme();
Expand All @@ -13,7 +14,7 @@ export const BuildInfoToast = () => {
<Typography fontSize={14} style={styles.link} onPress={() => Linking.openURL(build_info.COMMIT_URL)}>
{build_info.GITHUB_SHA_SHORT}
</Typography>{" "}
built at {`${build_info.BUILD_TIMESTAMP.slice(0, build_info.BUILD_TIMESTAMP.lastIndexOf(":"))}Z`} by{" "}
built at {removeSecondsFromISODate(build_info.BUILD_TIMESTAMP)} by{" "}
<Typography
fontSize={14}
style={styles.link}
Expand Down
66 changes: 66 additions & 0 deletions OwnTube.tv/components/DeviceCapabilities.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Pressable, StyleSheet, View } from "react-native";
import { Typography } from "./Typography";
import * as Clipboard from "expo-clipboard";
import { Ionicons } from "@expo/vector-icons";
import { Spacer } from "./shared/Spacer";
import { useAppConfigContext } from "../contexts";
import { useTheme } from "@react-navigation/native";

export const DeviceCapabilities = () => {
const { deviceCapabilities } = useAppConfigContext();
const { colors } = useTheme();

const handleCopyToClipboard = async () => {
await Clipboard.setStringAsync(JSON.stringify(deviceCapabilities));
};

return (
<View style={[{ backgroundColor: colors.card }, styles.modalContainer]}>
<View style={styles.modalHeader}>
<Typography>Device Capability info:</Typography>
<Pressable onPress={handleCopyToClipboard}>
<Ionicons color={colors.primary} name="copy" size={24} />
</Pressable>
</View>
<Spacer height={16} />
<View style={styles.row}>
<Typography>Player implementation:</Typography>
<Typography>{deviceCapabilities.playerImplementation}</Typography>
</View>
<View style={styles.row}>
<Typography>Device type:</Typography>
<Typography>{deviceCapabilities.deviceType}</Typography>
</View>
<View style={styles.row}>
<Typography>Operating system:</Typography>
<Typography>{deviceCapabilities.OS}</Typography>
</View>
{deviceCapabilities.browser && (
<View style={styles.row}>
<Typography>Browser:</Typography>
<Typography>{deviceCapabilities.browser}</Typography>
</View>
)}
{deviceCapabilities.device && (
<View style={styles.row}>
<Typography>Device:</Typography>
<Typography>{deviceCapabilities.device}</Typography>
</View>
)}
<View style={styles.row}>
<Typography>Screen dimensions:</Typography>
<Typography>{deviceCapabilities.dimensions}</Typography>
</View>
<View style={styles.row}>
<Typography>Orientation:</Typography>
<Typography>{deviceCapabilities.orientation}</Typography>
</View>
</View>
);
};

const styles = StyleSheet.create({
modalContainer: { borderRadius: 8, minWidth: "50%", padding: 16 },
modalHeader: { flexDirection: "row", gap: 16, justifyContent: "space-between" },
row: { flexWrap: "wrap", justifyContent: "space-between", marginVertical: 8, width: "100%" },
});
53 changes: 3 additions & 50 deletions OwnTube.tv/components/DeviceCapabilitiesModal.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { Ionicons } from "@expo/vector-icons";
import { useTheme } from "@react-navigation/native";
import { Modal, Pressable, StyleSheet, View } from "react-native";
import { Modal, Pressable, StyleSheet } from "react-native";
import { useState } from "react";
import { Typography } from "./Typography";
import { useAppConfigContext } from "../contexts";
import { Spacer } from "./shared/Spacer";
import * as Clipboard from "expo-clipboard";
import { colors } from "../colors";
import { DeviceCapabilities } from "./DeviceCapabilities";

export const DeviceCapabilitiesModal = () => {
const { colors } = useTheme();
const [modalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible((prevState) => !prevState);
};
const { deviceCapabilities } = useAppConfigContext();

return (
<>
Expand All @@ -23,47 +19,7 @@ export const DeviceCapabilitiesModal = () => {
</Pressable>
<Modal style={styles.modal} transparent={true} visible={modalVisible} onRequestClose={toggleModal}>
<Pressable style={styles.showModalBtn} onPress={toggleModal}>
<View style={[{ backgroundColor: colors.card }, styles.modalContainer]}>
<View style={styles.modalHeader}>
<Typography>Device Capability info:</Typography>
<Pressable onPress={() => Clipboard.setStringAsync(JSON.stringify(deviceCapabilities))}>
<Ionicons color={colors.primary} name="copy" size={24} />
</Pressable>
</View>
<Spacer height={16} />
<View style={styles.row}>
<Typography>Player implementation:</Typography>
<Typography>{deviceCapabilities.playerImplementation}</Typography>
</View>
<View style={styles.row}>
<Typography>Device type:</Typography>
<Typography>{deviceCapabilities.deviceType}</Typography>
</View>
<View style={styles.row}>
<Typography>Operating system:</Typography>
<Typography>{deviceCapabilities.OS}</Typography>
</View>
{deviceCapabilities.browser && (
<View style={styles.row}>
<Typography>Browser:</Typography>
<Typography>{deviceCapabilities.browser}</Typography>
</View>
)}
{deviceCapabilities.device && (
<View style={styles.row}>
<Typography>Device:</Typography>
<Typography>{deviceCapabilities.device}</Typography>
</View>
)}
<View style={styles.row}>
<Typography>Screen dimensions:</Typography>
<Typography>{deviceCapabilities.dimensions}</Typography>
</View>
<View style={styles.row}>
<Typography>Orientation:</Typography>
<Typography>{deviceCapabilities.orientation}</Typography>
</View>
</View>
<DeviceCapabilities />
</Pressable>
</Modal>
</>
Expand All @@ -72,9 +28,6 @@ export const DeviceCapabilitiesModal = () => {

const styles = StyleSheet.create({
modal: { height: "100%" },
modalContainer: { borderRadius: 8, minWidth: "50%", padding: 16 },
modalHeader: { flexDirection: "row", gap: 16, justifyContent: "space-between" },
row: { flexWrap: "wrap", justifyContent: "space-between", marginVertical: 8, width: "100%" },
showModalBtn: {
alignItems: "center",
backgroundColor: colors._50percentBlackTint,
Expand Down
7 changes: 4 additions & 3 deletions OwnTube.tv/components/VideoView/VideoView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ const VideoView = ({ uri, testID, handleSetTimeStamp, timestamp }: VideoViewProp
const handlePlaybackStatusUpdate = (status: AVPlaybackStatus) => {
if (status?.isLoaded) {
setPlaybackStatus(status);
setPlayerImplementation(
status.androidImplementation ? `Android ${status.androidImplementation}` : "iOS Native player",
);

if (status.androidImplementation) {
setPlayerImplementation(`Android ${status.androidImplementation}`);
}
} else if (status?.error) {
console.error(status.error);
}
Expand Down
3 changes: 0 additions & 3 deletions OwnTube.tv/components/VideoView/VideoView.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { VideoViewProps } from "./VideoView";
import { styles } from "./styles";
import "./styles.web.css";
import videojs from "video.js";
import { useAppConfigContext } from "../../contexts";

declare const window: {
videojs: typeof videojs;
Expand All @@ -25,7 +24,6 @@ const VideoView = ({ uri, testID, handleSetTimeStamp, timestamp }: VideoViewProp
duration: 1,
playableDuration: 0,
});
const { setPlayerImplementation } = useAppConfigContext();

const updatePlaybackStatus = (updatedStatus: Partial<typeof playbackStatus>) => {
setPlaybackStatus((prev) => ({ ...prev, ...updatedStatus }));
Expand Down Expand Up @@ -114,7 +112,6 @@ const VideoView = ({ uri, testID, handleSetTimeStamp, timestamp }: VideoViewProp

useEffect(() => {
if (!videojs) return;
setPlayerImplementation("Web video.js");

if (!playerRef.current) {
const videoElement = document.createElement("video-js");
Expand Down
2 changes: 2 additions & 0 deletions OwnTube.tv/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export * from "./VideoView/VideoView";
export * from "./VideoControlsOverlay";
export * from "./Loader";
export * from "./DeviceCapabilitiesModal";
export * from "./DeviceCapabilities";
export * from "./BuildInfoToast";
export * from "./ClickableHeaderText";
export * from "./ResumeWatching";
export * from "./ViewHistory";
8 changes: 7 additions & 1 deletion OwnTube.tv/hooks/useDeviceCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Device from "expo-device";
import { DeviceType } from "expo-device";
import { Platform, useWindowDimensions } from "react-native";
import UAParser from "ua-parser-js";
import { capitalize } from "../utils";

export interface DeviceCapabilities {
playerImplementation: string;
Expand All @@ -15,7 +16,12 @@ export interface DeviceCapabilities {
}

export const useDeviceCapabilities = () => {
const [playerImplementation, setPlayerImplementation] = useState("");
const [playerImplementation, setPlayerImplementation] = useState(
Platform.select({
web: "Web video.js",
default: capitalize(Platform.OS),
}),
);
const { height, width } = useWindowDimensions();

const getBrowserInfo = () => {
Expand Down
24 changes: 14 additions & 10 deletions OwnTube.tv/screens/SettingsScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { View, Switch } from "react-native";
import { SourceSelect, Typography } from "../../components";
import { SourceSelect, Typography, ViewHistory, DeviceCapabilities } from "../../components";
import { useAppConfigContext, useColorSchemeContext } from "../../contexts";
import { Screen } from "../../layouts";
import { styles } from "./styles";
import { useTheme } from "@react-navigation/native";
import { ViewHistory } from "../../components/ViewHistory";

export const SettingsScreen = () => {
const { isDebugMode, setIsDebugMode } = useAppConfigContext();
Expand All @@ -13,15 +12,20 @@ export const SettingsScreen = () => {

return (
<Screen style={{ ...styles.container, backgroundColor: colors.background }}>
<View style={styles.option}>
<Typography>Debug logging</Typography>
<Switch value={isDebugMode} onValueChange={setIsDebugMode} />
<View style={styles.deviceInfoAndToggles}>
<DeviceCapabilities />
<View style={styles.togglesContainer}>
<View style={styles.option}>
<Typography>Debug logging</Typography>
<Switch value={isDebugMode} onValueChange={setIsDebugMode} />
</View>
<View style={styles.option}>
<Typography>Toggle Theme</Typography>
<Switch value={scheme === "light"} onValueChange={toggleScheme} />
</View>
<SourceSelect />
</View>
</View>
<View style={styles.option}>
<Typography>Toggle Theme</Typography>
<Switch value={scheme === "light"} onValueChange={toggleScheme} />
</View>
<SourceSelect />
<ViewHistory />
</Screen>
);
Expand Down
3 changes: 3 additions & 0 deletions OwnTube.tv/screens/SettingsScreen/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ export const styles = StyleSheet.create({
gap: 10,
padding: 20,
},
deviceInfoAndToggles: { flexDirection: "row", flexWrap: "wrap", gap: 16, width: "100%" },
option: {
alignItems: "center",
flexDirection: "row",
gap: 5,
},
togglesContainer: { flex: 1, minWidth: 200 },
});
7 changes: 7 additions & 0 deletions OwnTube.tv/utils/common.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { capitalize } from "./common";

describe("capitalize", () => {
it("should capitalize a string", () => {
expect(capitalize("testing")).toBe("Testing");
});
});
4 changes: 4 additions & 0 deletions OwnTube.tv/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export const getThumbnailDimensions = () => {

return { width, height };
};

export const capitalize = (input: string) => {
return input.charAt(0).toUpperCase() + input.slice(1);
};
8 changes: 7 additions & 1 deletion OwnTube.tv/utils/time.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getHumanReadableDuration } from "./time";
import { getHumanReadableDuration, removeSecondsFromISODate } from "./time";

describe("getHumanReadableDuration", () => {
it("should output 40m30s for 2_430_000 ms input", () => {
Expand All @@ -14,3 +14,9 @@ describe("getHumanReadableDuration", () => {
expect(getHumanReadableDuration(undefined)).not.toBe("NaN:NaN");
});
});

describe("removeSecondsFromISODate", () => {
it("should remove seconds from an ISO formatted date", () => {
expect(removeSecondsFromISODate("1970-01-01T00:00:00Z")).toBe("1970-01-01T00:00Z");
});
});
4 changes: 4 additions & 0 deletions OwnTube.tv/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export const getHumanReadableDuration = (ms: number = 0) => {

return hours > 0 ? `${String(hours).padStart(2, "0")}:${mmss}` : mmss;
};

export const removeSecondsFromISODate = (isoDate: string) => {
return `${isoDate.slice(0, isoDate.lastIndexOf(":"))}Z`;
};

0 comments on commit ce29bbb

Please sign in to comment.