Compare commits

...

4 Commits

9 changed files with 76 additions and 11 deletions

View File

@ -25,7 +25,7 @@ export default function RevealMedia(props: RevealMediaProps) {
const isMine = props.creator === publicKey;
const hideMedia = preferences.autoLoadMedia === "none" || (!isMine && hideNonFollows);
const hostname = new URL(props.link).hostname;
const lowDataMode = preferences.lowDataMode;
const url = new URL(props.link);
const extension = FileExtensionRegex.test(url.pathname.toLowerCase()) && RegExp.$1;
const type = (() => {
@ -76,7 +76,29 @@ export default function RevealMedia(props: RevealMediaProps) {
/>
</Reveal>
);
} else {
} else if(lowDataMode) {
return (
<Reveal
message={
<FormattedMessage
defaultMessage="Images will not be loaded automatically in low data mode, update <a><i>your preference</i></a> to show media as per your media preference."
id="VfHIx1"
values={{
i: i => <i>{i}</i>,
a: a => <Link to="/settings/preferences">{a}</Link>,
}}
/>
}>
<MediaElement
mime={`${type}/${extension}`}
url={url.toString()}
onMediaClick={props.onMediaClick}
meta={props.meta}
/>
</Reveal>
);
}
else{
return (
<MediaElement
mime={`${type}/${extension}`}

View File

@ -36,6 +36,8 @@ function Grid({ frags }: { frags: Array<TimelineFragment> }) {
}, [allEvents]);
const modalThread = modalThreadIndex !== undefined ? mediaEvents[modalThreadIndex] : undefined;
const nextModalThread = modalThreadIndex !== undefined ? mediaEvents[modalThreadIndex + 1] : undefined;
const prevModalThread = modalThreadIndex !== undefined ? mediaEvents[modalThreadIndex - 1] : undefined;
return (
<>
@ -46,7 +48,7 @@ function Grid({ frags }: { frags: Array<TimelineFragment> }) {
</div>
{modalThread && (
<SpotlightThreadModal
key={modalThreadIndex}
key={modalThread.id}
thread={NostrLink.fromEvent(modalThread)}
onClose={() => setModalThreadIndex(undefined)}
onBack={() => setModalThreadIndex(undefined)}
@ -54,6 +56,20 @@ function Grid({ frags }: { frags: Array<TimelineFragment> }) {
onPrev={() => setModalThreadIndex(Math.max(modalThreadIndex - 1, 0))}
/>
)}
{nextModalThread && ( // preload next
<SpotlightThreadModal
className="hidden"
key={`${nextModalThread.id}-next`}
thread={NostrLink.fromEvent(nextModalThread)}
/>
)}
{prevModalThread && ( // preload previous
<SpotlightThreadModal
className="hidden"
key={`${prevModalThread.id}-prev`}
thread={NostrLink.fromEvent(prevModalThread)}
/>
)}
</>
);
}

View File

@ -60,7 +60,9 @@ export default function Modal(props: ModalProps) {
}, []);
return createPortal(
<div className={`modal${props.className ? ` ${props.className}` : ""}`} onClick={props.onClose}>
<div
className={props.className === "hidden" ? props.className : `modal ${props.className || ""}`}
onClick={props.onClose}>
<div
className={props.bodyClassName || "modal-body"}
onClick={e => {

View File

@ -78,7 +78,7 @@ export function SpotlightMedia(props: SpotlightMediaProps) {
/>
);
} else {
return <ProxyImg src={image} className="max-h-screen max-w-full" />;
return <ProxyImg src={image} className="max-h-screen max-w-full w-full object-contain" />;
}
}, [image, isVideo]);

View File

@ -8,6 +8,7 @@ import getEventMedia from "@/Element/Event/getEventMedia";
interface SpotlightThreadModalProps {
thread: NostrLink;
className?: string;
onClose?: () => void;
onBack?: () => void;
onNext?: () => void;
@ -24,7 +25,7 @@ export function SpotlightThreadModal(props: SpotlightThreadModalProps) {
};
return (
<Modal id="thread-overlay" onClose={onClose} bodyClassName={"flex flex-1"}>
<Modal className={props.className} onClose={onClose} bodyClassName={"flex flex-1"}>
<ThreadContextWrapper link={props.thread}>
<div className="flex flex-row h-screen w-screen">
<div className="flex w-full md:w-2/3 items-center justify-center overflow-hidden" onClick={onClickBg}>

View File

@ -96,6 +96,11 @@ export interface UserPreferences {
* Auto-translate when available
*/
autoTranslate?: boolean;
/**
* Low Data mode - images/reactions wont be loaded
*/
lowDataMode: boolean;
}
export const DefaultPreferences = {
@ -116,4 +121,5 @@ export const DefaultPreferences = {
showStatus: true,
checkSigs: true,
autoTranslate: true,
lowDataMode: false
} as UserPreferences;

View File

@ -122,11 +122,7 @@ export function SnortDeckLayout() {
)}
{deckState.article && (
<>
<Modal
id="thread-overlay-article"
onClose={() => setDeckState({})}
className="thread-overlay long-form"
onClick={() => setDeckState({})}>
<Modal onClose={() => setDeckState({})} className="long-form" onClick={() => setDeckState({})}>
<div onClick={e => e.stopPropagation()}>
<LongFormText ev={deckState.article} isPreview={false} related={[]} />
</div>

View File

@ -497,6 +497,23 @@ const PreferencesPage = () => {
/>
</div>
</div>
<div className="flex justify-between">
<div className="flex flex-col g8">
<h4>
<FormattedMessage {...messages.LowDataMode} />
</h4>
<small>
<FormattedMessage {...messages.LowDataModeHelp} />
</small>
</div>
<div>
<input
type="checkbox"
checked={perf.lowDataMode}
onChange={e => updatePreferences(id, { ...perf, lowDataMode: e.target.checked })}
/>
</div>
</div>
</div>
);
};

View File

@ -76,4 +76,9 @@ export default defineMessages({
ServiceWorkerNotRunning: { defaultMessage: "Service Worker Not Running", id: "RDha9y" },
SubscribedToPush: { defaultMessage: "Subscribed to Push", id: "G3A56c" },
NotSubscribedToPush: { defaultMessage: "Not Subscribed to Push", id: "d2ebEu" },
LowDataMode: { defaultMessage: "Low Data Mode", id: '87tg/I' },
LowDataModeHelp: {
defaultMessage: "Reactions will not be shown on timeline and images would not load automatically",
id: 'Qie1Ef',
},
});