-
-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: Persist 'Share as Image' options #1581
base: main
Are you sure you want to change the base?
Changes from all commits
baeb5b0
ae428a1
51f9488
1d08717
de855c4
db6a9e0
29d1410
6f423e3
f4db7a2
a34f6d8
89b9279
775ba47
95dfbb9
e66819e
af78955
e671ed1
1f74e89
3b74aca
e0230b2
c8af557
090983d
badb846
7957aa0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { ShareAsImagePreferences } from "./ShareAsImagePreferences"; | ||
|
||
export const defaultPreferences: ShareAsImagePreferences = { | ||
common: { | ||
hideUsernames: false, | ||
watermark: false, | ||
}, | ||
post: { | ||
hideCommunity: false, | ||
}, | ||
comment: { | ||
includePostContent: false, | ||
includePostDetails: false, | ||
allParentComments: false, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ import { webviewServerUrl } from "#/services/nativeFetch"; | |
|
||
import AddRemoveButtons from "./AddRemoveButtons"; | ||
import { ShareAsImageData } from "./ShareAsImageModal"; | ||
import { useShareAsImagePreferences } from "./ShareAsImagePreferences"; | ||
import Watermark from "./Watermark"; | ||
import includeStyleProperties from "./includeStyleProperties"; | ||
|
||
|
@@ -163,22 +164,28 @@ interface ShareAsImageProps { | |
export default function ShareAsImage({ data, header }: ShareAsImageProps) { | ||
const presentToast = useAppToast(); | ||
|
||
const [hideUsernames, setHideUsernames] = useState(false); | ||
const [hideCommunity, setHideCommunity] = useState(false); | ||
const [includePostDetails, setIncludePostDetails] = useState( | ||
!("comment" in data), | ||
); | ||
Comment on lines
-168
to
-170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aeharding I guess this was the cause of the issue, and its not browser dependent. I tried it in incognito window in edge and its reproducing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I have fixed the issue in my latest commit: let me know if there's anything else |
||
const [includePostText, setIncludePostText] = useState(true); | ||
const [watermark, setWatermark] = useState(false); | ||
|
||
const [blob, setBlob] = useState<Blob | undefined>(); | ||
const [imageSrc, setImageSrc] = useState(""); | ||
|
||
const [minDepth, setMinDepth] = useState( | ||
("comment" in data | ||
const { | ||
shareAsImagePreferences: { | ||
comment: { includePostContent, includePostDetails, allParentComments }, | ||
common: { hideUsernames, watermark }, | ||
post: { hideCommunity }, | ||
}, | ||
setShareAsImagePreferences, | ||
} = useShareAsImagePreferences(); | ||
|
||
const isComment = "comment" in data; | ||
|
||
// eslint-disable-next-line no-nested-ternary | ||
const defaultMinDepth = allParentComments | ||
? 0 | ||
: isComment | ||
? getDepthFromComment(data.comment.comment) | ||
: undefined) ?? 0, | ||
); | ||
: 0; | ||
|
||
const [minDepth, setMinDepth] = useState(defaultMinDepth ?? 0); | ||
|
||
const hasPostBody = data.post.post.body || data.post.post.url; | ||
|
||
|
@@ -191,7 +198,7 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
}, [blob]); | ||
|
||
const filteredComments = (() => { | ||
if (!("comment" in data)) return []; | ||
if (!isComment) return []; | ||
|
||
const filtered = data.comments | ||
.filter( | ||
|
@@ -239,15 +246,15 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
watermark, | ||
hideUsernames, | ||
hideCommunity, | ||
includePostContent, | ||
includePostDetails, | ||
includePostText, | ||
allParentComments, | ||
]); | ||
|
||
async function onShare() { | ||
if (!blob) return; | ||
|
||
const apId = | ||
"comment" in data ? data.comment.comment.ap_id : data.post.post.ap_id; | ||
const apId = isComment ? data.comment.comment.ap_id : data.post.post.ap_id; | ||
|
||
const filename = `${apId | ||
.replace(/^https:\/\//, "") | ||
|
@@ -307,23 +314,31 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
)} | ||
|
||
<StyledIonList inset lines="full"> | ||
{"comment" in data && ( | ||
{isComment && ( | ||
<> | ||
<IonItem> | ||
<IonToggle | ||
checked={includePostDetails} | ||
onIonChange={(e) => setIncludePostDetails(e.detail.checked)} | ||
onIonChange={({ detail: { checked } }) => | ||
setShareAsImagePreferences({ | ||
comment: { includePostDetails: checked }, | ||
}) | ||
} | ||
> | ||
Include Post Details | ||
</IonToggle> | ||
</IonItem> | ||
{includePostDetails && hasPostBody ? ( | ||
{(isComment ? includePostDetails : true) && hasPostBody ? ( | ||
<IonItem> | ||
<IonToggle | ||
checked={includePostText} | ||
onIonChange={(e) => setIncludePostText(e.detail.checked)} | ||
checked={includePostContent} | ||
onIonChange={({ detail: { checked } }) => | ||
setShareAsImagePreferences({ | ||
comment: { includePostContent: checked }, | ||
}) | ||
} | ||
> | ||
Include Post Text | ||
Include Post Content | ||
</IonToggle> | ||
</IonItem> | ||
) : undefined} | ||
|
@@ -341,8 +356,30 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
removeDisabled={ | ||
minDepth === getDepthFromComment(data.comment.comment) | ||
} | ||
onAdd={() => setMinDepth((minDepth) => minDepth - 1)} | ||
onRemove={() => setMinDepth((minDepth) => minDepth + 1)} | ||
onAdd={() => { | ||
setMinDepth((minDepth) => { | ||
const newValue = minDepth - 1; | ||
if (newValue === 0) { | ||
setShareAsImagePreferences({ | ||
comment: { allParentComments: true }, | ||
}); | ||
} | ||
return newValue; | ||
}); | ||
}} | ||
onRemove={() => { | ||
setMinDepth((minDepth) => { | ||
const newValue = minDepth + 1; | ||
if ( | ||
newValue === getDepthFromComment(data.comment.comment) | ||
) { | ||
setShareAsImagePreferences({ | ||
comment: { allParentComments: false }, | ||
}); | ||
} | ||
return newValue; | ||
}); | ||
}} | ||
/> | ||
</ParentCommentValues> | ||
</IonItem> | ||
|
@@ -353,7 +390,9 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
<IonItem> | ||
<IonToggle | ||
checked={hideCommunity} | ||
onIonChange={(e) => setHideCommunity(e.detail.checked)} | ||
onIonChange={({ detail: { checked } }) => | ||
setShareAsImagePreferences({ post: { hideCommunity: checked } }) | ||
} | ||
> | ||
Hide Community | ||
</IonToggle> | ||
|
@@ -362,15 +401,19 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
<IonItem> | ||
<IonToggle | ||
checked={hideUsernames} | ||
onIonChange={(e) => setHideUsernames(e.detail.checked)} | ||
onIonChange={({ detail: { checked } }) => | ||
setShareAsImagePreferences({ common: { hideUsernames: checked } }) | ||
} | ||
> | ||
Hide Usernames | ||
</IonToggle> | ||
</IonItem> | ||
<IonItem lines="none"> | ||
<IonToggle | ||
checked={watermark} | ||
onIonChange={(e) => setWatermark(e.detail.checked)} | ||
onIonChange={({ detail: { checked } }) => | ||
setShareAsImagePreferences({ common: { watermark: checked } }) | ||
} | ||
> | ||
Watermark | ||
</IonToggle> | ||
|
@@ -385,16 +428,16 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { | |
<ShareImageContext.Provider | ||
value={{ capturing: true, hideUsernames, hideCommunity }} | ||
> | ||
{includePostDetails && ( | ||
{(isComment ? includePostDetails : true) && ( | ||
<PostHeader | ||
className={!("comment" in data) ? hideBottomBorderCss : ""} | ||
className={!isComment ? hideBottomBorderCss : ""} | ||
post={data.post} | ||
showPostText={includePostText} | ||
showPostText={isComment ? includePostContent : true} | ||
showPostActions={false} | ||
constrainHeight={false} | ||
/> | ||
)} | ||
{"comment" in data && ( | ||
{isComment && ( | ||
<> | ||
{includePostDetails && <PostCommentSpacer />} | ||
<CommentTree | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,90 @@ | ||||||||||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit"; | ||||||||||||
import { useCallback, useEffect } from "react"; | ||||||||||||
|
||||||||||||
import { DeepPartial } from "#/helpers/deepPartial"; | ||||||||||||
import { db } from "#/services/db"; | ||||||||||||
|
||||||||||||
import { AppDispatch, useAppDispatch, useAppSelector } from "../../../store"; | ||||||||||||
import { defaultPreferences } from "./DefaultPreferences"; | ||||||||||||
|
||||||||||||
export interface ShareAsImagePreferences { | ||||||||||||
common: { | ||||||||||||
hideUsernames: boolean; | ||||||||||||
watermark: boolean; | ||||||||||||
}; | ||||||||||||
post: { | ||||||||||||
hideCommunity: boolean; | ||||||||||||
}; | ||||||||||||
comment: { | ||||||||||||
includePostDetails: boolean; | ||||||||||||
includePostContent: boolean; | ||||||||||||
allParentComments: boolean; | ||||||||||||
}; | ||||||||||||
} | ||||||||||||
|
||||||||||||
const initialState = defaultPreferences; | ||||||||||||
|
||||||||||||
const { reducer, actions } = createSlice({ | ||||||||||||
name: "shareAsImagePreferences", | ||||||||||||
initialState, | ||||||||||||
reducers: { | ||||||||||||
setShareAsImagePreferences: ( | ||||||||||||
state, | ||||||||||||
action: PayloadAction<DeepPartial<ShareAsImagePreferences>>, | ||||||||||||
) => { | ||||||||||||
const { post, comment, common } = action.payload; | ||||||||||||
|
||||||||||||
state.common.hideUsernames = | ||||||||||||
common?.hideUsernames ?? state.common.hideUsernames; | ||||||||||||
state.common.watermark = common?.watermark ?? state.common.watermark; | ||||||||||||
|
||||||||||||
state.post.hideCommunity = | ||||||||||||
post?.hideCommunity ?? state.post.hideCommunity; | ||||||||||||
|
||||||||||||
state.comment.includePostContent = | ||||||||||||
comment?.includePostContent ?? state.comment.includePostContent; | ||||||||||||
state.comment.includePostDetails = | ||||||||||||
comment?.includePostDetails ?? state.comment.includePostDetails; | ||||||||||||
state.comment.allParentComments = | ||||||||||||
comment?.allParentComments ?? state.comment.allParentComments; | ||||||||||||
|
||||||||||||
db.setSetting( | ||||||||||||
"share_as_image_preferences", | ||||||||||||
JSON.parse(JSON.stringify(state)), | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternative to this was
Suggested change
passing |
||||||||||||
); | ||||||||||||
}, | ||||||||||||
}, | ||||||||||||
}); | ||||||||||||
|
||||||||||||
export default reducer; | ||||||||||||
|
||||||||||||
export const useShareAsImagePreferences = () => { | ||||||||||||
const dispatch = useAppDispatch(); | ||||||||||||
|
||||||||||||
useEffect(() => { | ||||||||||||
// Load settings from DB on mount | ||||||||||||
dispatch(async (dispatchImpl: AppDispatch) => { | ||||||||||||
const share_as_image_preferences = await db.getSetting( | ||||||||||||
"share_as_image_preferences", | ||||||||||||
); | ||||||||||||
dispatchImpl( | ||||||||||||
actions.setShareAsImagePreferences( | ||||||||||||
share_as_image_preferences ?? initialState, | ||||||||||||
), | ||||||||||||
); | ||||||||||||
}); | ||||||||||||
}, [dispatch]); | ||||||||||||
|
||||||||||||
const shareAsImagePreferences = useAppSelector( | ||||||||||||
(state) => state.shareAsImagePreferences, | ||||||||||||
); | ||||||||||||
|
||||||||||||
const setShareAsImagePreferences = useCallback( | ||||||||||||
(payload: DeepPartial<ShareAsImagePreferences>) => { | ||||||||||||
dispatch(actions.setShareAsImagePreferences(payload)); | ||||||||||||
}, | ||||||||||||
[dispatch], | ||||||||||||
); | ||||||||||||
|
||||||||||||
return { shareAsImagePreferences, setShareAsImagePreferences }; | ||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export type DeepPartial<T> = { | ||
[P in keyof T]?: T[P] extends Array<infer U> | ||
? Array<DeepPartial<U>> | ||
: T[P] extends ReadonlyArray<infer U> | ||
? ReadonlyArray<DeepPartial<U>> | ||
: DeepPartial<T[P]>; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to have these in a separate file, as I intend to flip some of these values downstream