1
0
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:
Zhiyuan Zheng 2021-02-09 01:16:12 +01:00
parent 1f4108c2d4
commit c46888acab
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
9 changed files with 158 additions and 155 deletions

27
.envrc.example Normal file
View 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
View 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

View File

@ -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

View File

@ -112,7 +112,7 @@
"native": "210201",
"major": 0,
"minor": 3,
"patch": 0,
"patch": 1,
"expo": "40.0.0"
}
}

View File

@ -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}
</>
)
}

View File

@ -94,7 +94,7 @@ const AttachmentVideo: React.FC<Props> = ({
}}
/>
) : null
) : gifv ? null : (
) : (
<Button
round
overlay

View File

@ -48,7 +48,7 @@ const ScreenMeRoot: React.FC = () => {
{localActiveIndex !== null ? (
<MyInfo setData={setData} />
) : (
<ComponentInstance type='local' />
<ComponentInstance />
)}
{localActiveIndex !== null ? <Collections /> : null}
<Settings />

View File

@ -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>

View File

@ -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 = <