Compare commits
10 Commits
noa.virell
...
cfe8bd0bfa
| Author | SHA1 | Date | |
|---|---|---|---|
| cfe8bd0bfa | |||
| 0d3651f923 | |||
| a84a13339f | |||
| bbb77a7c5e | |||
| cb46eb4a60 | |||
| adbad1c365 | |||
| 3df97e2125 | |||
| 252543957b | |||
| eb4a0b83e3 | |||
| 4f6c54e891 |
@@ -1,2 +1,9 @@
|
|||||||
TZ=Asia/Shanghai
|
SERVER_ADDRESS=:8000
|
||||||
LOG_LEVEL=debug
|
SERVER_DEBUG_MODE=true
|
||||||
|
SERVER_FILE_LOGGER=false
|
||||||
|
SERVER_JWT_SECRET=test
|
||||||
|
DATABASE_TYPE=postgres
|
||||||
|
DATABASE_HOST=127.0.0.1
|
||||||
|
DATABASE_NAME=postgres
|
||||||
|
DATABASE_USERNAME=postgres
|
||||||
|
DATABASE_PASSWORD=postgres
|
||||||
|
|||||||
3
.gitignore
vendored
@@ -46,6 +46,3 @@ go.work.sum
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
__MACOSX
|
__MACOSX
|
||||||
._*
|
._*
|
||||||
|
|
||||||
# go gen
|
|
||||||
*_gen.go
|
|
||||||
|
|||||||
@@ -7,11 +7,7 @@
|
|||||||
"tab_size": 4,
|
"tab_size": 4,
|
||||||
"format_on_save": "on",
|
"format_on_save": "on",
|
||||||
"languages": {
|
"languages": {
|
||||||
"Nix": {
|
|
||||||
"tab_size": 2,
|
|
||||||
},
|
|
||||||
"TypeScript": {
|
"TypeScript": {
|
||||||
"tab_size": 2,
|
|
||||||
"language_servers": [
|
"language_servers": [
|
||||||
"typescript-language-server",
|
"typescript-language-server",
|
||||||
"!vtsls",
|
"!vtsls",
|
||||||
@@ -20,7 +16,6 @@
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"TSX": {
|
"TSX": {
|
||||||
"tab_size": 2,
|
|
||||||
"language_servers": [
|
"language_servers": [
|
||||||
"typescript-language-server",
|
"typescript-language-server",
|
||||||
"!vtsls",
|
"!vtsls",
|
||||||
@@ -29,7 +24,6 @@
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"JavaScript": {
|
"JavaScript": {
|
||||||
"tab_size": 2,
|
|
||||||
"language_servers": [
|
"language_servers": [
|
||||||
"typescript-language-server",
|
"typescript-language-server",
|
||||||
"!vtsls",
|
"!vtsls",
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
FROM docker.io/node:22-alpine AS client-cms-build
|
|
||||||
RUN apk add just -y
|
|
||||||
RUN npm install -g corepack && \
|
|
||||||
corepack enable
|
|
||||||
WORKDIR /app
|
|
||||||
ENV VITE_APP_BASE_URL=$CLIENT_BASE_URL
|
|
||||||
COPY . .
|
|
||||||
RUN just build-client-cms
|
|
||||||
|
|
||||||
FROM docker.io/busybox:1.37 AS client-cms
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=client-build /app/.outputs/client/cms/dist .
|
|
||||||
EXPOSE 3000
|
|
||||||
ENTRYPOINT ["httpd", "-f", "-p", "3000", "-h", "/app", "-v"]
|
|
||||||
|
|
||||||
FROM docker.io/golang:1.25.5-alpine AS backend-build
|
|
||||||
WORKDIR /app
|
|
||||||
COPY . /app
|
|
||||||
RUN go mod tidy && \
|
|
||||||
go build -o /app/nixcn-cms
|
|
||||||
|
|
||||||
FROM docker.io/alpine:3.23 AS backend
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=backend-build /app/nixcn-cms /app/nixcn-cms
|
|
||||||
EXPOSE 8000
|
|
||||||
ENTRYPOINT [ "/app/nixcn-cms" ]
|
|
||||||
23
README.md
@@ -1,25 +1,2 @@
|
|||||||
# nixcn-cms
|
# nixcn-cms
|
||||||
|
|
||||||
## Contribution
|
|
||||||
|
|
||||||
1. **Root docs serve the zh-CN version** _[MUST]_
|
|
||||||
2. **Use sign-off via `git commit -s`** _[MUST]_
|
|
||||||
3. **Do not modify the `main` branch for any reason** _[MUST]_
|
|
||||||
4. **Do not omit the commit subject for any reason** _[MUST]_
|
|
||||||
5. **Describe all changes in the commit message** _[MUST]_
|
|
||||||
6. **Rebase before submitting patches** _[MUST]_
|
|
||||||
7. **Commit message written in english** _[MUST]_
|
|
||||||
8. **Use OpenPGP/SSH for commit signing** _[MUST]_
|
|
||||||
9. **Split commits for large or multi-part changes** _[OPTION]_
|
|
||||||
10. **Have fun contributing :)** _[VERY NECESSARY]_
|
|
||||||
|
|
||||||
## Toolchain
|
|
||||||
|
|
||||||
- Nix
|
|
||||||
- Devenv
|
|
||||||
- Direnv
|
|
||||||
|
|
||||||
## Notice
|
|
||||||
|
|
||||||
1. Client and all nix files use 2 space tab.
|
|
||||||
2. All Golang files and other configs use 4 space tab.
|
|
||||||
|
|||||||
1
client/.envrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
use flake . --impure
|
||||||
1579
client/bun.lock
Normal file
8472
client/cms/pnpm-lock.yaml
generated
@@ -1,70 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from '@/components/ui/dialog';
|
|
||||||
import { QRCode } from '@/components/ui/shadcn-io/qr-code';
|
|
||||||
import { useCheckinCode } from '@/hooks/data/useGetCheckInCode';
|
|
||||||
import { Button } from '../ui/button';
|
|
||||||
|
|
||||||
export function QrDialog(
|
|
||||||
{ eventId }: { eventId: string },
|
|
||||||
) {
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
return (
|
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button className="w-20">签到</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="sm:max-w-[425px]">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>QR Code</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
请工作人员扫描下面的二维码为你签到。
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<QrSection eventId={eventId} enabled={open} />
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function QrSection({ eventId, enabled }: { eventId: string; enabled: boolean }) {
|
|
||||||
const { data } = useCheckinCode(eventId, enabled);
|
|
||||||
return data
|
|
||||||
? (
|
|
||||||
<>
|
|
||||||
<div className="border-2 px-4 py-8 border-muted rounded-xl flex flex-col items-center justify-center p-4">
|
|
||||||
<QRCode data={data.data.checkin_code} className="size-60" />
|
|
||||||
</div>
|
|
||||||
<DialogFooter>
|
|
||||||
<div className="flex flex-1 items-center ml-2 font-mono text-3xl tracking-widest text-primary/80 justify-center">
|
|
||||||
{data.data.checkin_code}
|
|
||||||
</div>
|
|
||||||
</DialogFooter>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<QrSectionSkeleton />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function QrSectionSkeleton() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="border-2 px-4 py-8 border-muted rounded-xl flex flex-col items-center justify-center p-4">
|
|
||||||
<QRCode data="114514" className="size-60 blur-xs" />
|
|
||||||
</div>
|
|
||||||
<DialogFooter>
|
|
||||||
<div className="flex flex-1 items-center ml-2 font-mono text-3xl tracking-widest text-primary/80 justify-center">
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</DialogFooter>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import type { ReactNode } from 'react';
|
|
||||||
import React, { Suspense } from 'react';
|
|
||||||
|
|
||||||
export function withFallback<P extends object>(
|
|
||||||
Component: React.ComponentType<P>,
|
|
||||||
fallback: ReactNode,
|
|
||||||
) {
|
|
||||||
const Wrapped: React.FC<P> = (props) => {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={fallback}>
|
|
||||||
<Component {...props} />
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Wrapped.displayName = `withFallback(${Component.displayName! || Component.name || 'Component'
|
|
||||||
})`;
|
|
||||||
|
|
||||||
return Wrapped;
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import type { TurnstileInstance } from '@marsidev/react-turnstile';
|
|
||||||
import type { AuthorizeSearchParams } from '@/routes/authorize';
|
|
||||||
import { Turnstile } from '@marsidev/react-turnstile';
|
|
||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import { useRef, useState } from 'react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import NixOSLogo from '@/assets/nixos.svg?react';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import {
|
|
||||||
Field,
|
|
||||||
FieldGroup,
|
|
||||||
FieldLabel,
|
|
||||||
} from '@/components/ui/field';
|
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { useGetMagicLink } from '@/hooks/data/useGetMagicLink';
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
export function LoginForm({
|
|
||||||
oauthParams,
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<'div'> & {
|
|
||||||
oauthParams: AuthorizeSearchParams;
|
|
||||||
}) {
|
|
||||||
const formRef = useRef<HTMLFormElement>(null);
|
|
||||||
const turnstileRef = useRef<TurnstileInstance>(null);
|
|
||||||
const [token, setToken] = useState<string | null>(null);
|
|
||||||
const { mutateAsync, isPending } = useGetMagicLink();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
|
||||||
event.preventDefault();
|
|
||||||
const formData = new FormData(formRef.current!);
|
|
||||||
const email = formData.get('email')! as string;
|
|
||||||
mutateAsync({ email, turnstile_token: token!, ...oauthParams }).then(() => {
|
|
||||||
void navigate({ to: '/magicLinkSent', search: { email } });
|
|
||||||
}).catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
toast.error('请求登录链接失败');
|
|
||||||
turnstileRef.current?.reset();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
|
||||||
<form ref={formRef} onSubmit={handleSubmit}>
|
|
||||||
<FieldGroup>
|
|
||||||
<div className="flex flex-col items-center gap-2 text-center">
|
|
||||||
<div className="flex size-8 items-center justify-center rounded-md">
|
|
||||||
<NixOSLogo className="size-6" />
|
|
||||||
</div>
|
|
||||||
<span className="sr-only">Nix CN Meetup #2</span>
|
|
||||||
<h1 className="text-xl font-bold">欢迎来到 Nix CN Meetup #2</h1>
|
|
||||||
</div>
|
|
||||||
<Field>
|
|
||||||
<FieldLabel htmlFor="email">参会登记Email</FieldLabel>
|
|
||||||
<Input
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
type="email"
|
|
||||||
placeholder="edolstra@gmail.com"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<Field>
|
|
||||||
<Button type="submit" disabled={token === null || isPending}>
|
|
||||||
{token === null ? '等待 Turnstile' : isPending ? '发送中...' : '发送登录链接'}
|
|
||||||
</Button>
|
|
||||||
</Field>
|
|
||||||
</FieldGroup>
|
|
||||||
</form>
|
|
||||||
<Turnstile
|
|
||||||
ref={turnstileRef}
|
|
||||||
siteKey="0x4AAAAAACI5pu-lNWFc6Wu1"
|
|
||||||
options={{
|
|
||||||
refreshExpired: 'auto',
|
|
||||||
}}
|
|
||||||
onSuccess={(token) => {
|
|
||||||
setToken(token);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
import { useForm } from '@tanstack/react-form';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import z from 'zod';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogClose,
|
|
||||||
DialogContent,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from '@/components/ui/dialog';
|
|
||||||
import {
|
|
||||||
Field,
|
|
||||||
FieldError,
|
|
||||||
FieldLabel,
|
|
||||||
} from '@/components/ui/field';
|
|
||||||
import {
|
|
||||||
Input,
|
|
||||||
} from '@/components/ui/input';
|
|
||||||
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
|
|
||||||
import { useUserInfo } from '@/hooks/data/useUserInfo';
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
username: z.string().min(5),
|
|
||||||
nickname: z.string().min(1),
|
|
||||||
subtitle: z.string().min(1),
|
|
||||||
avatar: z.url().min(1),
|
|
||||||
});
|
|
||||||
export function EditProfileDialog() {
|
|
||||||
const { data: user } = useUserInfo();
|
|
||||||
const { mutateAsync } = useUpdateUser();
|
|
||||||
|
|
||||||
const form = useForm({
|
|
||||||
defaultValues: {
|
|
||||||
avatar: user.avatar,
|
|
||||||
username: user.username,
|
|
||||||
nickname: user.nickname,
|
|
||||||
subtitle: user.subtitle,
|
|
||||||
},
|
|
||||||
validators: {
|
|
||||||
onBlur: formSchema,
|
|
||||||
},
|
|
||||||
onSubmit: async ({
|
|
||||||
value,
|
|
||||||
}) => {
|
|
||||||
try {
|
|
||||||
await mutateAsync(value);
|
|
||||||
toast.success('个人资料更新成功');
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Form submission error', error);
|
|
||||||
toast.error('更新个人资料失败,请重试');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button variant="outline" className="w-full" size="lg">编辑个人资料</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="sm:max-w-[425px]">
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
void form.handleSubmit();
|
|
||||||
}}
|
|
||||||
className="grid gap-4"
|
|
||||||
>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>编辑个人资料</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<form.Field name="username">
|
|
||||||
{field => (
|
|
||||||
<Field>
|
|
||||||
<FieldLabel htmlFor="username">用户名</FieldLabel>
|
|
||||||
<Input
|
|
||||||
id="username"
|
|
||||||
name="username"
|
|
||||||
placeholder={user.username}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
onChange={e => field.handleChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
<FieldError errors={field.state.meta.errors} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
</form.Field>
|
|
||||||
<form.Field name="nickname">
|
|
||||||
{field => (
|
|
||||||
<Field>
|
|
||||||
<FieldLabel htmlFor="nickname">昵称</FieldLabel>
|
|
||||||
<Input
|
|
||||||
id="nickname"
|
|
||||||
name="nickname"
|
|
||||||
placeholder={user.nickname}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
onChange={e => field.handleChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
<FieldError errors={field.state.meta.errors} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
</form.Field>
|
|
||||||
<form.Field name="subtitle">
|
|
||||||
{field => (
|
|
||||||
<Field>
|
|
||||||
<FieldLabel htmlFor="subtitle">副标题</FieldLabel>
|
|
||||||
<Input
|
|
||||||
id="subtitle"
|
|
||||||
name="subtitle"
|
|
||||||
placeholder={user.subtitle}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
onChange={e => field.handleChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
<FieldError errors={field.state.meta.errors} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
</form.Field>
|
|
||||||
<form.Field name="avatar">
|
|
||||||
{field => (
|
|
||||||
<Field>
|
|
||||||
<FieldLabel htmlFor="avatar">头像链接</FieldLabel>
|
|
||||||
<Input
|
|
||||||
id="avatar"
|
|
||||||
name="avatar"
|
|
||||||
placeholder={user.avatar}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
onChange={e => field.handleChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
<FieldError errors={field.state.meta.errors} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
</form.Field>
|
|
||||||
<DialogFooter>
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button variant="outline">取消</Button>
|
|
||||||
</DialogClose>
|
|
||||||
<DialogClose asChild>
|
|
||||||
<Button type="submit">保存</Button>
|
|
||||||
</DialogClose>
|
|
||||||
</DialogFooter>
|
|
||||||
</form>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
import MDEditor from '@uiw/react-md-editor';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import { Mail, Pencil } from 'lucide-react';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import Markdown from 'react-markdown';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
||||||
import { useUpdateUser } from '@/hooks/data/useUpdateUser';
|
|
||||||
import { useUserInfo } from '@/hooks/data/useUserInfo';
|
|
||||||
import { base64ToUtf8, utf8ToBase64 } from '@/lib/utils';
|
|
||||||
import { Button } from '../ui/button';
|
|
||||||
import { EditProfileDialog } from './edit-profile-dialog';
|
|
||||||
|
|
||||||
export function MainProfile() {
|
|
||||||
const { data: user } = useUserInfo();
|
|
||||||
const [bio, setBio] = useState<string | undefined>(() => base64ToUtf8(user.bio));
|
|
||||||
const [enableBioEdit, setEnableBioEdit] = useState(false);
|
|
||||||
const { mutateAsync } = useUpdateUser();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col justify-center w-full lg:w-auto h-full lg:h-auto lg:flex-row lg:gap-8">
|
|
||||||
<div className="flex w-full flex-row mt-2 lg:mt-0 lg:flex-col lg:w-max">
|
|
||||||
<div className="flex flex-col w-full gap-3">
|
|
||||||
<div className="flex flex-col w-full gap-3">
|
|
||||||
<div className="flex flex-row gap-3 w-full lg:flex-col">
|
|
||||||
<Avatar className="size-16 rounded-full border-2 border-muted lg:size-64">
|
|
||||||
<AvatarImage src={user.avatar} alt={user.nickname} />
|
|
||||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
||||||
</Avatar>
|
|
||||||
<div className="flex flex-1 flex-col justify-center lg:mt-3">
|
|
||||||
<span className="font-semibold text-2xl" aria-hidden="true">{user.nickname}</span>
|
|
||||||
<span className="text-[20px] text-muted-foreground" aria-hidden="true">{user.subtitle}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row gap-2 items-center text-sm px-1 lg:px-0">
|
|
||||||
<Mail className="h-4 w-4 stroke-muted-foreground" />
|
|
||||||
{user.email}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<EditProfileDialog />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<section className="relative rounded-md border border-muted w-full flex-1 lg:flex-auto min-h-72 lg:h-full mt-4 lg:mt-0 prose dark:prose-invert max-w-[1012px] self-center">
|
|
||||||
{/* Bio */}
|
|
||||||
{enableBioEdit
|
|
||||||
? (
|
|
||||||
<MDEditor
|
|
||||||
value={bio}
|
|
||||||
onChange={setBio}
|
|
||||||
height="100%"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
: <div className="p-6 prose dark:prose-invert"><Markdown>{bio}</Markdown></div>}
|
|
||||||
<Button
|
|
||||||
className="absolute bottom-4 right-4"
|
|
||||||
// eslint-disable-next-line ts/no-misused-promises
|
|
||||||
onClick={async () => {
|
|
||||||
if (!enableBioEdit) {
|
|
||||||
setEnableBioEdit(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!isNil(bio)) {
|
|
||||||
try {
|
|
||||||
await mutateAsync({ bio: utf8ToBase64(bio) });
|
|
||||||
setEnableBioEdit(false);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
toast.error('个人简介更新失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
size="icon-sm"
|
|
||||||
variant={enableBioEdit ? 'default' : 'outline'}
|
|
||||||
>
|
|
||||||
<Pencil />
|
|
||||||
</Button>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import type { Icon } from '@tabler/icons-react';
|
|
||||||
import { Link } from '@tanstack/react-router';
|
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import {
|
|
||||||
SidebarGroup,
|
|
||||||
SidebarGroupContent,
|
|
||||||
SidebarMenu,
|
|
||||||
SidebarMenuButton,
|
|
||||||
SidebarMenuItem,
|
|
||||||
} from '@/components/ui/sidebar';
|
|
||||||
|
|
||||||
export function NavSecondary({
|
|
||||||
items,
|
|
||||||
...props
|
|
||||||
}: {
|
|
||||||
items: {
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
icon: Icon;
|
|
||||||
}[];
|
|
||||||
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
|
|
||||||
return (
|
|
||||||
<SidebarGroup {...props}>
|
|
||||||
<SidebarGroupContent>
|
|
||||||
<SidebarMenu>
|
|
||||||
{items.map(item => (
|
|
||||||
<SidebarMenuItem key={item.title}>
|
|
||||||
<Link to={item.url}>
|
|
||||||
{({ isActive }) => {
|
|
||||||
return (
|
|
||||||
<SidebarMenuButton isActive={isActive} tooltip={item.title}>
|
|
||||||
<item.icon />
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Link>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
))}
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
import * as React from "react"
|
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
|
||||||
import { XIcon } from "lucide-react"
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
|
|
||||||
function Dialog({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
||||||
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogTrigger({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
||||||
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogPortal({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
||||||
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogClose({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
||||||
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogOverlay({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
||||||
return (
|
|
||||||
<DialogPrimitive.Overlay
|
|
||||||
data-slot="dialog-overlay"
|
|
||||||
className={cn(
|
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogContent({
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
showCloseButton = true,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
||||||
showCloseButton?: boolean
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<DialogPortal data-slot="dialog-portal">
|
|
||||||
<DialogOverlay />
|
|
||||||
<DialogPrimitive.Content
|
|
||||||
data-slot="dialog-content"
|
|
||||||
className={cn(
|
|
||||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
{showCloseButton && (
|
|
||||||
<DialogPrimitive.Close
|
|
||||||
data-slot="dialog-close"
|
|
||||||
className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
||||||
>
|
|
||||||
<XIcon />
|
|
||||||
<span className="sr-only">Close</span>
|
|
||||||
</DialogPrimitive.Close>
|
|
||||||
)}
|
|
||||||
</DialogPrimitive.Content>
|
|
||||||
</DialogPortal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-slot="dialog-header"
|
|
||||||
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-slot="dialog-footer"
|
|
||||||
className={cn(
|
|
||||||
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogTitle({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
||||||
return (
|
|
||||||
<DialogPrimitive.Title
|
|
||||||
data-slot="dialog-title"
|
|
||||||
className={cn("text-lg leading-none font-semibold", className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogDescription({
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
||||||
return (
|
|
||||||
<DialogPrimitive.Description
|
|
||||||
data-slot="dialog-description"
|
|
||||||
className={cn("text-muted-foreground text-sm", className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
Dialog,
|
|
||||||
DialogClose,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogOverlay,
|
|
||||||
DialogPortal,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import { formatHex, oklch } from 'culori';
|
|
||||||
import QR from 'qrcode';
|
|
||||||
import { type HTMLAttributes, useEffect, useState } from 'react';
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
export type QRCodeProps = HTMLAttributes<HTMLDivElement> & {
|
|
||||||
data: string;
|
|
||||||
foreground?: string;
|
|
||||||
background?: string;
|
|
||||||
robustness?: 'L' | 'M' | 'Q' | 'H';
|
|
||||||
};
|
|
||||||
|
|
||||||
const oklchRegex = /oklch\(([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\)/;
|
|
||||||
|
|
||||||
const getOklch = (color: string, fallback: [number, number, number]) => {
|
|
||||||
const oklchMatch = color.match(oklchRegex);
|
|
||||||
|
|
||||||
if (!oklchMatch) {
|
|
||||||
return { l: fallback[0], c: fallback[1], h: fallback[2] };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
l: Number.parseFloat(oklchMatch[1]),
|
|
||||||
c: Number.parseFloat(oklchMatch[2]),
|
|
||||||
h: Number.parseFloat(oklchMatch[3]),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const QRCode = ({
|
|
||||||
data,
|
|
||||||
foreground,
|
|
||||||
background,
|
|
||||||
robustness = 'M',
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: QRCodeProps) => {
|
|
||||||
const [svg, setSVG] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const generateQR = async () => {
|
|
||||||
try {
|
|
||||||
const styles = getComputedStyle(document.documentElement);
|
|
||||||
const foregroundColor =
|
|
||||||
foreground ?? styles.getPropertyValue('--foreground');
|
|
||||||
const backgroundColor =
|
|
||||||
background ?? styles.getPropertyValue('--background');
|
|
||||||
|
|
||||||
const foregroundOklch = getOklch(
|
|
||||||
foregroundColor,
|
|
||||||
[0.21, 0.006, 285.885]
|
|
||||||
);
|
|
||||||
const backgroundOklch = getOklch(backgroundColor, [0.985, 0, 0]);
|
|
||||||
|
|
||||||
const newSvg = await QR.toString(data, {
|
|
||||||
type: 'svg',
|
|
||||||
color: {
|
|
||||||
dark: formatHex(oklch({ mode: 'oklch', ...foregroundOklch })),
|
|
||||||
light: formatHex(oklch({ mode: 'oklch', ...backgroundOklch })),
|
|
||||||
},
|
|
||||||
width: 200,
|
|
||||||
errorCorrectionLevel: robustness,
|
|
||||||
margin: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
setSVG(newSvg);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
generateQR();
|
|
||||||
}, [data, foreground, background, robustness]);
|
|
||||||
|
|
||||||
if (!svg) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn('size-full', '[&_svg]:size-full', className)}
|
|
||||||
// biome-ignore lint/security/noDangerouslySetInnerHtml: "Required for SVG"
|
|
||||||
dangerouslySetInnerHTML={{ __html: svg }}
|
|
||||||
{...(props as any)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Skeleton } from '../ui/skeleton';
|
|
||||||
|
|
||||||
export function CardSkeleton() {
|
|
||||||
return (
|
|
||||||
<Skeleton
|
|
||||||
className="gap-6 rounded-xl py-6 h-full"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
|
|
||||||
export function useCheckinCode(eventId: string, enabled: boolean) {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['getCheckinCode', eventId],
|
|
||||||
queryFn: async () => {
|
|
||||||
return axiosClient.get<{
|
|
||||||
checkin_code: string;
|
|
||||||
}>('/user/checkin', {
|
|
||||||
params: {
|
|
||||||
event_id: eventId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
enabled,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import type { AuthorizeSearchParams } from '@/routes/authorize';
|
|
||||||
import { useMutation } from '@tanstack/react-query';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
|
|
||||||
interface GetMagicLinkPayload extends AuthorizeSearchParams {
|
|
||||||
email: string;
|
|
||||||
turnstile_token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useGetMagicLink() {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async (payload: GetMagicLinkPayload) => {
|
|
||||||
return axiosClient.post<{ status: string }>('/auth/magic', payload);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
|
|
||||||
interface UpdateUserPayload {
|
|
||||||
avatar?: string;
|
|
||||||
bio?: string;
|
|
||||||
nickname?: string;
|
|
||||||
subtitle?: string;
|
|
||||||
username?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateUser() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async (payload: UpdateUserPayload) => {
|
|
||||||
return axiosClient.patch<{ status: string }>('/user/update', payload);
|
|
||||||
},
|
|
||||||
onSuccess: async () => {
|
|
||||||
await queryClient.invalidateQueries({ queryKey: ['userInfo'] });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
|
|
||||||
export function useUserInfo() {
|
|
||||||
return useSuspenseQuery({
|
|
||||||
queryKey: ['userInfo'],
|
|
||||||
queryFn: async () => {
|
|
||||||
const response = await axiosClient.get<{
|
|
||||||
username: string;
|
|
||||||
user_id: string;
|
|
||||||
email: string;
|
|
||||||
type: string;
|
|
||||||
nickname: string;
|
|
||||||
subtitle: string;
|
|
||||||
avatar: string;
|
|
||||||
bio: string;
|
|
||||||
}
|
|
||||||
>('/user/info');
|
|
||||||
return response.data;
|
|
||||||
},
|
|
||||||
staleTime: 10 * 60 * 1000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
|
|
||||||
export function useValidateMagicLink(ticket: string) {
|
|
||||||
return useSuspenseQuery({
|
|
||||||
queryKey: ['validateMagicLink', ticket],
|
|
||||||
queryFn: async () => {
|
|
||||||
return axiosClient.get<{ access_token: string; refresh_token: string }>('/auth/magic/verify', { params: { token: ticket } });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
const MOBILE_BREAKPOINT = 768;
|
|
||||||
|
|
||||||
export function useIsMobile() {
|
|
||||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
||||||
const onChange = () => {
|
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
||||||
};
|
|
||||||
mql.addEventListener('change', onChange);
|
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
||||||
return () => mql.removeEventListener('change', onChange);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return !!isMobile;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { clearTokens } from '@/lib/token';
|
|
||||||
|
|
||||||
export function useLogout() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const logout = useCallback(() => {
|
|
||||||
clearTokens();
|
|
||||||
void navigate({ to: '/authorize' });
|
|
||||||
}, [navigate]);
|
|
||||||
|
|
||||||
return { logout };
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import type { AxiosError, AxiosRequestConfig } from 'axios';
|
|
||||||
import type { JsonValue } from 'type-fest';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import { router } from '@/lib/router';
|
|
||||||
import { clearTokens, doRefreshToken, getRefreshToken, getToken, setRefreshToken, setToken } from './token';
|
|
||||||
|
|
||||||
export const HEADER_API_VERSION = {
|
|
||||||
'X-Api-Version': 'latest',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const axiosClient = axios.create({
|
|
||||||
baseURL: '/api/v1/',
|
|
||||||
headers: HEADER_API_VERSION,
|
|
||||||
});
|
|
||||||
|
|
||||||
axiosClient.interceptors.request.use((config) => {
|
|
||||||
const token = getToken();
|
|
||||||
if (token !== null) {
|
|
||||||
config.headers = config.headers ?? {};
|
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
});
|
|
||||||
|
|
||||||
type RetryConfig = AxiosRequestConfig & { _retry?: boolean };
|
|
||||||
|
|
||||||
interface ResponseData {
|
|
||||||
code: number;
|
|
||||||
error_id: string;
|
|
||||||
status: string;
|
|
||||||
data: JsonValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
axiosClient.interceptors.response.use(async (response) => {
|
|
||||||
const data = response.data as ResponseData;
|
|
||||||
if (data.code !== 200) {
|
|
||||||
return Promise.reject(data);
|
|
||||||
}
|
|
||||||
response.data = data.data;
|
|
||||||
return response;
|
|
||||||
}, async (error: AxiosError) => {
|
|
||||||
const originalRequest = error.config as RetryConfig | undefined;
|
|
||||||
if (!error.response || error.response.status !== 401 || !originalRequest) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
if (error.response.status === 401 && originalRequest.url !== '/auth/refresh' && !isNil(getRefreshToken())) {
|
|
||||||
try {
|
|
||||||
const maybeRefreshTokenResponse = await doRefreshToken();
|
|
||||||
if (maybeRefreshTokenResponse.status !== 200) {
|
|
||||||
throw new Error('Failed to refresh token');
|
|
||||||
}
|
|
||||||
const { access_token, refresh_token } = maybeRefreshTokenResponse.data;
|
|
||||||
originalRequest.headers = originalRequest.headers ?? {};
|
|
||||||
originalRequest.headers.Authorization = `Bearer ${access_token}`;
|
|
||||||
setToken(access_token);
|
|
||||||
setRefreshToken(refresh_token);
|
|
||||||
return await axiosClient(originalRequest);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
||||||
catch (e) {
|
|
||||||
// Should remove token (tokens are out of date)
|
|
||||||
clearTokens();
|
|
||||||
await router.navigate({ to: '/authorize' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {
|
|
||||||
IconDashboard,
|
|
||||||
IconUser,
|
|
||||||
} from '@tabler/icons-react';
|
|
||||||
|
|
||||||
export const navData = {
|
|
||||||
navMain: [
|
|
||||||
{
|
|
||||||
title: '工作台',
|
|
||||||
url: '/',
|
|
||||||
icon: IconDashboard,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
navSecondary: [
|
|
||||||
{
|
|
||||||
title: '个人资料',
|
|
||||||
url: '/profile',
|
|
||||||
icon: IconUser,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Generate a cryptographically secure OAuth2 state string
|
|
||||||
* base64url encoded, URL-safe
|
|
||||||
*/
|
|
||||||
export function generateOAuthState(bytes: number = 32): string {
|
|
||||||
const random = new Uint8Array(bytes);
|
|
||||||
crypto.getRandomValues(random);
|
|
||||||
|
|
||||||
// base64url encode
|
|
||||||
return btoa(String.fromCharCode(...random))
|
|
||||||
.replace(/\+/g, '-')
|
|
||||||
.replace(/\//g, '_')
|
|
||||||
.replace(/=+$/, '');
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import { axiosClient, HEADER_API_VERSION } from './axios';
|
|
||||||
|
|
||||||
export function setToken(token: string) {
|
|
||||||
localStorage.setItem('token', token);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getToken() {
|
|
||||||
return localStorage.getItem('token');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeToken() {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hasToken() {
|
|
||||||
return getToken() !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setRefreshToken(refreshToken: string) {
|
|
||||||
localStorage.setItem('refreshToken', refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRefreshToken() {
|
|
||||||
return localStorage.getItem('refreshToken');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearTokens() {
|
|
||||||
removeToken();
|
|
||||||
setRefreshToken('');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function doSetTokenByCode(code: string) {
|
|
||||||
const { data } = await axiosClient.post<{ access_token: string; refresh_token: string }>('/auth/token', { code }, { headers: HEADER_API_VERSION });
|
|
||||||
setToken(data.access_token);
|
|
||||||
setRefreshToken(data.refresh_token);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function doRefreshToken() {
|
|
||||||
return axiosClient.post<{ access_token: string; refresh_token: string }>('/auth/refresh', { refresh_token: getRefreshToken() }, { headers: HEADER_API_VERSION });
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import type { ClassValue } from 'clsx';
|
|
||||||
// eslint-disable-next-line unicorn/prefer-node-protocol
|
|
||||||
import { Buffer } from 'buffer';
|
|
||||||
import { clsx } from 'clsx';
|
|
||||||
import { twMerge } from 'tailwind-merge';
|
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
|
||||||
return twMerge(clsx(inputs));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function base64ToUtf8(base64: string): string {
|
|
||||||
return new TextDecoder('utf-8').decode(
|
|
||||||
Uint8Array.from(Buffer.from(base64, 'base64')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function utf8ToBase64(utf8: string): string {
|
|
||||||
return Buffer.from(utf8, 'utf-8').toString('base64');
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
|
||||||
|
|
||||||
// This file was automatically generated by TanStack Router.
|
|
||||||
// You should NOT make any changes in this file as it will be overwritten.
|
|
||||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
||||||
|
|
||||||
import { Route as rootRouteImport } from './routes/__root'
|
|
||||||
import { Route as TokenRouteImport } from './routes/token'
|
|
||||||
import { Route as MagicLinkSentRouteImport } from './routes/magicLinkSent'
|
|
||||||
import { Route as AuthorizeRouteImport } from './routes/authorize'
|
|
||||||
import { Route as SidebarLayoutRouteImport } from './routes/_sidebarLayout'
|
|
||||||
import { Route as SidebarLayoutIndexRouteImport } from './routes/_sidebarLayout/index'
|
|
||||||
import { Route as SidebarLayoutProfileRouteImport } from './routes/_sidebarLayout/profile'
|
|
||||||
|
|
||||||
const TokenRoute = TokenRouteImport.update({
|
|
||||||
id: '/token',
|
|
||||||
path: '/token',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const MagicLinkSentRoute = MagicLinkSentRouteImport.update({
|
|
||||||
id: '/magicLinkSent',
|
|
||||||
path: '/magicLinkSent',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const AuthorizeRoute = AuthorizeRouteImport.update({
|
|
||||||
id: '/authorize',
|
|
||||||
path: '/authorize',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const SidebarLayoutRoute = SidebarLayoutRouteImport.update({
|
|
||||||
id: '/_sidebarLayout',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const SidebarLayoutIndexRoute = SidebarLayoutIndexRouteImport.update({
|
|
||||||
id: '/',
|
|
||||||
path: '/',
|
|
||||||
getParentRoute: () => SidebarLayoutRoute,
|
|
||||||
} as any)
|
|
||||||
const SidebarLayoutProfileRoute = SidebarLayoutProfileRouteImport.update({
|
|
||||||
id: '/profile',
|
|
||||||
path: '/profile',
|
|
||||||
getParentRoute: () => SidebarLayoutRoute,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
|
||||||
'/': typeof SidebarLayoutIndexRoute
|
|
||||||
'/authorize': typeof AuthorizeRoute
|
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
|
||||||
'/token': typeof TokenRoute
|
|
||||||
'/profile': typeof SidebarLayoutProfileRoute
|
|
||||||
}
|
|
||||||
export interface FileRoutesByTo {
|
|
||||||
'/authorize': typeof AuthorizeRoute
|
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
|
||||||
'/token': typeof TokenRoute
|
|
||||||
'/profile': typeof SidebarLayoutProfileRoute
|
|
||||||
'/': typeof SidebarLayoutIndexRoute
|
|
||||||
}
|
|
||||||
export interface FileRoutesById {
|
|
||||||
__root__: typeof rootRouteImport
|
|
||||||
'/_sidebarLayout': typeof SidebarLayoutRouteWithChildren
|
|
||||||
'/authorize': typeof AuthorizeRoute
|
|
||||||
'/magicLinkSent': typeof MagicLinkSentRoute
|
|
||||||
'/token': typeof TokenRoute
|
|
||||||
'/_sidebarLayout/profile': typeof SidebarLayoutProfileRoute
|
|
||||||
'/_sidebarLayout/': typeof SidebarLayoutIndexRoute
|
|
||||||
}
|
|
||||||
export interface FileRouteTypes {
|
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
|
||||||
fullPaths: '/' | '/authorize' | '/magicLinkSent' | '/token' | '/profile'
|
|
||||||
fileRoutesByTo: FileRoutesByTo
|
|
||||||
to: '/authorize' | '/magicLinkSent' | '/token' | '/profile' | '/'
|
|
||||||
id:
|
|
||||||
| '__root__'
|
|
||||||
| '/_sidebarLayout'
|
|
||||||
| '/authorize'
|
|
||||||
| '/magicLinkSent'
|
|
||||||
| '/token'
|
|
||||||
| '/_sidebarLayout/profile'
|
|
||||||
| '/_sidebarLayout/'
|
|
||||||
fileRoutesById: FileRoutesById
|
|
||||||
}
|
|
||||||
export interface RootRouteChildren {
|
|
||||||
SidebarLayoutRoute: typeof SidebarLayoutRouteWithChildren
|
|
||||||
AuthorizeRoute: typeof AuthorizeRoute
|
|
||||||
MagicLinkSentRoute: typeof MagicLinkSentRoute
|
|
||||||
TokenRoute: typeof TokenRoute
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
|
||||||
interface FileRoutesByPath {
|
|
||||||
'/token': {
|
|
||||||
id: '/token'
|
|
||||||
path: '/token'
|
|
||||||
fullPath: '/token'
|
|
||||||
preLoaderRoute: typeof TokenRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/magicLinkSent': {
|
|
||||||
id: '/magicLinkSent'
|
|
||||||
path: '/magicLinkSent'
|
|
||||||
fullPath: '/magicLinkSent'
|
|
||||||
preLoaderRoute: typeof MagicLinkSentRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/authorize': {
|
|
||||||
id: '/authorize'
|
|
||||||
path: '/authorize'
|
|
||||||
fullPath: '/authorize'
|
|
||||||
preLoaderRoute: typeof AuthorizeRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/_sidebarLayout': {
|
|
||||||
id: '/_sidebarLayout'
|
|
||||||
path: ''
|
|
||||||
fullPath: '/'
|
|
||||||
preLoaderRoute: typeof SidebarLayoutRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/_sidebarLayout/': {
|
|
||||||
id: '/_sidebarLayout/'
|
|
||||||
path: '/'
|
|
||||||
fullPath: '/'
|
|
||||||
preLoaderRoute: typeof SidebarLayoutIndexRouteImport
|
|
||||||
parentRoute: typeof SidebarLayoutRoute
|
|
||||||
}
|
|
||||||
'/_sidebarLayout/profile': {
|
|
||||||
id: '/_sidebarLayout/profile'
|
|
||||||
path: '/profile'
|
|
||||||
fullPath: '/profile'
|
|
||||||
preLoaderRoute: typeof SidebarLayoutProfileRouteImport
|
|
||||||
parentRoute: typeof SidebarLayoutRoute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SidebarLayoutRouteChildren {
|
|
||||||
SidebarLayoutProfileRoute: typeof SidebarLayoutProfileRoute
|
|
||||||
SidebarLayoutIndexRoute: typeof SidebarLayoutIndexRoute
|
|
||||||
}
|
|
||||||
|
|
||||||
const SidebarLayoutRouteChildren: SidebarLayoutRouteChildren = {
|
|
||||||
SidebarLayoutProfileRoute: SidebarLayoutProfileRoute,
|
|
||||||
SidebarLayoutIndexRoute: SidebarLayoutIndexRoute,
|
|
||||||
}
|
|
||||||
|
|
||||||
const SidebarLayoutRouteWithChildren = SidebarLayoutRoute._addFileChildren(
|
|
||||||
SidebarLayoutRouteChildren,
|
|
||||||
)
|
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
|
||||||
SidebarLayoutRoute: SidebarLayoutRouteWithChildren,
|
|
||||||
AuthorizeRoute: AuthorizeRoute,
|
|
||||||
MagicLinkSentRoute: MagicLinkSentRoute,
|
|
||||||
TokenRoute: TokenRoute,
|
|
||||||
}
|
|
||||||
export const routeTree = rootRouteImport
|
|
||||||
._addFileChildren(rootRouteChildren)
|
|
||||||
._addFileTypes<FileRouteTypes>()
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
||||||
import { createRootRoute, Outlet } from '@tanstack/react-router';
|
|
||||||
import { ThemeProvider } from '@/components/theme-provider';
|
|
||||||
import { Toaster } from '@/components/ui/sonner';
|
|
||||||
import '@/index.css';
|
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
|
||||||
defaultOptions: {
|
|
||||||
queries: {
|
|
||||||
retry: (failureCount, error: any) => {
|
|
||||||
// eslint-disable-next-line ts/no-unsafe-assignment
|
|
||||||
const status
|
|
||||||
// eslint-disable-next-line ts/no-unsafe-member-access
|
|
||||||
= error?.response?.status ?? error?.status;
|
|
||||||
|
|
||||||
if (status >= 400 && status < 500) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return failureCount < 3;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function RootLayout() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
|
||||||
<QueryClientProvider client={queryClient}>
|
|
||||||
<Outlet />
|
|
||||||
</QueryClientProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
<Toaster position="top-right" />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Route = createRootRoute({ component: RootLayout });
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { createFileRoute, redirect } from '@tanstack/react-router';
|
|
||||||
import { hasToken } from '@/lib/token';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/_sidebarLayout/')({
|
|
||||||
component: Index,
|
|
||||||
loader: async () => {
|
|
||||||
if (!hasToken()) {
|
|
||||||
throw redirect({
|
|
||||||
to: '/authorize',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function Index() {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
|
|
||||||
{/* Section Cards */}
|
|
||||||
<div className="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card
|
|
||||||
grid grid-cols-1 gap-4 px-4 auto-rows-[minmax(175px,auto)] items-stretch
|
|
||||||
*:data-[slot=card]:bg-linear-to-t *:data-[slot=card]:shadow-xs lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-4"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import { MainProfile } from '@/components/profile/main-profile';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/_sidebarLayout/profile')({
|
|
||||||
component: RouteComponent,
|
|
||||||
});
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
return (
|
|
||||||
<div className="flex h-full flex-col gap-6 px-4 py-6">
|
|
||||||
<MainProfile />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import { zodValidator } from '@tanstack/zod-adapter';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import z from 'zod';
|
|
||||||
import { LoginForm } from '@/components/login-form';
|
|
||||||
import { axiosClient } from '@/lib/axios';
|
|
||||||
import { generateOAuthState } from '@/lib/random';
|
|
||||||
import { getToken } from '@/lib/token';
|
|
||||||
|
|
||||||
const authorizeSchema = z.object({
|
|
||||||
response_type: z.literal('code').default('code'),
|
|
||||||
client_id: z.literal('org_client').default('org_client'),
|
|
||||||
redirect_uri: z.string().default(`${new URL(import.meta.env.VITE_APP_BASE_URL as string).toString()}token`),
|
|
||||||
state: z.string().default(generateOAuthState()),
|
|
||||||
});
|
|
||||||
|
|
||||||
export type AuthorizeSearchParams = z.infer<typeof authorizeSchema>;
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/authorize')({
|
|
||||||
component: RouteComponent,
|
|
||||||
validateSearch: zodValidator(authorizeSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
const token = getToken();
|
|
||||||
const oauthParams = Route.useSearch();
|
|
||||||
/**
|
|
||||||
* Auth by Token Flow
|
|
||||||
*/
|
|
||||||
if (!isNil(token)) {
|
|
||||||
axiosClient.post<{ redirect_uri: string }>('/auth/exchange', {
|
|
||||||
client_id: oauthParams.client_id,
|
|
||||||
redirect_uri: oauthParams.redirect_uri,
|
|
||||||
state: oauthParams.state,
|
|
||||||
}).then((res) => {
|
|
||||||
window.location.href = res.data.redirect_uri;
|
|
||||||
}).catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
return 'Token exchange failed';
|
|
||||||
});
|
|
||||||
return 'Redirecting';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
|
|
||||||
<div className="w-full max-w-sm">
|
|
||||||
<LoginForm oauthParams={oauthParams} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { createFileRoute, Navigate } from '@tanstack/react-router';
|
|
||||||
import { zodValidator } from '@tanstack/zod-adapter';
|
|
||||||
import z from 'zod';
|
|
||||||
import NixOSLogo from '@/assets/nixos.svg?react';
|
|
||||||
|
|
||||||
const paramsSchema = z.object({
|
|
||||||
email: z.string().optional(),
|
|
||||||
});
|
|
||||||
export const Route = createFileRoute('/magicLinkSent')({
|
|
||||||
component: RouteComponent,
|
|
||||||
validateSearch: zodValidator(paramsSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
const { email } = Route.useSearch();
|
|
||||||
return email !== undefined
|
|
||||||
? (
|
|
||||||
<div
|
|
||||||
className="
|
|
||||||
bg-background flex min-h-svh flex-row items-center justify-center gap-6 p-6 md:p-10"
|
|
||||||
>
|
|
||||||
<NixOSLogo className="size-12" />
|
|
||||||
<span
|
|
||||||
aria-hidden="true"
|
|
||||||
className="mx-2 inline-block h-6 w-px bg-current opacity-40"
|
|
||||||
/>
|
|
||||||
登录链接已发送至
|
|
||||||
{' '}
|
|
||||||
{email}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<Navigate to="/authorize" />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import z from 'zod';
|
|
||||||
import { doSetTokenByCode } from '@/lib/token';
|
|
||||||
|
|
||||||
const tokenCodeSchema = z.object({
|
|
||||||
code: z.string().nonempty(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/token')({
|
|
||||||
component: RouteComponent,
|
|
||||||
validateSearch: tokenCodeSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
const { code } = Route.useSearch();
|
|
||||||
const [status, setStatus] = useState('Loading...');
|
|
||||||
const navigate = useNavigate();
|
|
||||||
doSetTokenByCode(code).then(() => {
|
|
||||||
void navigate({ to: '/' });
|
|
||||||
}).catch((_) => {
|
|
||||||
setStatus('Error getting token');
|
|
||||||
});
|
|
||||||
return <div>{status}</div>;
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ import pluginQuery from '@tanstack/eslint-plugin-query';
|
|||||||
|
|
||||||
export default antfu({
|
export default antfu({
|
||||||
gitignore: true,
|
gitignore: true,
|
||||||
ignores: ['**/node_modules/**', '**/dist/**', 'bun.lock', '**/routeTree.gen.ts', '**/ui/**', 'src/components/editor/**/*'],
|
ignores: ['**/node_modules/**', '**/dist/**', 'bun.lock', '**/routeTree.gen.ts', '**/ui/**'],
|
||||||
react: true,
|
react: true,
|
||||||
stylistic: {
|
stylistic: {
|
||||||
semi: true,
|
semi: true,
|
||||||
61
client/flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765779637,
|
||||||
|
"narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1306659b587dc277866c7b69eb97e5f07864d8c4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
28
client/flake.nix
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
description = "Basic flake for devShell";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
bun
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
source_up
|
|
||||||
|
|
||||||
fvm install
|
|
||||||
|
|
||||||
PATH_add .fvm/flutter_sdk/bin
|
|
||||||
PATH_add .fvm/flutter_sdk/bin/cache/dart-sdk/bin
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"flutter": "3.38.0"
|
|
||||||
}
|
|
||||||
19
client/mobile/.gitignore
vendored
@@ -1,19 +0,0 @@
|
|||||||
# fvm
|
|
||||||
.fvm/
|
|
||||||
|
|
||||||
# dart
|
|
||||||
.dart_tool/
|
|
||||||
.packages
|
|
||||||
.pub-cache/
|
|
||||||
.pub/
|
|
||||||
|
|
||||||
# build
|
|
||||||
build/
|
|
||||||
|
|
||||||
# vscode
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# idea
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
android/*.iml
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# This file tracks properties of this Flutter project.
|
|
||||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
|
||||||
#
|
|
||||||
# This file should be version controlled and should not be manually edited.
|
|
||||||
|
|
||||||
version:
|
|
||||||
revision: "a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7"
|
|
||||||
channel: "stable"
|
|
||||||
|
|
||||||
project_type: app
|
|
||||||
|
|
||||||
# Tracks metadata for the flutter migrate command
|
|
||||||
migration:
|
|
||||||
platforms:
|
|
||||||
- platform: root
|
|
||||||
create_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
base_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
- platform: android
|
|
||||||
create_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
base_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
- platform: ios
|
|
||||||
create_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
base_revision: a0e9b9dbf78c8a5ef39b45a7efd40ed2de19c1a7
|
|
||||||
|
|
||||||
# User provided section
|
|
||||||
|
|
||||||
# List of Local paths (relative to this file) that should be
|
|
||||||
# ignored by the migrate tool.
|
|
||||||
#
|
|
||||||
# Files that are not part of the templates will be ignored by default.
|
|
||||||
unmanaged_files:
|
|
||||||
- 'lib/main.dart'
|
|
||||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# nixcn
|
|
||||||
|
|
||||||
A new Flutter project.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
This project is a starting point for a Flutter application.
|
|
||||||
|
|
||||||
A few resources to get you started if this is your first Flutter project:
|
|
||||||
|
|
||||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
|
||||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
|
||||||
|
|
||||||
For help getting started with Flutter development, view the
|
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
|
||||||
samples, guidance on mobile development, and a full API reference.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# This file configures the analyzer, which statically analyzes Dart code to
|
|
||||||
# check for errors, warnings, and lints.
|
|
||||||
#
|
|
||||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
|
||||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
|
||||||
# invoked from the command line by running `flutter analyze`.
|
|
||||||
|
|
||||||
# The following line activates a set of recommended lints for Flutter apps,
|
|
||||||
# packages, and plugins designed to encourage good coding practices.
|
|
||||||
include: package:flutter_lints/flutter.yaml
|
|
||||||
|
|
||||||
linter:
|
|
||||||
# The lint rules applied to this project can be customized in the
|
|
||||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
|
||||||
# included above or to enable additional rules. A list of all available lints
|
|
||||||
# and their documentation is published at https://dart.dev/lints.
|
|
||||||
#
|
|
||||||
# Instead of disabling a lint rule for the entire project in the
|
|
||||||
# section below, it can also be suppressed for a single line of code
|
|
||||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
|
||||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
|
||||||
# producing the lint.
|
|
||||||
rules:
|
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
|
||||||
# https://dart.dev/guides/language/analysis-options
|
|
||||||
14
client/mobile/android/.gitignore
vendored
@@ -1,14 +0,0 @@
|
|||||||
gradle-wrapper.jar
|
|
||||||
/.gradle
|
|
||||||
/captures/
|
|
||||||
/gradlew
|
|
||||||
/gradlew.bat
|
|
||||||
/local.properties
|
|
||||||
GeneratedPluginRegistrant.java
|
|
||||||
.cxx/
|
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
|
||||||
# See https://flutter.dev/to/reference-keystore
|
|
||||||
key.properties
|
|
||||||
**/*.keystore
|
|
||||||
**/*.jks
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("com.android.application")
|
|
||||||
id("kotlin-android")
|
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
|
||||||
id("dev.flutter.flutter-gradle-plugin")
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "io.asnk.applications.nixcn"
|
|
||||||
compileSdk = flutter.compileSdkVersion
|
|
||||||
ndkVersion = flutter.ndkVersion
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "io.asnk.applications.nixcn"
|
|
||||||
// You can update the following values to match your application needs.
|
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
|
||||||
minSdk = flutter.minSdkVersion
|
|
||||||
targetSdk = flutter.targetSdkVersion
|
|
||||||
versionCode = flutter.versionCode
|
|
||||||
versionName = flutter.versionName
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
// TODO: Add your own signing config for the release build.
|
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flutter {
|
|
||||||
source = "../.."
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<application
|
|
||||||
android:label="nixcn"
|
|
||||||
android:name="${applicationName}"
|
|
||||||
android:icon="@mipmap/ic_launcher">
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:exported="true"
|
|
||||||
android:launchMode="singleTop"
|
|
||||||
android:taskAffinity=""
|
|
||||||
android:theme="@style/LaunchTheme"
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:windowSoftInputMode="adjustResize">
|
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
|
||||||
the Android process has started. This theme is visible to the user
|
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
|
||||||
to determine the Window background behind the Flutter UI. -->
|
|
||||||
<meta-data
|
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
|
||||||
android:resource="@style/NormalTheme"
|
|
||||||
/>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<!-- Don't delete the meta-data below.
|
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
|
||||||
<meta-data
|
|
||||||
android:name="flutterEmbedding"
|
|
||||||
android:value="2" />
|
|
||||||
</application>
|
|
||||||
<!-- Required to query activities that can process text, see:
|
|
||||||
https://developer.android.com/training/package-visibility and
|
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
|
||||||
<data android:mimeType="text/plain"/>
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package io.asnk.applications.nixcn
|
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
|
||||||
|
|
||||||
class MainActivity : FlutterActivity()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="?android:colorBackground" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:drawable="@android:color/white" />
|
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
|
||||||
<!-- <item>
|
|
||||||
<bitmap
|
|
||||||
android:gravity="center"
|
|
||||||
android:src="@mipmap/launch_image" />
|
|
||||||
</item> -->
|
|
||||||
</layer-list>
|
|
||||||
|
Before Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 721 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
|
||||||
the Flutter engine draws its first frame -->
|
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
||||||
</style>
|
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
|
||||||
This theme determines the color of the Android Window while your
|
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
|
||||||
running.
|
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
the Flutter tool needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val newBuildDir: Directory =
|
|
||||||
rootProject.layout.buildDirectory
|
|
||||||
.dir("../../build")
|
|
||||||
.get()
|
|
||||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
|
||||||
|
|
||||||
subprojects {
|
|
||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(":app")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register<Delete>("clean") {
|
|
||||||
delete(rootProject.layout.buildDirectory)
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
|
||||||
android.useAndroidX=true
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
val flutterSdkPath =
|
|
||||||
run {
|
|
||||||
val properties = java.util.Properties()
|
|
||||||
file("local.properties").inputStream().use { properties.load(it) }
|
|
||||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
|
||||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
|
||||||
flutterSdkPath
|
|
||||||
}
|
|
||||||
|
|
||||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
|
||||||
id("com.android.application") version "8.11.1" apply false
|
|
||||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
include(":app")
|
|
||||||
34
client/mobile/ios/.gitignore
vendored
@@ -1,34 +0,0 @@
|
|||||||
**/dgph
|
|
||||||
*.mode1v3
|
|
||||||
*.mode2v3
|
|
||||||
*.moved-aside
|
|
||||||
*.pbxuser
|
|
||||||
*.perspectivev3
|
|
||||||
**/*sync/
|
|
||||||
.sconsign.dblite
|
|
||||||
.tags*
|
|
||||||
**/.vagrant/
|
|
||||||
**/DerivedData/
|
|
||||||
Icon?
|
|
||||||
**/Pods/
|
|
||||||
**/.symlinks/
|
|
||||||
profile
|
|
||||||
xcuserdata
|
|
||||||
**/.generated/
|
|
||||||
Flutter/App.framework
|
|
||||||
Flutter/Flutter.framework
|
|
||||||
Flutter/Flutter.podspec
|
|
||||||
Flutter/Generated.xcconfig
|
|
||||||
Flutter/ephemeral/
|
|
||||||
Flutter/app.flx
|
|
||||||
Flutter/app.zip
|
|
||||||
Flutter/flutter_assets/
|
|
||||||
Flutter/flutter_export_environment.sh
|
|
||||||
ServiceDefinitions.json
|
|
||||||
Runner/GeneratedPluginRegistrant.*
|
|
||||||
|
|
||||||
# Exceptions to above rules.
|
|
||||||
!default.mode1v3
|
|
||||||
!default.mode2v3
|
|
||||||
!default.pbxuser
|
|
||||||
!default.perspectivev3
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>io.flutter.flutter.app</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>MinimumOSVersion</key>
|
|
||||||
<string>13.0</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
||||||
@@ -1,616 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 54;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
|
||||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
|
||||||
remoteInfo = Runner;
|
|
||||||
};
|
|
||||||
/* End PBXContainerItemProxy section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 10;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
name = "Embed Frameworks";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
|
||||||
);
|
|
||||||
path = RunnerTests;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Flutter;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146E51CF9000F007C117D = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146EF1CF9000F007C117D /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
|
||||||
);
|
|
||||||
path = Runner;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
|
||||||
buildPhases = (
|
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
|
||||||
);
|
|
||||||
name = RunnerTests;
|
|
||||||
productName = RunnerTests;
|
|
||||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
|
||||||
};
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
|
||||||
buildPhases = (
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = Runner;
|
|
||||||
productName = Runner;
|
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
BuildIndependentTargetsInParallel = YES;
|
|
||||||
LastUpgradeCheck = 1510;
|
|
||||||
ORGANIZATIONNAME = "";
|
|
||||||
TargetAttributes = {
|
|
||||||
331C8080294A63A400263BE5 = {
|
|
||||||
CreatedOnToolsVersion = 14.0;
|
|
||||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
|
||||||
};
|
|
||||||
97C146ED1CF9000F007C117D = {
|
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
|
||||||
LastSwiftMigration = 1100;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
|
||||||
compatibilityVersion = "Xcode 9.3";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
331C807F294A63A400263BE5 /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
|
||||||
);
|
|
||||||
name = "Thin Binary";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
|
||||||
};
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Run Script";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
331C807D294A63A400263BE5 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
|
||||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
|
||||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C146FB1CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = Main.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C147001CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = LaunchScreen.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
97C147031CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147041CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
97C147061CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147071CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.asnk.applications.nixcn;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
331C8088294A63A400263BE5 /* Debug */,
|
|
||||||
331C8089294A63A400263BE5 /* Release */,
|
|
||||||
331C808A294A63A400263BE5 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147031CF9000F007C117D /* Debug */,
|
|
||||||
97C147041CF9000F007C117D /* Release */,
|
|
||||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147061CF9000F007C117D /* Debug */,
|
|
||||||
97C147071CF9000F007C117D /* Release */,
|
|
||||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>PreviewsEnabled</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1510"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO"
|
|
||||||
parallelizable = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
|
||||||
BuildableName = "RunnerTests.xctest"
|
|
||||||
BlueprintName = "RunnerTests"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
enableGPUValidationMode = "1"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Profile"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:Runner.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>PreviewsEnabled</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import Flutter
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
@main
|
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
|
||||||
override func application(
|
|
||||||
_ application: UIApplication,
|
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
||||||
) -> Bool {
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "83.5x83.5",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "1024x1024",
|
|
||||||
"idiom" : "ios-marketing",
|
|
||||||
"filename" : "Icon-App-1024x1024@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 762 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |