33 ActivityIndicator ,
44 Alert ,
55 Linking ,
6+ Pressable ,
67 ScrollView ,
78 StyleSheet ,
89 Text ,
@@ -39,8 +40,20 @@ import {
3940 listFolders ,
4041 renameFolder ,
4142} from '../src/services/foldersRepo' ;
43+ import {
44+ recordReviewSignal ,
45+ requestReviewAfterPositiveMoment ,
46+ } from '../src/services/reviewPromptService' ;
4247import type { BackgroundType , FolderMetadata , NoteMetadata } from '../src/types/note' ;
4348
49+ const LEGAL_URLS = {
50+ privacy : 'https://mathnotes-app.github.io/OpenNotes/privacy/' ,
51+ terms : 'https://mathnotes-app.github.io/OpenNotes/terms/' ,
52+ support : 'https://mathnotes-app.github.io/OpenNotes/support/' ,
53+ github : 'https://github.com/mathnotes-app/OpenNotes' ,
54+ x : 'https://x.com/markpm39' ,
55+ } ;
56+
4457type Action =
4558 | { kind : 'newItem' }
4659 | { kind : 'about' }
@@ -78,6 +91,7 @@ export default function LibraryScreen() {
7891 useFocusEffect (
7992 useCallback ( ( ) => {
8093 void refresh ( ) ;
94+ void requestReviewAfterPositiveMoment ( ) ;
8195 } , [ refresh ] ) ,
8296 ) ;
8397
@@ -103,6 +117,7 @@ export default function LibraryScreen() {
103117 const openNote = useCallback (
104118 ( id : string ) => {
105119 void Haptics . selectionAsync ( ) ;
120+ void recordReviewSignal ( 'note_opened' ) ;
106121 router . push ( `/note/${ id } ` ) ;
107122 } ,
108123 [ router ] ,
@@ -127,12 +142,16 @@ export default function LibraryScreen() {
127142 backgroundType,
128143 title : title . trim ( ) || undefined ,
129144 } ) ;
145+ void recordReviewSignal ( 'note_created' ) ;
130146 openNote ( meta . id ) ;
131147 return ;
132148 }
133149
134150 const meta = await createPdfNoteFromPicker ( { folderId : null , title } ) ;
135- if ( meta ) openNote ( meta . id ) ;
151+ if ( meta ) {
152+ void recordReviewSignal ( 'note_created' ) ;
153+ openNote ( meta . id ) ;
154+ }
136155 } catch ( error ) {
137156 if ( __DEV__ ) console . warn ( '[LibraryScreen] create note failed' , error ) ;
138157 Alert . alert ( 'Could not create note' , 'Please try again.' ) ;
@@ -233,13 +252,13 @@ export default function LibraryScreen() {
233252 key : 'github' ,
234253 icon : 'logo-github' ,
235254 accessibilityLabel : 'Open OpenNotes on GitHub' ,
236- onPress : ( ) => void openUrl ( 'https://github.com/mathnotes-app/OpenNotes' ) ,
255+ onPress : ( ) => void openUrl ( LEGAL_URLS . github ) ,
237256 } ,
238257 {
239258 key : 'x' ,
240259 icon : 'logo-x' ,
241260 accessibilityLabel : 'Open Mark Miller on X' ,
242- onPress : ( ) => void openUrl ( 'https://x.com/markpm39' ) ,
261+ onPress : ( ) => void openUrl ( LEGAL_URLS . x ) ,
243262 } ,
244263 {
245264 key : 'about' ,
@@ -471,6 +490,14 @@ function AboutSheet({
471490 onClose : ( ) => void ;
472491} ) {
473492 const theme = useTheme ( ) ;
493+ const openUrl = useCallback ( async ( url : string ) => {
494+ try {
495+ await Linking . openURL ( url ) ;
496+ } catch ( error ) {
497+ if ( __DEV__ ) console . warn ( '[AboutSheet] open link failed' , error ) ;
498+ Alert . alert ( 'Could not open link' , 'Please try again.' ) ;
499+ }
500+ } , [ ] ) ;
474501
475502 return (
476503 < Sheet visible = { visible } onClose = { onClose } >
@@ -506,10 +533,34 @@ function AboutSheet({
506533 < Text style = { [ typography . footnote , styles . aboutBody , { color : theme . colors . textSecondary } ] } >
507534 OpenNotes is powered by the open source Mobile Ink engine.
508535 </ Text >
536+ < View style = { styles . aboutLinks } >
537+ < AboutLink label = "Privacy" onPress = { ( ) => void openUrl ( LEGAL_URLS . privacy ) } />
538+ < AboutLink label = "Terms" onPress = { ( ) => void openUrl ( LEGAL_URLS . terms ) } />
539+ < AboutLink label = "Support" onPress = { ( ) => void openUrl ( LEGAL_URLS . support ) } />
540+ </ View >
509541 </ Sheet >
510542 ) ;
511543}
512544
545+ function AboutLink ( { label, onPress } : { label : string ; onPress : ( ) => void } ) {
546+ const theme = useTheme ( ) ;
547+ return (
548+ < Pressable
549+ accessibilityRole = "link"
550+ onPress = { onPress }
551+ style = { ( { pressed } ) => [
552+ styles . aboutLink ,
553+ { borderColor : theme . colors . divider } ,
554+ pressed && { opacity : 0.65 } ,
555+ ] }
556+ >
557+ < Text style = { [ typography . callout , styles . aboutLinkText , { color : theme . colors . accent } ] } >
558+ { label }
559+ </ Text >
560+ </ Pressable >
561+ ) ;
562+ }
563+
513564function Section ( {
514565 title,
515566 theme,
@@ -581,4 +632,21 @@ const styles = StyleSheet.create({
581632 lineHeight : 22 ,
582633 marginBottom : spacing . md ,
583634 } ,
635+ aboutLinks : {
636+ flexDirection : 'row' ,
637+ flexWrap : 'wrap' ,
638+ gap : spacing . sm ,
639+ marginTop : spacing . xs ,
640+ } ,
641+ aboutLink : {
642+ alignItems : 'center' ,
643+ borderRadius : 16 ,
644+ borderWidth : StyleSheet . hairlineWidth ,
645+ minHeight : 34 ,
646+ justifyContent : 'center' ,
647+ paddingHorizontal : spacing . md ,
648+ } ,
649+ aboutLinkText : {
650+ fontWeight : '600' ,
651+ } ,
584652} ) ;
0 commit comments