Skip to content
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

Nag users to shill Duolicious #492

Merged
merged 1 commit into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 269 additions & 2 deletions components/donation-nag-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,95 @@
import {
Animated,
Linking,
Modal,
Platform,
View,
} from 'react-native';
import {
useState,
useEffect,
useRef,
useState,
} from 'react';
import { DefaultText } from './default-text';
import { ButtonWithCenteredText } from './button/centered-text';
import { signedInUser } from '../App';
import { api } from '../api/api';
import { getRandomElement } from '../util/util';

const gagLocations = [
'/a/',
'/adv/',
'/r9k/',
'/v/',
'@tinder on Twitter',
'Bronies Anonymous',
'Pornhub gooners',
'Quora',
'Re**it',
'a 3-viewer Twitch chat',
'a mongolian basket weaving forum',
'a telemarketer',
'a televangelist hotline',
'annual cheese rolling event-goers',
'boomers on Facebook',
'cabal of BPD-having besties 😊',
'chat',
'goth girls at the local cemetery',
'jehovah’s witnesses',
'my Ao3 readers',
'my Discord server',
'my Fortnite squad',
'my Hinge matches',
'my Letterboxd review readers',
'my LinkedIn connections',
'my Rabbi',
'my TikTok followers',
'my Tinder date',
'my Twitch followers',
'my Twitter oomfies',
'my YouTube subscribers',
'my autism support group',
'my body pillow',
'my church',
'my colleagues',
'my cosplay convention',
'my doctor',
'my drunk uncle at Thanksgiving',
'my femboy oomfies',
'my flat earth society gathering',
'my furry convention',
'my grandmother’s ghost',
'my imaginary friend',
'my local renaissance faire',
'my mom',
'my parole officer',
'my priest',
'my silent meditation retreat',
'my sleep paralysis demon',
'my tax agent',
'my therapist',
'my weeb friends',
'my wife’s boyfriend',
'r/TwoXChromosomes',
'r/UnexpectedJoJo',
'r/bumble',
'r/greentext',
'r/wallstreetbets',
'some gooners',
'the NSA agent monitoring me',
'the Neopets Revival Discord',
'the Wendy’s drive-thru',
'the antique typewriter convention',
'the comic-con',
'the fediverse',
'the guy using the urinal next to mine',
'the guy who hands out samples at Costco',
'the guy who sells me vape juice',
'the hand cuz the face ain’t listening',
'the homeless gentleman outside my apartment',
'the voices in my head',
'you want I want, what I really really want',
];

const DonationNagModal = () => {
const name = signedInUser?.name;
Expand All @@ -31,7 +109,18 @@ const DonationNagModal = () => {
}
};

const DonationNagModalWeb = ({
const DonationNagModalWeb = (props: {
name: string
estimatedEndDate: Date
}) => {
if (Math.random() > 0.5) {
return <MonetaryDonationNagModalWeb {...props} />
} else {
return <MarketingDonationNagModalWeb {...props} />
}
};

const MonetaryDonationNagModalWeb = ({
name,
estimatedEndDate,
}: {
Expand Down Expand Up @@ -160,6 +249,184 @@ const DonationNagModalWeb = ({
);
};

const MarketingDonationNagModalWeb = ({
name,
estimatedEndDate,
}: {
name: string
estimatedEndDate: Date
}) => {
const [gagLocation, setGagLocation] = useState(getRandomElement(gagLocations));
const [isVisible, setIsVisible] = useState(true);
const opacity = useRef(new Animated.Value(1)).current;

useEffect(() => {
// Function to pick a random location with cross-fade animation
const pickRandomLocation = () => {
// Fade out the current text
Animated.timing(opacity, {
toValue: 0,
duration: 300, // Duration of fade-out
useNativeDriver: true,
}).start(() => {
// After fade-out completes, update the location
const randomIndex = Math.floor(Math.random() * gagLocations.length);
setGagLocation(gagLocations[randomIndex]);

// Fade in the new text
Animated.timing(opacity, {
toValue: 1,
duration: 300, // Duration of fade-in
useNativeDriver: true,
}).start();
});
};

const intervalId = setInterval(pickRandomLocation, 3000);

// Cleanup interval on component unmount
return () => clearInterval(intervalId);
}, [opacity]);

const onPressButton = () => {
setIsVisible(false);
api('post', '/dismiss-donation');
};

return (
<Modal
animationType="fade"
transparent={true}
visible={isVisible}
statusBarTranslucent={true}
>
<View
style={{
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
}}
>
<View
style={{
flex: 1,
maxWidth: 600,
margin: 10,
backgroundColor: 'white',
borderRadius: 5,
flexDirection: 'column',
overflow: 'hidden',
}}
>
<View
style={{
backgroundColor: '#70f',
padding: 10,
gap: 10,
}}
>
<DefaultText
style={{
fontSize: 22,
fontWeight: 900,
textAlign: 'center',
color: 'white',
}}
>
Attention all terminally online degenerates!
</DefaultText>

<View
style={{
opacity: 0.9,
gap: 10,
}}
>
<DefaultText
style={{
color: 'white',
textAlign: 'center',
}}
>
Want Duolicious to stay free? You’re gonna need to do some shilling...
</DefaultText>
</View>
</View>

<View
style={{
gap: 10,
paddingHorizontal: 10,
paddingVertical: 20,
}}
>
<DefaultText
style={{
textAlign: 'center',
}}
>
Shilling is what brought us all here. But Duolicious’ choice to
be 100% free and volunteer-run means we can’t afford paid shills
like big apps can. That means {}
<DefaultText style={{ fontWeight: '700' }} >
edgy shitposters like you
</DefaultText>
{} need to shill Duolicious to keep the new members coming. {}
<DefaultText style={{ fontWeight: '700' }} >
Please mention us wherever you lurk.
</DefaultText>
</DefaultText>
</View>

<View
style={{
padding: 10,
paddingTop: 0,
}}
>
<ButtonWithCenteredText
onPress={onPressButton}
extraChildren={
<Animated.View
style={{
opacity: opacity,
}}
>
<DefaultText
style={{
fontWeight: '700',
color: 'white',
fontSize: 16,
textAlign: 'center',
paddingHorizontal: 10,
}}
>
Ok, I’ll tell {gagLocation}
</DefaultText>
</Animated.View>
}
/>

<ButtonWithCenteredText
onPress={onPressButton}
secondary={true}
textStyle={{
fontWeight: '700',
paddingHorizontal: 10,
}}
>
Just plaster this shithole with ads already
</ButtonWithCenteredText>
</View>
</View>
</View>
</Modal>
);
};

const DonationNagModalMobile = ({
name,
estimatedEndDate,
Expand Down
6 changes: 6 additions & 0 deletions util/util.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ const secToMinSec = (sec: number): [string, string] => {
return [minutes, seconds];
};

const getRandomElement = <T,>(list: T[]): T | undefined =>
list.length === 0 ?
undefined :
list[Math.floor(Math.random() * list.length)];

export {
compareArrays,
delay,
Expand All @@ -139,4 +144,5 @@ export {
possessive,
secToMinSec,
withTimeout,
getRandomElement,
};
Loading