mobile: fix wrapped ui on tablets

This commit is contained in:
Ammar Ahmed
2025-12-12 10:37:56 +05:00
parent d23661c0b8
commit 0ec83fd389
5 changed files with 229 additions and 187 deletions

View File

@@ -324,7 +324,9 @@ export const Signup = ({
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: DefaultAppStyles.GAP,
width: DDS.isTab ? "50%" : "100%",
alignSelf: "center"
}}
>
<Paragraph

View File

@@ -44,6 +44,8 @@ import { useNavigationFocus } from "../../hooks/use-navigation-focus";
import Navigation, { NavigationProps } from "../../services/navigation";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { useSettingStore } from "../../stores/use-setting-store";
import { useStoredRef } from "../../hooks/use-stored-ref";
function formatNumber(num: number) {
if (num >= 1000000) {
@@ -604,7 +606,8 @@ function SummarySlide({
<Slide width={width}>
<ScrollView
contentContainerStyle={{
paddingBottom: 50
paddingBottom: 50,
maxWidth: 500
}}
>
<ViewShot
@@ -652,6 +655,7 @@ function SummarySlide({
>
{Object.keys(stats.monthlyStats).map((item) => (
<View
key={item}
style={{
flexGrow: 1,
alignItems: "center"
@@ -763,6 +767,7 @@ function SummarySlide({
}
].map((item) => (
<View
key={item.title}
style={{
backgroundColor: colors.secondary.background,
padding: DefaultAppStyles.GAP_SMALL,
@@ -905,6 +910,7 @@ function SummarySlide({
type="secondaryAccented"
onPress={async () => {
const path = await viewShotRef.current?.capture?.();
console.log(path, "shared path");
Share.open({
url: path
}).catch(() => {});
@@ -924,9 +930,16 @@ export const Wrapped = ({ navigation, route }: NavigationProps<"Wrapped">) => {
const { width } = useWindowDimensions();
const [loading, setLoading] = useState(true);
const [wrapped, setWrapped] = useState<WrappedStats | null>(null);
const wrappedRef = useStoredRef<WrappedStats | null>(
"wrapped-" + dayjs().year(),
null
);
const [showPresentation, setShowPresentation] = useState(false);
const [messageIndex, setMessageIndex] = useState(0);
const insets = useGlobalSafeAreaInsets();
const dimensions = useSettingStore((state) => state.dimensions);
const [slides, setSlides] = useState<React.ReactNode[]>([]);
useNavigationFocus(navigation, { focusOnInit: true });
useEffect(() => {
let interval: NodeJS.Timeout;
@@ -941,152 +954,102 @@ export const Wrapped = ({ navigation, route }: NavigationProps<"Wrapped">) => {
};
}, [loading]);
async function loadWrapped() {
setLoading(true);
try {
const wrappedData = await db.wrapped.get();
setWrapped(wrappedData);
setShowPresentation(true);
} catch (error) {
console.error("Error loading wrapped:", error);
} finally {
setLoading(false);
}
}
useEffect(() => {
async function loadWrapped() {
setLoading(true);
try {
if (!wrappedRef.current) {
wrappedRef.current = await db.wrapped.get();
console.log("CACHE NOT FOUND");
}
setWrapped(wrappedRef.current);
console.log("WRAP LOADED");
setShowPresentation(true);
setSlides(() => {
const slides: React.ReactNode[] = [];
if (!wrappedRef.current) return [];
const wrapped = wrappedRef.current as WrappedStats;
slides.push(<WelcomeSlide key="welcome" width={width} />);
slides.push(
<TotalNotesSlide
key="total-notes"
count={wrapped.totalNotes}
width={width}
/>
);
if (wrapped.totalWords > 0) {
slides.push(
<TotalWordsSlide
key="total-words"
count={wrapped.totalWords}
width={width}
/>
);
}
if (
wrapped.mostNotesCreatedInMonth ||
wrapped.mostNotesCreatedInDay
) {
slides.push(
<ActivityStatsSlide
key="activity"
mostNotesCreatedInMonth={wrapped.mostNotesCreatedInMonth}
mostNotesCreatedInDay={wrapped.mostNotesCreatedInDay}
width={width}
/>
);
}
// if (wrapped.mostUsedTags && wrapped.mostUsedTags.length > 0) {
// slides.push(
// <MostUsedTagsSlide
// key="tags"
// tags={wrapped.mostUsedTags}
// totalTags={wrapped.totalTags}
// width={width}
// />
// );
// }
// if (wrapped.mostActiveNotebooks && wrapped.mostActiveNotebooks.length > 0) {
// slides.push(
// <MostActiveNotebooksSlide
// key="notebooks"
// notebooks={wrapped.mostActiveNotebooks}
// totalNotebooks={wrapped.totalNotebooks}
// width={width}
// />
// );
// }
// if (wrapped.totalAttachments > 0) {
// slides.push(
// <AttachmentsSlide
// key="attachments"
// totalAttachments={wrapped.totalAttachments}
// totalStorageUsed={wrapped.totalStorageUsed}
// width={width}
// />
// );
// }
slides.push(
<SummarySlide key="summary" stats={wrapped} width={width} />
);
return slides;
});
} catch (error) {
console.error("Error loading wrapped:", error);
} finally {
setLoading(false);
}
}
loadWrapped();
}, []);
// Build slides array
const slides: React.ReactNode[] = [];
if (wrapped && showPresentation) {
slides.push(<WelcomeSlide key="welcome" width={width} />);
slides.push(
<TotalNotesSlide
key="total-notes"
count={wrapped.totalNotes}
width={width}
/>
);
if (wrapped.totalWords > 0) {
slides.push(
<TotalWordsSlide
key="total-words"
count={wrapped.totalWords}
width={width}
/>
);
}
if (wrapped.mostNotesCreatedInMonth || wrapped.mostNotesCreatedInDay) {
slides.push(
<ActivityStatsSlide
key="activity"
mostNotesCreatedInMonth={wrapped.mostNotesCreatedInMonth}
mostNotesCreatedInDay={wrapped.mostNotesCreatedInDay}
width={width}
/>
);
}
// if (wrapped.mostUsedTags && wrapped.mostUsedTags.length > 0) {
// slides.push(
// <MostUsedTagsSlide
// key="tags"
// tags={wrapped.mostUsedTags}
// totalTags={wrapped.totalTags}
// width={width}
// />
// );
// }
// if (wrapped.mostActiveNotebooks && wrapped.mostActiveNotebooks.length > 0) {
// slides.push(
// <MostActiveNotebooksSlide
// key="notebooks"
// notebooks={wrapped.mostActiveNotebooks}
// totalNotebooks={wrapped.totalNotebooks}
// width={width}
// />
// );
// }
// if (wrapped.totalAttachments > 0) {
// slides.push(
// <AttachmentsSlide
// key="attachments"
// totalAttachments={wrapped.totalAttachments}
// totalStorageUsed={wrapped.totalStorageUsed}
// width={width}
// />
// );
// }
slides.push(<SummarySlide key="summary" stats={wrapped} width={width} />);
}
if (showPresentation && wrapped) {
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: colors.primary.background
}}
>
<View
style={{
position: "absolute",
top: insets.top + 5,
right: DefaultAppStyles.GAP,
zIndex: 1000
}}
>
<IconButton
name="close"
color={colors.primary.icon}
type="secondary"
onPress={() => {
setShowPresentation(false);
Navigation.goBack();
}}
/>
</View>
<PolkadotBackground
width={Dimensions.get("window").width}
height={Dimensions.get("window").height}
dotColor={colors.primary.icon}
opacity={0.5}
/>
<SwiperFlatList
autoplay={false}
index={0}
showPagination={true}
paginationActiveColor={colors.primary.accent}
paginationStyleItem={{
width: 10,
height: 5,
marginRight: 4,
marginLeft: 4
}}
paginationDefaultColor={colors.primary.border}
paginationStyle={{
marginBottom: insets.bottom + 12,
backgroundColor: colors.primary.background,
borderRadius: 100,
paddingHorizontal: 12,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
alignItems: "center"
}}
data={slides}
renderItem={({ item }) => item}
/>
</SafeAreaView>
);
}
return (
<SafeAreaView
style={{
@@ -1095,38 +1058,86 @@ export const Wrapped = ({ navigation, route }: NavigationProps<"Wrapped">) => {
}}
>
<PolkadotBackground
width={Dimensions.get("window").width}
height={Dimensions.get("window").height}
dotColor={colors.primary.icon}
opacity={0.5}
width={dimensions.width}
height={dimensions.height}
dotColor={colors.primary.separator}
spacing={40}
opacity={1}
/>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<View
style={{
alignItems: "center",
gap: DefaultAppStyles.GAP_VERTICAL
}}
>
<ActivityIndicator size="large" color={colors.primary.accent} />
<Paragraph
{showPresentation && wrapped ? (
<>
<View
style={{
fontSize: AppFontSize.lg,
textAlign: "center",
color: colors.secondary.paragraph,
marginTop: 20
position: "absolute",
top: insets.top + 5,
right: DefaultAppStyles.GAP,
zIndex: 1000
}}
>
{loadingMessages[messageIndex]}
</Paragraph>
<IconButton
name="close"
color={colors.primary.icon}
type="secondary"
onPress={() => {
setShowPresentation(false);
Navigation.goBack();
}}
/>
</View>
<SwiperFlatList
autoplay={false}
index={0}
showPagination={true}
paginationActiveColor={colors.primary.accent}
paginationStyleItem={{
width: 10,
height: 5,
marginRight: 4,
marginLeft: 4
}}
paginationDefaultColor={colors.primary.border}
paginationStyle={{
marginBottom: insets.bottom + 12,
backgroundColor: colors.primary.background,
borderRadius: 100,
paddingHorizontal: 12,
paddingVertical: DefaultAppStyles.GAP_VERTICAL,
alignItems: "center"
}}
data={slides}
renderItem={({ item }) => item}
/>
</>
) : (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: DefaultAppStyles.GAP
}}
>
<View
style={{
alignItems: "center",
gap: DefaultAppStyles.GAP_VERTICAL
}}
>
<ActivityIndicator size="large" color={colors.primary.accent} />
<Paragraph
style={{
fontSize: AppFontSize.lg,
textAlign: "center",
color: colors.secondary.paragraph,
marginTop: 20
}}
>
{loadingMessages[messageIndex]}
</Paragraph>
</View>
</View>
</View>
)}
</SafeAreaView>
);
};
@@ -1134,10 +1145,10 @@ export const Wrapped = ({ navigation, route }: NavigationProps<"Wrapped">) => {
export function PolkadotBackground({
width,
height,
spacing = 20,
spacing = 50,
dotSize = 3,
dotColor = "#E5E5E5",
opacity = 0.3
dotColor = "#ececec",
opacity = 0.1
}: {
width: number;
height: number;
@@ -1162,6 +1173,7 @@ export function PolkadotBackground({
opacity: opacity
}
]}
pointerEvents="none"
>
{Array.from({ length: rows }).map((_, row) =>
Array.from({ length: cols }).map((_, col) => (
@@ -1175,7 +1187,7 @@ export function PolkadotBackground({
height: dotSize,
borderRadius: dotSize / 2,
backgroundColor: dotColor,
opacity: 0.3
opacity: 1
}}
/>
))
@@ -1184,8 +1196,4 @@ export function PolkadotBackground({
);
}
const styles = StyleSheet.create({
container: { overflow: "hidden", position: "absolute" }
});
export default Wrapped;

View File

@@ -1104,7 +1104,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1210,7 +1210,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1379,7 +1379,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1423,7 +1423,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1534,7 +1534,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1647,7 +1647,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
MARKETING_VERSION = "3.3.10";
MARKETING_VERSION = 3.3.10;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -2246,6 +2246,34 @@ PODS:
- Yoga
- react-native-upload (6.28.0):
- React
- react-native-view-shot (4.0.3):
- boost
- DoubleConversion
- fast_float
- fmt
- glog
- hermes-engine
- RCT-Folly
- RCT-Folly/Fabric
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-webview (13.16.0):
- boost
- DoubleConversion
@@ -3465,6 +3493,7 @@ DEPENDENCIES:
- "react-native-sodium (from `../node_modules/@ammarahmed/react-native-sodium`)"
- react-native-theme-switch-animation (from `../node_modules/react-native-theme-switch-animation`)
- "react-native-upload (from `../node_modules/@ammarahmed/react-native-upload`)"
- react-native-view-shot (from `../node_modules/react-native-view-shot`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
@@ -3680,6 +3709,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-theme-switch-animation"
react-native-upload:
:path: "../node_modules/@ammarahmed/react-native-upload"
react-native-view-shot:
:path: "../node_modules/react-native-view-shot"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-NativeModulesApple:
@@ -3881,6 +3912,7 @@ SPEC CHECKSUMS:
react-native-sodium: 066f76e46c9be13e9260521e3fa994937c4cdab4
react-native-theme-switch-animation: 449d6db7a760f55740505e7403ae8061debc9a7e
react-native-upload: ddf12a152c62fcafa202ef0404d3d46333a6a6a6
react-native-view-shot: 6c008e58f4720de58370848201c5d4a082c6d4ca
react-native-webview: 654f794a7686b47491cf43aa67f7f428bea00eed
React-NativeModulesApple: 46690a0fe94ec28fc6fc686ec797b911d251ded0
React-oscompat: 95875e81f5d4b3c7b2c888d5bd2c9d83450d8bdb

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "3.3.10-beta.4",
"version": "3.3.10-beta.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.3.10-beta.4",
"version": "3.3.10-beta.5",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {