mirror of
https://github.com/tooot-app/app
synced 2024-12-26 09:23:56 +01:00
Test development branch
This commit is contained in:
parent
1f4108c2d4
commit
c46888acab
27
.envrc.example
Normal file
27
.envrc.example
Normal file
@ -0,0 +1,27 @@
|
||||
export TOOOT_ENVIRONMENT=""
|
||||
|
||||
export SENTRY_ORGANIZATION=""
|
||||
export SENTRY_PROJECT=""
|
||||
export SENTRY_AUTH_TOKEN=""
|
||||
export SENTRY_DSN=""
|
||||
|
||||
# Fastlane start
|
||||
export LC_ALL=""
|
||||
export LANG=""
|
||||
|
||||
export FASTLANE_USER=""
|
||||
|
||||
export MATCH_PASSWORD=""
|
||||
export MATCH_GIT_URL=""
|
||||
export MATCH_GIT_BASIC_AUTHORIZATION=""
|
||||
|
||||
export APP_STORE_CONNECT_API_KEY_KEY_ID=""
|
||||
export APP_STORE_CONNECT_API_KEY_ISSUER_ID=""
|
||||
export APP_STORE_CONNECT_API_KEY_KEY=""
|
||||
|
||||
export ANDROID_KEYSTORE=""
|
||||
export ANDROID_KEYSTORE_PASSWORD=""
|
||||
export ANDROID_KEYSTORE_ALIAS=""
|
||||
export ANDROID_KEYSTORE_KEY_PASSWORD=""
|
||||
export SUPPLY_JSON_KEY_DATA=""
|
||||
# Fastlane end
|
50
.github/workflows/development.yml
vendored
Normal file
50
.github/workflows/development.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: Build development
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- development
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: -- Step 1 -- Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: -- Step 2 -- Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
- name: -- Step 3 -- Use Expo action
|
||||
uses: expo/expo-github-action@v5
|
||||
with:
|
||||
expo-version: 4.x
|
||||
expo-username: ${{ secrets.EXPO_USERNAME }}
|
||||
expo-token: ${{ secrets.EXPO_TOKEN }}
|
||||
- name: -- Step 4 -- Install node dependencies
|
||||
run: yarn install
|
||||
- name: -- Step 5 -- Install native dependencies
|
||||
run: npx pod-install
|
||||
- name: -- Step 6 -- Install ruby dependencies
|
||||
run: bundle install
|
||||
- name: -- Step 7 -- Run fastlane
|
||||
env:
|
||||
TOOOT_ENVIRONMENT: development
|
||||
SENTRY_ORGANIZATION: ${{ secrets.SENTRY_ORGANIZATION }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
|
||||
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
|
||||
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
|
||||
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
|
||||
ANDROID_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE }}
|
||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
|
||||
ANDROID_KEYSTORE_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_KEY_PASSWORD }}
|
||||
SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }}
|
||||
FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: yarn app:build
|
@ -15,7 +15,7 @@ case ENVIRONMENT
|
||||
when "development"
|
||||
GITHUB_RELEASE= ""
|
||||
when "staging"
|
||||
GITHUB_RELEASE = "v#{VERSION}(#{BUILD_NUMBER})"
|
||||
GITHUB_RELEASE = "v#{VERSION}-rc#{VERSIONS[:patch]}"
|
||||
when "production"
|
||||
GITHUB_RELEASE = "v#{VERSION}"
|
||||
end
|
||||
@ -44,20 +44,14 @@ private_lane :prepare_playstore_android do
|
||||
end
|
||||
|
||||
desc "Create new GitHub release"
|
||||
private_lane :github_release do
|
||||
case ENVIRONMENT
|
||||
when "staging"
|
||||
is_prerelease = true
|
||||
when "production"
|
||||
is_prerelease = false
|
||||
end
|
||||
private_lane :github_release do |options|
|
||||
set_github_release(
|
||||
repository_name: GITHUB_REPO,
|
||||
name: GITHUB_RELEASE,
|
||||
tag_name: GITHUB_RELEASE,
|
||||
description: "No changelog provided",
|
||||
commitish: git_branch,
|
||||
is_prerelease: is_prerelease
|
||||
is_prerelease: options[:prerelease]
|
||||
)
|
||||
end
|
||||
|
||||
@ -76,8 +70,10 @@ private_lane :build_ios do
|
||||
case ENVIRONMENT
|
||||
when "development"
|
||||
match( type: "development", readonly: true )
|
||||
build_ios_app( export_method: "development", output_directory: BUILD_DIRECTORY, output_name: "#{VERSION}-#{BUILD_NUMBER}" )
|
||||
install_on_device( skip_wifi: true )
|
||||
if !is_ci
|
||||
build_ios_app( export_method: "development", output_directory: BUILD_DIRECTORY )
|
||||
install_on_device( skip_wifi: true )
|
||||
end
|
||||
when "staging"
|
||||
prepare_appstore_ios
|
||||
match( type: "appstore", readonly: true )
|
||||
@ -101,14 +97,16 @@ private_lane :build_android do
|
||||
|
||||
case ENVIRONMENT
|
||||
when "development"
|
||||
build_android_app(
|
||||
task: 'assemble',
|
||||
build_type: 'debug',
|
||||
project_dir: "./android"
|
||||
)
|
||||
adb(
|
||||
command: "install #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]}"
|
||||
)
|
||||
if !is_ci
|
||||
build_android_app(
|
||||
task: 'assemble',
|
||||
build_type: 'debug',
|
||||
project_dir: "./android"
|
||||
)
|
||||
adb(
|
||||
command: "install #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]}"
|
||||
)
|
||||
end
|
||||
when "staging"
|
||||
prepare_playstore_android
|
||||
build_android_app(
|
||||
@ -127,7 +125,7 @@ private_lane :build_android do
|
||||
}
|
||||
)
|
||||
upload_to_play_store(
|
||||
track: "alpha",
|
||||
track: "beta",
|
||||
skip_upload_metadata: true,
|
||||
skip_upload_changelogs: true,
|
||||
skip_upload_images: true,
|
||||
@ -147,9 +145,9 @@ lane :build do
|
||||
build_android
|
||||
case ENVIRONMENT
|
||||
when "staging"
|
||||
github_release
|
||||
github_release(prerelease: true)
|
||||
when "production"
|
||||
github_release
|
||||
github_release(prerelease: false)
|
||||
end
|
||||
end
|
||||
expo_release
|
||||
|
@ -112,7 +112,7 @@
|
||||
"native": "210201",
|
||||
"major": 0,
|
||||
"minor": 3,
|
||||
"patch": 0,
|
||||
"patch": 1,
|
||||
"expo": "40.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
import Button from '@components/Button'
|
||||
import haptics from '@components/haptics'
|
||||
import Icon from '@components/Icon'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { useAppsQuery } from '@utils/queryHooks/apps'
|
||||
import { useInstanceQuery } from '@utils/queryHooks/instance'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { getLocalInstances, remoteUpdate } from '@utils/slices/instancesSlice'
|
||||
import { getLocalInstances } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
@ -13,39 +10,30 @@ import { debounce } from 'lodash'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert, Image, StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
import { useQueryClient } from 'react-query'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { Placeholder, Fade } from 'rn-placeholder'
|
||||
import analytics from './analytics'
|
||||
import InstanceAuth from './Instance/Auth'
|
||||
import EULA from './Instance/EULA'
|
||||
import InstanceInfo from './Instance/Info'
|
||||
import { toast } from './toast'
|
||||
|
||||
export interface Props {
|
||||
type: 'local' | 'remote'
|
||||
disableHeaderImage?: boolean
|
||||
goBack?: boolean
|
||||
}
|
||||
|
||||
const ComponentInstance: React.FC<Props> = ({
|
||||
type,
|
||||
disableHeaderImage,
|
||||
goBack = false
|
||||
}) => {
|
||||
const { t, i18n } = useTranslation('componentInstance')
|
||||
const { t } = useTranslation('componentInstance')
|
||||
const { theme } = useTheme()
|
||||
const navigation = useNavigation()
|
||||
|
||||
const localInstances = useSelector(getLocalInstances)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const [instanceDomain, setInstanceDomain] = useState<string>()
|
||||
|
||||
const instanceQuery = useInstanceQuery({
|
||||
instanceDomain,
|
||||
checkPublic: type === 'remote',
|
||||
options: { enabled: false, retry: false }
|
||||
})
|
||||
const appsQuery = useAppsQuery({
|
||||
@ -70,46 +58,30 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
|
||||
const processUpdate = useCallback(() => {
|
||||
if (instanceDomain) {
|
||||
switch (type) {
|
||||
case 'local':
|
||||
analytics('instance_local_login')
|
||||
if (
|
||||
localInstances &&
|
||||
localInstances.filter(instance => instance.url === instanceDomain)
|
||||
.length
|
||||
) {
|
||||
Alert.alert(
|
||||
t('update.local.alert.title'),
|
||||
t('update.local.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t('update.local.alert.buttons.cancel'),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t('update.local.alert.buttons.continue'),
|
||||
onPress: () => {
|
||||
appsQuery.refetch()
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
} else {
|
||||
appsQuery.refetch()
|
||||
}
|
||||
break
|
||||
case 'remote':
|
||||
analytics('instance_remote_register')
|
||||
haptics('Success')
|
||||
const queryKey: QueryKeyTimeline = [
|
||||
'Timeline',
|
||||
{ page: 'RemotePublic' }
|
||||
analytics('instance_local_login')
|
||||
if (
|
||||
localInstances &&
|
||||
localInstances.filter(instance => instance.url === instanceDomain)
|
||||
.length
|
||||
) {
|
||||
Alert.alert(
|
||||
t('update.local.alert.title'),
|
||||
t('update.local.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t('update.local.alert.buttons.cancel'),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t('update.local.alert.buttons.continue'),
|
||||
onPress: () => {
|
||||
appsQuery.refetch()
|
||||
}
|
||||
}
|
||||
]
|
||||
dispatch(remoteUpdate(instanceDomain))
|
||||
queryClient.resetQueries(queryKey)
|
||||
toast({ type: 'success', message: t('update.remote.succeed') })
|
||||
navigation.goBack()
|
||||
break
|
||||
)
|
||||
} else {
|
||||
appsQuery.refetch()
|
||||
}
|
||||
}
|
||||
}, [instanceDomain])
|
||||
@ -129,15 +101,6 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
[instanceDomain, instanceQuery.isSuccess, instanceQuery.data]
|
||||
)
|
||||
|
||||
const buttonContent = useMemo(() => {
|
||||
switch (type) {
|
||||
case 'local':
|
||||
return t('server.button.local')
|
||||
case 'remote':
|
||||
return t('server.button.remote')
|
||||
}
|
||||
}, [i18n.language])
|
||||
|
||||
const requestAuth = useMemo(() => {
|
||||
if (
|
||||
instanceDomain &&
|
||||
@ -179,12 +142,9 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
styles.textInput,
|
||||
{
|
||||
color: theme.primary,
|
||||
borderBottomColor:
|
||||
type === 'remote' &&
|
||||
instanceQuery.data &&
|
||||
!instanceQuery.data.publicAllow
|
||||
? theme.red
|
||||
: theme.border
|
||||
borderBottomColor: instanceQuery.isError
|
||||
? theme.red
|
||||
: theme.border
|
||||
}
|
||||
]}
|
||||
onChangeText={onChangeText}
|
||||
@ -200,13 +160,9 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={buttonContent}
|
||||
content={t('server.button.local')}
|
||||
onPress={processUpdate}
|
||||
disabled={
|
||||
!instanceQuery.data?.uri ||
|
||||
(type === 'remote' && !instanceQuery.data.publicAllow) ||
|
||||
!agreed
|
||||
}
|
||||
disabled={!instanceQuery.data?.uri || !agreed}
|
||||
loading={instanceQuery.isFetching || appsQuery.isFetching}
|
||||
/>
|
||||
</View>
|
||||
@ -262,34 +218,32 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
/>
|
||||
</View>
|
||||
</Placeholder>
|
||||
{type === 'local' ? (
|
||||
<View style={styles.disclaimer}>
|
||||
<Icon
|
||||
name='Lock'
|
||||
size={StyleConstants.Font.Size.S}
|
||||
color={theme.secondary}
|
||||
style={styles.disclaimerIcon}
|
||||
/>
|
||||
<Text style={[styles.disclaimerText, { color: theme.secondary }]}>
|
||||
{t('server.disclaimer.base')}
|
||||
<Text
|
||||
style={{ color: theme.blue }}
|
||||
onPress={() => {
|
||||
analytics('view_privacy')
|
||||
WebBrowser.openBrowserAsync(
|
||||
'https://tooot.app/privacy-policy'
|
||||
)
|
||||
}}
|
||||
>
|
||||
{t('server.disclaimer.privacy')}
|
||||
</Text>
|
||||
<View style={styles.disclaimer}>
|
||||
<Icon
|
||||
name='Lock'
|
||||
size={StyleConstants.Font.Size.S}
|
||||
color={theme.secondary}
|
||||
style={styles.disclaimerIcon}
|
||||
/>
|
||||
<Text style={[styles.disclaimerText, { color: theme.secondary }]}>
|
||||
{t('server.disclaimer.base')}
|
||||
<Text
|
||||
style={{ color: theme.blue }}
|
||||
onPress={() => {
|
||||
analytics('view_privacy')
|
||||
WebBrowser.openBrowserAsync(
|
||||
'https://tooot.app/privacy-policy'
|
||||
)
|
||||
}}
|
||||
>
|
||||
{t('server.disclaimer.privacy')}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{type === 'local' ? requestAuth : null}
|
||||
{requestAuth}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ const AttachmentVideo: React.FC<Props> = ({
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
) : gifv ? null : (
|
||||
) : (
|
||||
<Button
|
||||
round
|
||||
overlay
|
||||
|
@ -48,7 +48,7 @@ const ScreenMeRoot: React.FC = () => {
|
||||
{localActiveIndex !== null ? (
|
||||
<MyInfo setData={setData} />
|
||||
) : (
|
||||
<ComponentInstance type='local' />
|
||||
<ComponentInstance />
|
||||
)}
|
||||
{localActiveIndex !== null ? <Collections /> : null}
|
||||
<Settings />
|
||||
|
@ -102,7 +102,7 @@ const ScreenMeSwitchRoot: React.FC = () => {
|
||||
<Text style={[styles.header, { color: theme.primary }]}>
|
||||
{t('content.new')}
|
||||
</Text>
|
||||
<ComponentInstance type='local' disableHeaderImage goBack />
|
||||
<ComponentInstance disableHeaderImage goBack />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
|
@ -2,43 +2,17 @@ import client from '@api/client'
|
||||
import { AxiosError } from 'axios'
|
||||
import { useQuery, UseQueryOptions } from 'react-query'
|
||||
|
||||
export type QueryKey = [
|
||||
'Instance',
|
||||
{ instanceDomain?: string; checkPublic: boolean }
|
||||
]
|
||||
export type QueryKey = ['Instance', { instanceDomain?: string }]
|
||||
|
||||
const queryFunction = async ({ queryKey }: { queryKey: QueryKey }) => {
|
||||
const { instanceDomain, checkPublic } = queryKey[1]
|
||||
const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
|
||||
const { instanceDomain } = queryKey[1]
|
||||
|
||||
let res: Mastodon.Instance & { publicAllow?: boolean } = await client<
|
||||
Mastodon.Instance
|
||||
>({
|
||||
return client<Mastodon.Instance>({
|
||||
method: 'get',
|
||||
instance: 'remote',
|
||||
instanceDomain,
|
||||
url: `instance`
|
||||
})
|
||||
|
||||
if (checkPublic) {
|
||||
let check
|
||||
try {
|
||||
check = await client<Mastodon.Status[]>({
|
||||
method: 'get',
|
||||
instance: 'remote',
|
||||
instanceDomain,
|
||||
url: `timelines/public`
|
||||
})
|
||||
} catch {}
|
||||
|
||||
if (check) {
|
||||
res.publicAllow = true
|
||||
return res
|
||||
} else {
|
||||
res.publicAllow = false
|
||||
return res
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const useInstanceQuery = <
|
||||
|
Loading…
Reference in New Issue
Block a user