Keep things more consistent with deer-social/social-app, make images higher quality in more places, re-add direct quote fetching, fix some icons, and make some more tweaks.
···77- Stay away from PRs like...
78 - Changing "Post" to "Skeet."
79 - Refactoring the codebase, e.g., to replace React Query with Redux Toolkit or something.
80- - Adding entirely new features without prior discussion.
8182If we don't merge your PR for whatever reason, you are welcome to fork and/or self host:
83
···77- Stay away from PRs like...
78 - Changing "Post" to "Skeet."
79 - Refactoring the codebase, e.g., to replace React Query with Redux Toolkit or something.
80+- Include a new toggle and preference for your feature.
8182If we don't merge your PR for whatever reason, you are welcome to fork and/or self host:
83
+1-1
src/Navigation.tsx
···88import {AppIconSettingsScreen} from '#/screens/Settings/AppIconSettings'
89import {AppPasswordsScreen} from '#/screens/Settings/AppPasswords'
90import {ContentAndMediaSettingsScreen} from '#/screens/Settings/ContentAndMediaSettings'
091import {ExternalMediaPreferencesScreen} from '#/screens/Settings/ExternalMediaPreferences'
92import {FollowingFeedPreferencesScreen} from '#/screens/Settings/FollowingFeedPreferences'
93import {InterestsSettingsScreen} from '#/screens/Settings/InterestsSettings'
···109} from '#/components/dialogs/EmailDialog'
110import {router} from '#/routes'
111import {Referrer} from '../modules/expo-bluesky-swiss-army'
112-import {DeerSettingsScreen} from './screens/Settings/DeerSettings'
113import {LegacyNotificationSettingsScreen} from './screens/Settings/LegacyNotificationSettings'
114import {NotificationSettingsScreen} from './screens/Settings/NotificationSettings'
115import {LikeNotificationSettingsScreen} from './screens/Settings/NotificationSettings/LikeNotificationSettings'
···88import {AppIconSettingsScreen} from '#/screens/Settings/AppIconSettings'
89import {AppPasswordsScreen} from '#/screens/Settings/AppPasswords'
90import {ContentAndMediaSettingsScreen} from '#/screens/Settings/ContentAndMediaSettings'
91+import {DeerSettingsScreen} from '#/screens/Settings/DeerSettings'
92import {ExternalMediaPreferencesScreen} from '#/screens/Settings/ExternalMediaPreferences'
93import {FollowingFeedPreferencesScreen} from '#/screens/Settings/FollowingFeedPreferences'
94import {InterestsSettingsScreen} from '#/screens/Settings/InterestsSettings'
···110} from '#/components/dialogs/EmailDialog'
111import {router} from '#/routes'
112import {Referrer} from '../modules/expo-bluesky-swiss-army'
0113import {LegacyNotificationSettingsScreen} from './screens/Settings/LegacyNotificationSettings'
114import {NotificationSettingsScreen} from './screens/Settings/NotificationSettings'
115import {LikeNotificationSettingsScreen} from './screens/Settings/NotificationSettings/LikeNotificationSettings'
···35import {toShareUrl} from '#/lib/strings/url-helpers'
36import {getTranslatorLink} from '#/locale/helpers'
37import {logger} from '#/logger'
38-import {isWeb} from '#/platform/detection'
39import {type Shadow} from '#/state/cache/post-shadow'
40import {useProfileShadow} from '#/state/cache/profile-shadow'
41import {useFeedFeedbackContext} from '#/state/feed-feedback'
···35import {toShareUrl} from '#/lib/strings/url-helpers'
36import {getTranslatorLink} from '#/locale/helpers'
37import {logger} from '#/logger'
038import {type Shadow} from '#/state/cache/post-shadow'
39import {useProfileShadow} from '#/state/cache/profile-shadow'
40import {useFeedFeedbackContext} from '#/state/feed-feedback'
···1import React from 'react'
2import EventEmitter from 'eventemitter3'
34-import {networkRetry} from '#/lib/async/retry'
5import {logger} from '#/logger'
6import {type Device, device} from '#/storage'
7···27 countryCode: 'US',
28}
2930-async function getGeolocation(): Promise<Device['geolocation']> {
31- const res = await fetch(`https://bsky.app/ipcc`)
32-33- if (!res.ok) {
34- throw new Error(`geolocation: lookup failed ${res.status}`)
35- }
36-37- const json = await res.json()
38-39- if (json.countryCode) {
40- return {
41- countryCode: json.countryCode,
42- }
43- } else {
44- return undefined
45- }
46-}
47-48/**
49 * Local promise used within this file only.
50 */
···64 * In dev, IP server is unavailable, so we just set the default geolocation
65 * and fail closed.
66 */
67- if (__DEV__) {
68- geolocationResolution = new Promise(y => y({success: true}))
69 device.set(['geolocation'], DEFAULT_GEOLOCATION)
70 }
71}
7273-geolocationResolution = new Promise(async resolve => {
74- let success = true
75-76- try {
77- // Try once, fail fast
78- const geolocation = await getGeolocation()
79- if (geolocation) {
80- device.set(['geolocation'], geolocation)
81- emitGeolocationUpdate(geolocation)
82- logger.debug(`geolocation: success`, {geolocation})
83- } else {
84- // endpoint should throw on all failures, this is insurance
85- throw new Error(`geolocation: nothing returned from initial request`)
86- }
87- } catch (e: any) {
88- success = false
89-90- logger.debug(`geolocation: failed initial request`, {
91- safeMessage: e.message,
92- })
93-94- // set to default
95- device.set(['geolocation'], DEFAULT_GEOLOCATION)
96-97- // retry 3 times, but don't await, proceed with default
98- networkRetry(3, getGeolocation)
99- .then(geolocation => {
100- if (geolocation) {
101- device.set(['geolocation'], geolocation)
102- emitGeolocationUpdate(geolocation)
103- logger.debug(`geolocation: success`, {geolocation})
104- success = true
105- } else {
106- // endpoint should throw on all failures, this is insurance
107- throw new Error(`geolocation: nothing returned from retries`)
108- }
109- })
110- .catch((e: any) => {
111- // complete fail closed
112- logger.debug(`geolocation: failed retries`, {safeMessage: e.message})
113- })
114- } finally {
115- resolve({success})
116- }
117-})
118119/**
120 * Ensure that geolocation has been resolved, or at the very least attempted
···1import React from 'react'
2import EventEmitter from 'eventemitter3'
304import {logger} from '#/logger'
5import {type Device, device} from '#/storage'
6···26 countryCode: 'US',
27}
2800000000000000000029/**
30 * Local promise used within this file only.
31 */
···45 * In dev, IP server is unavailable, so we just set the default geolocation
46 * and fail closed.
47 */
48+ geolocationResolution = new Promise(y => y({success: true}))
49+ if (device.get(['geolocation']) == undefined) {
50 device.set(['geolocation'], DEFAULT_GEOLOCATION)
51 }
52}
5354+export function setGeolocation(geolocation: Device['geolocation']) {
55+ device.set(['geolocation'], geolocation)
56+ emitGeolocationUpdate(geolocation)
57+}
000000000000000000000000000000000000000005859/**
60 * Ensure that geolocation has been resolved, or at the very least attempted