Update On Tue Mar 18 19:36:33 CET 2025

This commit is contained in:
github-action[bot]
2025-03-18 19:36:34 +01:00
parent 77912647d3
commit 919174b555
109 changed files with 2097 additions and 1284 deletions
+1
View File
@@ -945,3 +945,4 @@ Update On Fri Mar 14 19:34:32 CET 2025
Update On Sat Mar 15 19:32:45 CET 2025
Update On Sun Mar 16 19:33:44 CET 2025
Update On Mon Mar 17 19:35:42 CET 2025
Update On Tue Mar 18 19:36:24 CET 2025
+9 -1
View File
@@ -75,7 +75,15 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string
//log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16])
ecdheKey := uConn.HandshakeState.State13.EcdheKey
keyShareKeys := uConn.HandshakeState.State13.KeyShareKeys
if keyShareKeys == nil {
// WTF???
if retry > 2 {
return nil, errors.New("nil keyShareKeys")
}
continue // retry
}
ecdheKey := keyShareKeys.Ecdhe
if ecdheKey == nil {
// WTF???
if retry > 2 {
+1 -1
View File
@@ -32,7 +32,7 @@ require (
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422
github.com/metacubex/utls v1.6.6
github.com/metacubex/utls v1.6.8-alpha.4
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63
github.com/mroth/weightedrand/v2 v2.1.0
+2 -2
View File
@@ -129,8 +129,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
+27 -27
View File
@@ -592,7 +592,7 @@ dependencies = [
"futures-timer",
"futures-util",
"http 1.2.0",
"indexmap 2.7.1",
"indexmap 2.8.0",
"mime",
"multer",
"num-traits",
@@ -641,7 +641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "741110dda927420a28fbc1c310543d3416f789a6ba96859c2c265843a0a96887"
dependencies = [
"bytes",
"indexmap 2.7.1",
"indexmap 2.8.0",
"serde",
"serde_json",
]
@@ -1258,7 +1258,7 @@ dependencies = [
"boa_interner",
"boa_macros",
"boa_string",
"indexmap 2.7.1",
"indexmap 2.8.0",
"num-bigint",
"rustc-hash 2.1.1",
]
@@ -1284,7 +1284,7 @@ dependencies = [
"fast-float2",
"hashbrown 0.15.2",
"icu_normalizer",
"indexmap 2.7.1",
"indexmap 2.8.0",
"intrusive-collections",
"itertools 0.13.0",
"num-bigint",
@@ -1330,7 +1330,7 @@ dependencies = [
"boa_gc",
"boa_macros",
"hashbrown 0.15.2",
"indexmap 2.7.1",
"indexmap 2.8.0",
"once_cell",
"phf 0.11.3",
"rustc-hash 2.1.1",
@@ -1950,7 +1950,7 @@ dependencies = [
"hex",
"humansize",
"image",
"indexmap 2.7.1",
"indexmap 2.8.0",
"itertools 0.14.0",
"log",
"md-5",
@@ -4357,7 +4357,7 @@ dependencies = [
"futures-core",
"futures-sink",
"http 1.2.0",
"indexmap 2.7.1",
"indexmap 2.8.0",
"slab",
"tokio",
"tokio-util",
@@ -4975,9 +4975,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.7.1"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
@@ -6061,7 +6061,7 @@ dependencies = [
"cfg_aliases 0.2.1",
"codespan-reporting",
"hexf-parse",
"indexmap 2.7.1",
"indexmap 2.8.0",
"log",
"rustc-hash 1.1.0",
"spirv",
@@ -6537,7 +6537,7 @@ dependencies = [
"http-body-util",
"hyper",
"hyper-util",
"indexmap 2.7.1",
"indexmap 2.8.0",
"interprocess",
"nyanpasu-utils",
"pin-project-lite",
@@ -7573,7 +7573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset 0.4.2",
"indexmap 2.7.1",
"indexmap 2.8.0",
]
[[package]]
@@ -7794,7 +7794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64 0.22.1",
"indexmap 2.7.1",
"indexmap 2.8.0",
"quick-xml 0.32.0",
"serde",
"time",
@@ -9290,7 +9290,7 @@ version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"itoa 1.0.14",
"memchr",
"ryu",
@@ -9349,7 +9349,7 @@ dependencies = [
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.7.1",
"indexmap 2.8.0",
"serde",
"serde_derive",
"serde_json",
@@ -9375,7 +9375,7 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"itoa 1.0.14",
"ryu",
"serde",
@@ -9387,7 +9387,7 @@ name = "serde_yaml_ng"
version = "0.10.0"
source = "git+https://github.com/libnyanpasu/serde-yaml-ng.git?branch=feat/specta#3078760ab9e9a3a9e18ebb4c5d3e577eb74c4a5c"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"itoa 1.0.14",
"ryu",
"serde",
@@ -9401,7 +9401,7 @@ version = "0.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"itoa 1.0.14",
"libyml",
"memchr",
@@ -9820,7 +9820,7 @@ version = "2.0.0-rc.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab7f01e9310a820edd31c80fde3cae445295adde21a3f9416517d7d65015b971"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"paste",
"serde",
"serde_json",
@@ -10034,7 +10034,7 @@ dependencies = [
"dmp",
"futures",
"geo",
"indexmap 2.7.1",
"indexmap 2.8.0",
"path-clean",
"pharos",
"reblessive",
@@ -10680,9 +10680,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-updater"
version = "2.6.0"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67cd78a6cbd1255e989e96eedec004e9e8949e6c6359b41f861279aba64ea306"
checksum = "a31bfcfb4a8318008d2108ccfba439d8263cf48867baabf372cb0e9f24771896"
dependencies = [
"base64 0.22.1",
"dirs 6.0.0",
@@ -11283,7 +11283,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"toml_datetime",
"winnow 0.5.40",
]
@@ -11294,7 +11294,7 @@ version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"toml_datetime",
"winnow 0.5.40",
]
@@ -11305,7 +11305,7 @@ version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap 2.7.1",
"indexmap 2.8.0",
"serde",
"serde_spanned",
"toml_datetime",
@@ -12473,7 +12473,7 @@ dependencies = [
"bitflags 2.9.0",
"cfg_aliases 0.2.1",
"document-features",
"indexmap 2.7.1",
"indexmap 2.8.0",
"log",
"naga",
"once_cell",
@@ -13914,7 +13914,7 @@ dependencies = [
"displaydoc",
"flate2",
"hmac",
"indexmap 2.7.1",
"indexmap 2.8.0",
"lzma-rs",
"memchr",
"pbkdf2",
@@ -265,6 +265,7 @@ fn test_http_module_loader() -> JsResult<()> {
import YAML from 'https://esm.run/yaml@2.3.4';
import fromAsync from 'https://esm.run/array-from-async@3.0.0';
import { Base64 } from 'https://esm.run/js-base64@3.7.6';
import { text } from 'https://github.com/libnyanpasu/clash-nyanpasu/raw/refs/heads/main/pnpm-workspace.yaml';
const data = `
object:
@@ -279,6 +280,9 @@ fn test_http_module_loader() -> JsResult<()> {
Promise.resolve(Base64.encode(object.array[1])),
]);
const parsed = YAML.parse(text);
result.push(JSON.stringify(parsed));
export default result;
"#;
@@ -341,6 +345,15 @@ fn test_http_module_loader() -> JsResult<()> {
.ok_or_else(|| JsNativeError::typ().with_message("array element was not a string"))?,
&js_string!("d29ybGQ=")
);
assert!(
default
.get(2, context)?
.as_string()
.ok_or_else(|| JsNativeError::typ().with_message("array element was not a string"))?
.to_std_string_escaped()
.contains("packages"),
"YAML content should contain 'packages' field"
);
Ok(())
}
@@ -22,6 +22,6 @@
},
"devDependencies": {
"@types/lodash-es": "4.17.12",
"@types/react": "19.0.10"
"@types/react": "19.0.11"
}
}
@@ -13,6 +13,11 @@ export const NYANPASU_SETTING_QUERY_KEY = 'settings'
*/
export const NYANPASU_SYSTEM_PROXY_QUERY_KEY = 'system-proxy'
/**
* Nyanpasu chains log query key, fn: getPostProcessingOutput
*/
export const NYANPASU_POST_PROCESSING_QUERY_KEY = 'post-processing'
/**
* Clash version query key, used to fetch clash version from query
*/
@@ -21,7 +26,7 @@ export const CLASH_VERSION_QUERY_KEY = 'clash-version'
/**
* Nyanpasu profile query key, used to fetch profiles from query
*/
export const ROFILES_QUERY_KEY = 'profiles'
export const RROFILES_QUERY_KEY = 'profiles'
/**
* Clash log query key, used by clash ws provider to mutate logs via clash logs ws api
@@ -9,6 +9,7 @@ export * from './use-clash-logs'
export * from './use-clash-memory'
export * from './use-clash-traffic'
export * from './use-clash-version'
export * from './use-post-processing-output'
export * from './use-profile-content'
export * from './use-profile'
export * from './use-proxy-mode'
@@ -16,7 +17,6 @@ export * from './use-runtime-profile'
export * from './use-settings'
export * from './use-system-proxy'
export * from './use-system-service'
export * from './useClash'
export * from './useClashCore'
export { commands } from './bindings'
@@ -0,0 +1,25 @@
import { unwrapResult } from '@/utils'
import { useQuery } from '@tanstack/react-query'
import { commands } from './bindings'
import { NYANPASU_POST_PROCESSING_QUERY_KEY } from './consts'
/**
* Custom hook for fetching post-processing output using React Query.
* Another name is chains/script logs.
*
* This hook queries post-processing output data using a predefined query key
* and fetches the data through the `commands.getPostprocessingOutput` command.
* The result is unwrapped using the `unwrapResult` utility function.
*/
export const usePostProcessingOutput = () => {
const query = useQuery({
queryKey: [NYANPASU_POST_PROCESSING_QUERY_KEY],
queryFn: async () => {
return unwrapResult(await commands.getPostprocessingOutput())
},
})
return {
...query,
}
}
@@ -7,7 +7,7 @@ import {
type ProfilesBuilder,
type RemoteProfileOptionsBuilder,
} from './bindings'
import { ROFILES_QUERY_KEY } from './consts'
import { RROFILES_QUERY_KEY } from './consts'
type URLImportParams = Parameters<typeof commands.importProfile>
@@ -106,7 +106,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
* @returns A promise resolving to an object containing the profile list along with the extended helper functions.
*/
const query = useQuery({
queryKey: [ROFILES_QUERY_KEY],
queryKey: [RROFILES_QUERY_KEY],
queryFn: async () => {
const result = unwrapResult(await commands.getProfiles())
@@ -157,7 +157,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
},
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -185,7 +185,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
return unwrapResult(await commands.updateProfile(uid, option))
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -216,7 +216,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
},
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -240,7 +240,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
},
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -263,7 +263,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
)
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -280,7 +280,7 @@ export const useProfile = (options?: { without_helper_fn?: boolean }) => {
return unwrapResult(await commands.deleteProfile(uid))
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [ROFILES_QUERY_KEY] })
queryClient.invalidateQueries({ queryKey: [RROFILES_QUERY_KEY] })
},
})
@@ -1,132 +0,0 @@
import useSWR from 'swr'
import {
ClashConfig,
Profile,
ProfilesBuilder,
RemoteProfileOptionsBuilder,
} from '@/index'
import * as tauri from '@/service/tauri'
import { clash } from '../service/clash'
/**
* useClash with swr.
* Data from tauri backend.
*/
export const useClash = () => {
const { deleteConnections, ...api } = clash()
const getClashInfo = useSWR('getClashInfo', tauri.getClashInfo)
const getConfigs = useSWR('getClashConfig', api.getConfigs)
const setConfigs = async (payload: Partial<ClashConfig>) => {
try {
await tauri.patchClashConfig(payload)
await Promise.all([getClashInfo.mutate(), getConfigs.mutate()])
} catch (e) {
console.error(e)
}
return getClashInfo.data
}
const getVersion = useSWR('getClashVersion', api.getVersion)
const getRules = useSWR('getClashRules', api.getRules)
const getRuntimeExists = useSWR('getRuntimeExists', tauri.getRuntimeExists)
const getProfiles = useSWR('getProfiles', tauri.getProfiles)
const setProfiles = async (uid: string, profile: Partial<Profile>) => {
await tauri.setProfiles({ uid, profile })
await getProfiles.mutate()
await getRuntimeLogs.mutate()
}
const setProfilesConfig = async (profiles: ProfilesBuilder) => {
await tauri.setProfilesConfig(profiles)
await getProfiles.mutate()
await getRuntimeLogs.mutate()
}
const createProfile = async (item: Partial<Profile>, data?: string) => {
await tauri.createProfile(item, data)
await getProfiles.mutate()
}
const updateProfile = async (
uid: string,
option?: RemoteProfileOptionsBuilder,
) => {
await tauri.updateProfile(uid, option)
await getProfiles.mutate()
}
const deleteProfile = async (uid: string) => {
await tauri.deleteProfile(uid)
await getProfiles.mutate()
}
const getProfileFile = async (id?: string) => {
if (id) {
const result = await tauri.readProfileFile(id)
if (result) {
return result
} else {
return ''
}
} else {
return ''
}
}
const importProfile = async (
url: string,
option: RemoteProfileOptionsBuilder,
) => {
await tauri.importProfile(url, option)
await getProfiles.mutate()
}
const getRuntimeLogs = useSWR('getRuntimeLogs', tauri.getRuntimeLogs, {
refreshInterval: 1000,
})
const reorderProfilesByList = async (list: string[]) => {
await tauri.reorderProfilesByList(list)
await getProfiles.mutate()
}
return {
getClashInfo,
getConfigs,
setConfigs,
getVersion,
getRules,
deleteConnections,
getRuntimeExists,
getProfiles,
setProfiles,
setProfilesConfig,
createProfile,
updateProfile,
deleteProfile,
importProfile,
viewProfile: tauri.viewProfile,
getProfileFile,
getRuntimeLogs,
setProfileFile: tauri.saveProfileFile,
reorderProfilesByList,
}
}
@@ -9,6 +9,7 @@ import {
NYANPASU_BACKEND_EVENT_NAME,
NYANPASU_SETTING_QUERY_KEY,
NYANPASU_SYSTEM_PROXY_QUERY_KEY,
RROFILES_QUERY_KEY,
} from '../ipc/consts'
type EventPayload = 'nyanpasu_config' | 'clash_config' | 'proxies' | 'profiles'
@@ -24,6 +25,7 @@ const CLASH_CONFIG_MUTATION_KEYS = [
CLASH_VERSION_QUERY_KEY,
CLASH_INFO_QUERY_KEY,
CLASH_CONFIG_QUERY_KEY,
RROFILES_QUERY_KEY,
// TODO: clash rules hook refetch
// TODO: clash rules providers hook refetch
// TODO: proxies hook refetch
@@ -0,0 +1,50 @@
/**
* Retry a function with exponential backoff
*
* @param fn - The function to retry
* @param options - Retry options
* @returns The result of the function
* @throws The last error encountered
*/
export async function retry<T>(
fn: () => Promise<T>,
options: {
maxRetries?: number
initialDelay?: number
maxDelay?: number
factor?: number
retryCondition?: (error: Error) => boolean
} = {},
): Promise<T> {
const {
maxRetries = 3,
initialDelay = 200,
maxDelay = 5000,
factor = 2,
retryCondition = () => true,
} = options
let lastError: Error = new Error('Unknown error occurred')
let delay = initialDelay
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn()
} catch (error) {
if (attempt === maxRetries || !retryCondition(error as Error)) {
throw error
}
lastError = error as Error
// Wait for the specified delay
await new Promise((resolve) => setTimeout(resolve, delay))
// Increase the delay for the next attempt (exponential backoff)
delay = Math.min(delay * factor, maxDelay)
}
}
throw lastError
}
@@ -53,12 +53,12 @@
"@csstools/normalize.css": "12.1.1",
"@emotion/babel-plugin": "11.13.5",
"@emotion/react": "11.14.0",
"@iconify/json": "2.2.317",
"@iconify/json": "2.2.318",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.68.0",
"@tanstack/react-router": "1.114.23",
"@tanstack/router-devtools": "1.114.23",
"@tanstack/router-plugin": "1.114.23",
"@tanstack/react-router": "1.114.24",
"@tanstack/router-devtools": "1.114.24",
"@tanstack/router-plugin": "1.114.24",
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
"@tauri-apps/plugin-dialog": "2.2.0",
"@tauri-apps/plugin-fs": "2.2.0",
@@ -66,8 +66,8 @@
"@tauri-apps/plugin-os": "2.2.1",
"@tauri-apps/plugin-process": "2.2.0",
"@tauri-apps/plugin-shell": "2.2.0",
"@tauri-apps/plugin-updater": "2.6.0",
"@types/react": "19.0.10",
"@tauri-apps/plugin-updater": "2.6.1",
"@types/react": "19.0.11",
"@types/react-dom": "19.0.4",
"@types/validator": "13.12.2",
"@vitejs/plugin-legacy": "6.0.2",
@@ -7,11 +7,7 @@ import { formatError } from '@/utils'
import { message } from '@/utils/notification'
import { Add } from '@mui/icons-material'
import { alpha, ListItemButton, useTheme } from '@mui/material'
import {
ProfileQueryResultItem,
useClash,
useProfile,
} from '@nyanpasu/interface'
import { ProfileQueryResultItem, useProfile } from '@nyanpasu/interface'
import { ClashProfile, filterProfiles } from '../utils'
import ChainItem from './chain-item'
import { atomChainsSelected, atomGlobalChainCurrent } from './store'
@@ -29,11 +25,11 @@ export const SideChain = ({ onChainEdit }: SideChainProps) => {
const currentProfileUid = useAtomValue(atomChainsSelected)
const { setProfiles, reorderProfilesByList } = useClash()
const { query, upsert, patch, sort } = useProfile()
const { query, upsert } = useProfile()
const profiles = query.data
const { clash, chain } = filterProfiles(query.data?.items)
const { clash, chain } = filterProfiles(profiles?.items)
const currentProfile = useMemo(() => {
return clash?.find((item) => item.uid === currentProfileUid) as ClashProfile
@@ -41,7 +37,7 @@ export const SideChain = ({ onChainEdit }: SideChainProps) => {
const handleChainClick = useLockFn(async (uid: string) => {
const chains = isGlobalChainCurrent
? (query.data?.chain ?? [])
? (profiles?.chain ?? [])
: (currentProfile?.chain ?? [])
const updatedChains = chains.includes(uid)
@@ -55,7 +51,13 @@ export const SideChain = ({ onChainEdit }: SideChainProps) => {
if (!currentProfile?.uid) {
return
}
await setProfiles(currentProfile!.uid, { chain: updatedChains })
await patch.mutateAsync({
uid: currentProfile.uid,
profile: {
...currentProfile,
chain: updatedChains,
},
})
}
} catch (e) {
message(`Apply error: ${formatError(e)}`, {
@@ -77,14 +79,14 @@ export const SideChain = ({ onChainEdit }: SideChainProps) => {
values={reorderValues}
onReorder={(values) => {
const profileUids = clash?.map((item) => item.uid) || []
reorderProfilesByList([...profileUids, ...values])
sort.mutate([...profileUids, ...values])
}}
layoutScroll
style={{ overflowY: 'scroll' }}
>
{chain?.map((item, index) => {
const selected = isGlobalChainCurrent
? query.data?.chain?.includes(item.uid)
? profiles?.chain?.includes(item.uid)
: currentProfile?.chain?.includes(item.uid)
return (
@@ -1,12 +1,12 @@
import { isEmpty } from 'lodash-es'
import { memo } from 'react'
import { useAtomValue } from 'jotai'
import { memo, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { VList } from 'virtua'
import { RamenDining, Terminal } from '@mui/icons-material'
import { Divider } from '@mui/material'
import { useClash, useProfile } from '@nyanpasu/interface'
import { usePostProcessingOutput, useProfile } from '@nyanpasu/interface'
import { cn } from '@nyanpasu/ui'
import { filterProfiles } from '../utils'
import { atomChainsSelected, atomGlobalChainCurrent } from './store'
const LogListItem = memo(function LogListItem({
name,
@@ -37,11 +37,25 @@ export interface SideLogProps {
export const SideLog = ({ className }: SideLogProps) => {
const { t } = useTranslation()
// const { getRuntimeLogs, getProfiles } = useClash()
const { query } = useProfile()
const { chain } = filterProfiles(query.data?.items)
const profiles = query.data?.items
const { data } = usePostProcessingOutput()
const isGlobalChainCurrent = useAtomValue(atomGlobalChainCurrent)
const currentProfileUid = useAtomValue(atomChainsSelected)
const currentLogs = useMemo(() => {
if (currentProfileUid) {
return data?.scopes[currentProfileUid]
}
if (isGlobalChainCurrent) {
return data?.scopes.global
}
}, [currentProfileUid, data, isGlobalChainCurrent])
return (
<div className={cn('w-full', className)}>
@@ -56,10 +70,10 @@ export const SideLog = ({ className }: SideLogProps) => {
<Divider />
<VList className="flex flex-col gap-2 overflow-auto p-2 select-text">
{/* {!isEmpty(getRuntimeLogs.data) ? (
Object.entries(getRuntimeLogs.data).map(([uid, content]) => {
return content.map((item, index) => {
const name = scripts?.find((script) => script.uid === uid)?.name
{currentLogs ? (
Object.entries(currentLogs).map(([uid, content]) => {
return content?.map((item, index) => {
const name = profiles?.find((script) => script.uid === uid)?.name
return (
<LogListItem
@@ -71,12 +85,12 @@ export const SideLog = ({ className }: SideLogProps) => {
)
})
})
) : ( */}
<div className="flex h-full min-h-48 w-full flex-col items-center justify-center">
<RamenDining className="!size-10" />
<p>{t('No Logs')}</p>
</div>
{/* )} */}
) : (
<div className="flex h-full min-h-48 w-full flex-col items-center justify-center">
<RamenDining className="!size-10" />
<p>{t('No Logs')}</p>
</div>
)}
</VList>
</div>
)
@@ -8,7 +8,6 @@ import { Divider } from '@mui/material'
import {
Profile,
ProfileTemplate,
useClash,
useProfile,
useProfileContent,
} from '@nyanpasu/interface'
@@ -69,9 +68,6 @@ export const ScriptDialog = ({
}: ScriptDialogProps) => {
const { t } = useTranslation()
// const { getProfileFile, setProfileFile, createProfile, setProfiles } =
// useClash()
const { create, patch } = useProfile()
const contentFn = useProfileContent(profile?.uid ?? '')
@@ -149,9 +145,9 @@ export const ScriptDialog = ({
useAsyncEffect(async () => {
if (isEdit) {
await contentFn.query.refetch()
const result = await contentFn.query.refetch()
editor.value = contentFn.query.data ?? ''
editor.value = result.data ?? ''
editor.language = getLanguage(profile!.type)!
} else {
editor.value = ProfileTemplate.merge
@@ -253,7 +249,7 @@ export const ScriptDialog = ({
<Divider orientation="vertical" />
<Suspense fallback={null}>
{openMonaco && (
{openMonaco && !contentFn.query.isPending && (
<ProfileMonacoViewer
className="w-full"
value={editor.value}
@@ -8,7 +8,6 @@ import { message } from '@/utils/notification'
import { Box, List, ListItem } from '@mui/material'
import {
ClashCore,
useClash,
useClashConnections,
useClashCores,
useClashVersion,
@@ -28,7 +28,6 @@ import { Badge, Button, CircularProgress, IconButton } from '@mui/material'
import Grid from '@mui/material/Grid2'
import {
RemoteProfileOptionsBuilder,
useClash,
useProfile,
type RemoteProfile,
} from '@nyanpasu/interface'
@@ -50,51 +49,50 @@ export const Route = createFileRoute('/profiles')({
function ProfilePage() {
const { t } = useTranslation()
const { getRuntimeLogs } = useClash()
const { query, update } = useProfile()
const profiles = useMemo(() => {
return filterProfiles(query.data?.items)
}, [query.data?.items])
const maxLogLevelTriggered = useMemo(() => {
const currentProfileChains =
(
query.data?.items?.find(
// TODO: 支持多 Profile
(item) => query.data?.current?.[0] === item.uid,
// TODO: fix any type
) as any
)?.chain || []
return Object.entries(getRuntimeLogs.data || {}).reduce(
(acc, [key, value]) => {
const accKey = currentProfileChains.includes(key) ? 'current' : 'global'
if (acc[accKey] === 'error') {
return acc
}
for (const log of value) {
switch (log[0]) {
case 'error':
return { ...acc, [accKey]: 'error' }
case 'warn':
acc = { ...acc, [accKey]: 'warn' }
break
case 'info':
if (acc[accKey] !== 'warn') {
acc = { ...acc, [accKey]: 'info' }
}
break
}
}
return acc
},
{} as {
global: undefined | 'info' | 'error' | 'warn'
current: undefined | 'info' | 'error' | 'warn'
},
)
}, [query.data, getRuntimeLogs.data])
// TODO: fix me
// const maxLogLevelTriggered = useMemo(() => {
// const currentProfileChains =
// (
// query.data?.items?.find(
// // TODO: 支持多 Profile
// (item) => query.data?.current?.[0] === item.uid,
// // TODO: fix any type
// ) as any
// )?.chain || []
// return Object.entries(getRuntimeLogs.data || {}).reduce(
// (acc, [key, value]) => {
// const accKey = currentProfileChains.includes(key) ? 'current' : 'global'
// if (acc[accKey] === 'error') {
// return acc
// }
// for (const log of value) {
// switch (log[0]) {
// case 'error':
// return { ...acc, [accKey]: 'error' }
// case 'warn':
// acc = { ...acc, [accKey]: 'warn' }
// break
// case 'info':
// if (acc[accKey] !== 'warn') {
// acc = { ...acc, [accKey]: 'info' }
// }
// break
// }
// }
// return acc
// },
// {} as {
// global: undefined | 'info' | 'error' | 'warn'
// current: undefined | 'info' | 'error' | 'warn'
// },
// )
// }, [query.data, getRuntimeLogs.data])
const [globalChain, setGlobalChain] = useAtom(atomGlobalChainCurrent)
@@ -198,14 +196,14 @@ function ProfilePage() {
</IconButton>
<Badge
variant="dot"
color={
maxLogLevelTriggered.global === 'error'
? 'error'
: maxLogLevelTriggered.global === 'warn'
? 'warning'
: 'primary'
}
invisible={!maxLogLevelTriggered.global}
// color={
// maxLogLevelTriggered.global === 'error'
// ? 'error'
// : maxLogLevelTriggered.global === 'warn'
// ? 'warning'
// : 'primary'
// }
// invisible={!maxLogLevelTriggered.global}
>
<Button
size="small"
@@ -248,7 +246,7 @@ function ProfilePage() {
item={item}
onClickChains={onClickChains}
selected={query.data?.current?.includes(item.uid)}
maxLogLevelTriggered={maxLogLevelTriggered}
// maxLogLevelTriggered={maxLogLevelTriggered}
chainsSelected={chainsSelected === item.uid}
/>
</motion.div>
+1 -1
View File
@@ -24,7 +24,7 @@
"@radix-ui/react-scroll-area": "1.2.3",
"@tauri-apps/api": "2.3.0",
"@types/d3": "7.4.3",
"@types/react": "19.0.10",
"@types/react": "19.0.11",
"@vitejs/plugin-react": "4.3.4",
"ahooks": "3.8.4",
"d3": "7.9.0",
+3 -3
View File
@@ -2,10 +2,10 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.3",
"mihomo_alpha": "alpha-dee5898",
"mihomo_alpha": "alpha-7c444a9",
"clash_rs": "v0.7.6",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.7.6-alpha+sha.47236aa"
"clash_rs_alpha": "0.7.6-alpha+sha.3cc3aa2"
},
"arch_template": {
"mihomo": {
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-03-16T22:20:31.758Z"
"updated_at": "2025-03-17T22:20:57.095Z"
}
+1 -1
View File
@@ -109,7 +109,7 @@
"typescript": "5.8.2",
"typescript-eslint": "8.26.1"
},
"packageManager": "pnpm@10.6.3",
"packageManager": "pnpm@10.6.4",
"engines": {
"node": "22.14.0"
},
+214 -214
View File
@@ -203,8 +203,8 @@ importers:
specifier: 4.17.12
version: 4.17.12
'@types/react':
specifier: 19.0.10
version: 19.0.10
specifier: 19.0.11
version: 19.0.11
frontend/nyanpasu:
dependencies:
@@ -219,7 +219,7 @@ importers:
version: 3.2.2(react@19.0.0)
'@emotion/styled':
specifier: 11.14.0
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@juggle/resize-observer':
specifier: 3.4.0
version: 3.4.0
@@ -228,13 +228,13 @@ importers:
version: 0.3.0
'@mui/icons-material':
specifier: 6.4.7
version: 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
version: 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/lab':
specifier: 6.0.0-beta.30
version: 6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material':
specifier: 6.4.7
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@nyanpasu/interface':
specifier: workspace:^
version: link:../interface
@@ -246,7 +246,7 @@ importers:
version: 4.0.14
'@tanstack/router-zod-adapter':
specifier: 1.81.5
version: 1.81.5(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.2)
version: 1.81.5(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.2)
'@tauri-apps/api':
specifier: 2.3.0
version: 2.3.0
@@ -273,19 +273,19 @@ importers:
version: 24.2.3(typescript@5.8.2)
jotai:
specifier: 2.12.2
version: 2.12.2(@types/react@19.0.10)(react@19.0.0)
version: 2.12.2(@types/react@19.0.11)(react@19.0.0)
json-schema:
specifier: 0.4.0
version: 0.4.0
material-react-table:
specifier: 3.2.1
version: 3.2.1(2e84544a0e977e5cbb40e088279de64c)
version: 3.2.1(654f09cb8207d585a138693171e30e7f)
monaco-editor:
specifier: 0.52.2
version: 0.52.2
mui-color-input:
specifier: 5.0.1
version: 5.0.1(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 5.0.1(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react:
specifier: 19.0.0
version: 19.0.0
@@ -300,13 +300,13 @@ importers:
version: 1.6.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-hook-form-mui:
specifier: 7.5.0
version: 7.5.0(b98e4d9419cc277791cc5997c01ae06f)
version: 7.5.0(ea3e5f5c412ba73f5e2ef92ffc8e5c95)
react-i18next:
specifier: 15.4.1
version: 15.4.1(i18next@24.2.3(typescript@5.8.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-markdown:
specifier: 10.1.0
version: 10.1.0(@types/react@19.0.10)(react@19.0.0)
version: 10.1.0(@types/react@19.0.11)(react@19.0.0)
react-split-grid:
specifier: 1.0.4
version: 1.0.4(react@19.0.0)
@@ -331,10 +331,10 @@ importers:
version: 11.13.5
'@emotion/react':
specifier: 11.14.0
version: 11.14.0(@types/react@19.0.10)(react@19.0.0)
version: 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@iconify/json':
specifier: 2.2.317
version: 2.2.317
specifier: 2.2.318
version: 2.2.318
'@monaco-editor/react':
specifier: 4.7.0
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -342,14 +342,14 @@ importers:
specifier: 5.68.0
version: 5.68.0(react@19.0.0)
'@tanstack/react-router':
specifier: 1.114.23
version: 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: 1.114.24
version: 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-devtools':
specifier: 1.114.23
version: 1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.23)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)
specifier: 1.114.24
version: 1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.24)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)
'@tanstack/router-plugin':
specifier: 1.114.23
version: 1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
specifier: 1.114.24
version: 1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.2.2
version: 2.2.2
@@ -372,14 +372,14 @@ importers:
specifier: 2.2.0
version: 2.2.0
'@tauri-apps/plugin-updater':
specifier: 2.6.0
version: 2.6.0
specifier: 2.6.1
version: 2.6.1
'@types/react':
specifier: 19.0.10
version: 19.0.10
specifier: 19.0.11
version: 19.0.11
'@types/react-dom':
specifier: 19.0.4
version: 19.0.4(@types/react@19.0.10)
version: 19.0.4(@types/react@19.0.11)
'@types/validator':
specifier: 13.12.2
version: 13.12.2
@@ -454,19 +454,19 @@ importers:
version: 0.3.0
'@mui/icons-material':
specifier: 6.4.7
version: 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
version: 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/lab':
specifier: 6.0.0-beta.30
version: 6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material':
specifier: 6.4.7
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-portal':
specifier: 1.1.4
version: 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-scroll-area':
specifier: 1.2.3
version: 1.2.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
version: 1.2.3(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tauri-apps/api':
specifier: 2.3.0
version: 2.3.0
@@ -474,8 +474,8 @@ importers:
specifier: 7.4.3
version: 7.4.3
'@types/react':
specifier: 19.0.10
version: 19.0.10
specifier: 19.0.11
version: 19.0.11
'@vitejs/plugin-react':
specifier: 4.3.4
version: 4.3.4(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
@@ -515,7 +515,7 @@ importers:
devDependencies:
'@emotion/react':
specifier: 11.14.0
version: 11.14.0(@types/react@19.0.10)(react@19.0.0)
version: 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@types/d3-interpolate-path':
specifier: 2.0.3
version: 2.0.3
@@ -1674,8 +1674,8 @@ packages:
'@vue/compiler-sfc':
optional: true
'@iconify/json@2.2.317':
resolution: {integrity: sha512-RMf7b3Wd4FMKR7roYmJ8mO6Lwm1JCzuuuVCi0aPcBvBwZkgoWSNHEOFG504L3GMz95cid5KS5Yc4Gt1TPA5bJA==}
'@iconify/json@2.2.318':
resolution: {integrity: sha512-8hmJxD/l322LLyQzt9s6aPCE6O+p86H9GVFhoH3hEQ9PRrU5O3Ptf8tlzFKzkBrBoEqdSzkAG5j8bwGt47Ragw==}
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
@@ -2746,16 +2746,16 @@ packages:
peerDependencies:
react: ^18 || ^19
'@tanstack/react-router-devtools@1.114.23':
resolution: {integrity: sha512-eOTlXeLlT5PfSrOrDEljTz8F7Sl3YjjI+yTGn5ern0FrFlc3GlBxJqFaKC19mT9H4ZkwETnSqDHrLZKV06ykRA==}
'@tanstack/react-router-devtools@1.114.24':
resolution: {integrity: sha512-sxfrcT/1QWwp/FP7U8y8AMIeRkw8uTvWguRpTfpow2zML6/U1PSKz7ShpXD7NZ2MakrD14nidq1rruC1D39kTA==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.114.23
'@tanstack/react-router': ^1.114.24
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
'@tanstack/react-router@1.114.23':
resolution: {integrity: sha512-L9TS8HE5nvXzCyjwlwfXwnC7pfiofbDLCSAGN7Me2jUbxHPyQpAtxRYqtByANaFVclOJgYBmZkx1m6/GVk9oiA==}
'@tanstack/react-router@1.114.24':
resolution: {integrity: sha512-xHrgcYi/GvwBh/lTpVpZtDFGA8f8oBSSsFagAGgSGkvz+EPTIhAML0hvwKCV1jP2HaIdU/7aJk14y4q8TT2M4Q==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -2780,15 +2780,15 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@tanstack/router-core@1.114.23':
resolution: {integrity: sha512-aJkqAtVyRbdNBuoAsiy5Jmc9MYa2Gt9r1s/xlYBDfSEWoJzhMmWVoKfgBI6Ggeu3dwe6uCr/gkBRmpRkgWjg1w==}
'@tanstack/router-core@1.114.24':
resolution: {integrity: sha512-OmYX/oPby8CMfpm3a4xCBB9mfo6mqe2OAByz62XFD8ZcXvcDEcpHB5t2/ZrX2CCNH4gXQHUyZzl9+PxqqIpNPw==}
engines: {node: '>=12'}
'@tanstack/router-devtools-core@1.114.23':
resolution: {integrity: sha512-PP2JFokatFdL3RANKibZPWK1L1vy4LM2chEvwyJYVUhAKg+gWPIB4aE5FnhkI/sn7N/8dzt83Xbruj+NPEPfmg==}
'@tanstack/router-devtools-core@1.114.24':
resolution: {integrity: sha512-xGy0SmvWqS1r/sDCdqfdRRNlhUmNSRABcX95xoAXaBsRFmd7Gn6i/TfW9waZyCFTkfLq6Hs8ixFBXo+BGOG0mg==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/router-core': ^1.114.23
'@tanstack/router-core': ^1.114.24
csstype: ^3.0.10
solid-js: '>=1.9.5'
tiny-invariant: ^1.3.3
@@ -2796,11 +2796,11 @@ packages:
csstype:
optional: true
'@tanstack/router-devtools@1.114.23':
resolution: {integrity: sha512-i7F7VkA73fVvaZuPc/hsAiTlkDu/PF11Y3ERDNGL8G9NUaDEKeW8rvK0V+KTNNg8Tnm0FOHH4xohquzBXPkcuA==}
'@tanstack/router-devtools@1.114.24':
resolution: {integrity: sha512-+WOTp05bp33bQmqCz2hifCT3dqwUp+KabcYArSuGhNp7AoU784EvKetYAky0zb/ezrwcD3PoujI3bDCKh+cAwg==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.114.23
'@tanstack/react-router': ^1.114.24
csstype: ^3.0.10
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
@@ -2808,21 +2808,21 @@ packages:
csstype:
optional: true
'@tanstack/router-generator@1.114.23':
resolution: {integrity: sha512-+6YwCXXL4H6CwdWLIrO8Bmy9HZIB8p9yJGcIBGXefN3D0vOUOi7EJa2+MQgQCQgjdygP4zuutqXD/5qxEZQQNw==}
'@tanstack/router-generator@1.114.24':
resolution: {integrity: sha512-rKVyT9ArplwzLIGdENUxAFJdWsCrCLh9+Kts59EPv5fNvJLZX14NNcnh1hn8gq3dfRu3HmBU68NRG0d4dcw3kA==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.114.23
'@tanstack/react-router': ^1.114.24
peerDependenciesMeta:
'@tanstack/react-router':
optional: true
'@tanstack/router-plugin@1.114.23':
resolution: {integrity: sha512-4D5558eQ4So2HXnVrN5inZs4tU5nlv75VH6u95NZvVSGc+zUBryzBg7ElkhzMh+UPQoJ0RTf4NxNcKG3vw2+6w==}
'@tanstack/router-plugin@1.114.24':
resolution: {integrity: sha512-3RYR2gct2iR5nO0Vc+ShhS9VlUHrV2im+RuPKXGB04PdWWrRoM2EDkhjepg0CzmD5zgT2Tafp5Nysu9XyR0CGA==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
'@tanstack/react-router': ^1.114.23
'@tanstack/react-router': ^1.114.24
vite: '>=5.0.0 || >=6.0.0'
vite-plugin-solid: ^2.11.2
webpack: '>=5.92.0'
@@ -2958,8 +2958,8 @@ packages:
'@tauri-apps/plugin-shell@2.2.0':
resolution: {integrity: sha512-iC3Ic1hLmasoboG7BO+7p+AriSoqAwKrIk+Hpk+S/bjTQdXqbl2GbdclghI4gM32X0bls7xHzIFqhRdrlvJeaA==}
'@tauri-apps/plugin-updater@2.6.0':
resolution: {integrity: sha512-j74RUolLIhQDQwrff6R28xIewYVXME1gFU+d+4LYN1dLRzLD+ySa7VHqzyWYxWEvm+TPZ7lkUxa5a9uH9Ist3A==}
'@tauri-apps/plugin-updater@2.6.1':
resolution: {integrity: sha512-iiOevw4kc12Ok99J9KthXwUqwPv1sYjG+tNEDZqPmwvOmIq7s58nKMRz6NJPKXT4U16NzMPffFcP/LUOsz6c4A==}
'@trivago/prettier-plugin-sort-imports@4.3.0':
resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==}
@@ -3175,8 +3175,8 @@ packages:
peerDependencies:
'@types/react': '*'
'@types/react@19.0.10':
resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==}
'@types/react@19.0.11':
resolution: {integrity: sha512-vrdxRZfo9ALXth6yPfV16PYTLZwsUWhVjjC+DkfE5t1suNSbBrWC9YqSuuxJZ8Ps6z1o2ycRpIqzZJIgklq4Tw==}
'@types/responselike@1.0.3':
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
@@ -9234,7 +9234,7 @@ snapshots:
'@emotion/memoize@0.9.0': {}
'@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0)':
'@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@emotion/babel-plugin': 11.13.5
@@ -9246,7 +9246,7 @@ snapshots:
hoist-non-react-statics: 3.3.2
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
transitivePeerDependencies:
- supports-color
@@ -9260,18 +9260,18 @@ snapshots:
'@emotion/sheet@1.4.0': {}
'@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
'@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@emotion/babel-plugin': 11.13.5
'@emotion/is-prop-valid': 1.3.0
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/serialize': 1.3.3
'@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0)
'@emotion/utils': 1.4.2
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
transitivePeerDependencies:
- supports-color
@@ -9453,7 +9453,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@iconify/json@2.2.317':
'@iconify/json@2.2.318':
dependencies:
'@iconify/types': 2.0.0
pathe: 1.1.2
@@ -9562,56 +9562,56 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
'@mui/base@5.0.0-beta.69(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@mui/base@5.0.0-beta.69(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@mui/utils': 6.4.6(@types/react@19.0.11)(react@19.0.0)
'@popperjs/core': 2.11.8
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/core-downloads-tracker@6.4.7': {}
'@mui/icons-material@6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
'@mui/icons-material@6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/lab@6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@mui/lab@6.0.0-beta.30(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/base': 5.0.0-beta.69(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/system': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/base': 5.0.0-beta.69(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/system': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@mui/utils': 6.4.6(@types/react@19.0.11)(react@19.0.0)
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@types/react': 19.0.10
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@types/react': 19.0.11
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/core-downloads-tracker': 6.4.7
'@mui/system': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/system': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@mui/utils': 6.4.6(@types/react@19.0.11)(react@19.0.0)
'@popperjs/core': 2.11.8
'@types/react-transition-group': 4.4.12(@types/react@19.0.10)
'@types/react-transition-group': 4.4.12(@types/react@19.0.11)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
@@ -9620,29 +9620,29 @@ snapshots:
react-is: 19.0.0
react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@types/react': 19.0.10
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@types/react': 19.0.11
'@mui/private-theming@5.16.6(@types/react@19.0.10)(react@19.0.0)':
'@mui/private-theming@5.16.6(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.10
'@mui/utils': 5.16.6(@types/react@19.0.10)(react@19.0.0)
'@mui/utils': 5.16.6(@types/react@19.0.11)(react@19.0.0)
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/private-theming@6.4.6(@types/react@19.0.10)(react@19.0.0)':
'@mui/private-theming@6.4.6(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/utils': 6.4.6(@types/react@19.0.11)(react@19.0.0)
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/styled-engine@5.16.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
'@mui/styled-engine@5.16.6(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.10
'@emotion/cache': 11.14.0
@@ -9650,10 +9650,10 @@ snapshots:
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@emotion/cache': 11.14.0
@@ -9663,85 +9663,85 @@ snapshots:
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/system@5.16.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
'@mui/system@5.16.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.10
'@mui/private-theming': 5.16.6(@types/react@19.0.10)(react@19.0.0)
'@mui/styled-engine': 5.16.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/utils': 5.16.6(@types/react@19.0.10)(react@19.0.0)
'@mui/private-theming': 5.16.6(@types/react@19.0.11)(react@19.0.0)
'@mui/styled-engine': 5.16.6(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@mui/utils': 5.16.6(@types/react@19.0.11)(react@19.0.0)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@types/react': 19.0.10
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@types/react': 19.0.11
'@mui/system@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
'@mui/system@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/private-theming': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/styled-engine': 6.4.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
'@mui/private-theming': 6.4.6(@types/react@19.0.11)(react@19.0.0)
'@mui/styled-engine': 6.4.6(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(react@19.0.0)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@mui/utils': 6.4.6(@types/react@19.0.11)(react@19.0.0)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@types/react': 19.0.10
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@types/react': 19.0.11
'@mui/types@7.2.21(@types/react@19.0.10)':
'@mui/types@7.2.21(@types/react@19.0.11)':
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/utils@5.16.6(@types/react@19.0.10)(react@19.0.0)':
'@mui/utils@5.16.6(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.10
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@types/prop-types': 15.7.14
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0
react-is: 18.3.1
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/utils@6.4.6(@types/react@19.0.10)(react@19.0.0)':
'@mui/utils@6.4.6(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.0
'@mui/types': 7.2.21(@types/react@19.0.10)
'@mui/types': 7.2.21(@types/react@19.0.11)
'@types/prop-types': 15.7.14
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0
react-is: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@mui/x-date-pickers@7.9.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@mui/x-date-pickers@7.9.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.10
'@mui/base': 5.0.0-beta.69(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/system': 5.16.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/utils': 5.16.6(@types/react@19.0.10)(react@19.0.0)
'@types/react-transition-group': 4.4.12(@types/react@19.0.10)
'@mui/base': 5.0.0-beta.69(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/system': 5.16.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/utils': 5.16.6(@types/react@19.0.11)(react@19.0.0)
'@types/react-transition-group': 4.4.12(@types/react@19.0.11)
clsx: 2.1.1
prop-types: 15.8.1
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
dayjs: 1.11.13
transitivePeerDependencies:
- '@types/react'
@@ -10039,88 +10039,88 @@ snapshots:
'@radix-ui/primitive@1.1.1': {}
'@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.11)(react@19.0.0)':
dependencies:
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@radix-ui/react-context@1.1.1(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-context@1.1.1(@types/react@19.0.11)(react@19.0.0)':
dependencies:
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@radix-ui/react-direction@1.1.0(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-direction@1.1.0(@types/react@19.0.11)(react@19.0.0)':
dependencies:
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.11)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10)
'@types/react': 19.0.11
'@types/react-dom': 19.0.4(@types/react@19.0.11)
'@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.11)(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.11)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10)
'@types/react': 19.0.11
'@types/react-dom': 19.0.4(@types/react@19.0.11)
'@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-slot': 1.1.2(@types/react@19.0.11)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10)
'@types/react': 19.0.11
'@types/react-dom': 19.0.4(@types/react@19.0.11)
'@radix-ui/react-scroll-area@1.2.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@radix-ui/react-scroll-area@1.2.3(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/number': 1.1.0
'@radix-ui/primitive': 1.1.1
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.11)(react@19.0.0)
'@radix-ui/react-context': 1.1.1(@types/react@19.0.11)(react@19.0.0)
'@radix-ui/react-direction': 1.1.0(@types/react@19.0.11)(react@19.0.0)
'@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.11))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.11)(react@19.0.0)
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.11)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10)
'@types/react': 19.0.11
'@types/react-dom': 19.0.4(@types/react@19.0.11)
'@radix-ui/react-slot@1.1.2(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-slot@1.1.2(@types/react@19.0.11)(react@19.0.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.11)(react@19.0.0)
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.11)(react@19.0.0)':
dependencies:
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.10)(react@19.0.0)':
'@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.11)(react@19.0.0)':
dependencies:
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@rollup/pluginutils@4.2.1':
dependencies:
@@ -10492,10 +10492,10 @@ snapshots:
'@tanstack/query-core': 5.68.0
react: 19.0.0
'@tanstack/react-router-devtools@1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.23)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)':
'@tanstack/react-router-devtools@1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.24)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-devtools-core': 1.114.23(@tanstack/router-core@1.114.23)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/react-router': 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-devtools-core': 1.114.24(@tanstack/router-core@1.114.24)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
solid-js: 1.9.5
@@ -10504,11 +10504,11 @@ snapshots:
- csstype
- tiny-invariant
'@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@tanstack/history': 1.114.22
'@tanstack/react-store': 0.7.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-core': 1.114.23
'@tanstack/router-core': 1.114.24
jsesc: 3.1.0
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
@@ -10534,14 +10534,14 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
'@tanstack/router-core@1.114.23':
'@tanstack/router-core@1.114.24':
dependencies:
'@tanstack/history': 1.114.22
'@tanstack/store': 0.7.0
'@tanstack/router-devtools-core@1.114.23(@tanstack/router-core@1.114.23)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools-core@1.114.24(@tanstack/router-core@1.114.24)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/router-core': 1.114.23
'@tanstack/router-core': 1.114.24
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
solid-js: 1.9.5
@@ -10549,10 +10549,10 @@ snapshots:
optionalDependencies:
csstype: 3.1.3
'@tanstack/router-devtools@1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.23)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools@1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.24)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router-devtools': 1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.23)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)
'@tanstack/react-router': 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router-devtools': 1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@tanstack/router-core@1.114.24)(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tiny-invariant@1.3.3)
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
react: 19.0.0
@@ -10563,16 +10563,16 @@ snapshots:
- '@tanstack/router-core'
- tiny-invariant
'@tanstack/router-generator@1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))':
'@tanstack/router-generator@1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))':
dependencies:
'@tanstack/virtual-file-routes': 1.114.12
prettier: 3.5.3
tsx: 4.19.3
zod: 3.24.2
optionalDependencies:
'@tanstack/react-router': 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-plugin@1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
'@tanstack/router-plugin@1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.9
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9)
@@ -10580,8 +10580,8 @@ snapshots:
'@babel/template': 7.26.9
'@babel/traverse': 7.26.9
'@babel/types': 7.26.9
'@tanstack/router-core': 1.114.23
'@tanstack/router-generator': 1.114.23(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@tanstack/router-core': 1.114.24
'@tanstack/router-generator': 1.114.24(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@tanstack/router-utils': 1.114.12
'@tanstack/virtual-file-routes': 1.114.12
'@types/babel__core': 7.20.5
@@ -10592,7 +10592,7 @@ snapshots:
unplugin: 2.2.0
zod: 3.24.2
optionalDependencies:
'@tanstack/react-router': 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -10604,9 +10604,9 @@ snapshots:
ansis: 3.12.0
diff: 7.0.0
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.2)':
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.2)':
dependencies:
'@tanstack/react-router': 1.114.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.114.24(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 3.24.2
'@tanstack/store@0.7.0': {}
@@ -10696,7 +10696,7 @@ snapshots:
dependencies:
'@tauri-apps/api': 2.3.0
'@tauri-apps/plugin-updater@2.6.0':
'@tauri-apps/plugin-updater@2.6.1':
dependencies:
'@tauri-apps/api': 2.3.0
@@ -10945,15 +10945,15 @@ snapshots:
'@types/prop-types@15.7.14': {}
'@types/react-dom@19.0.4(@types/react@19.0.10)':
'@types/react-dom@19.0.4(@types/react@19.0.11)':
dependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@types/react-transition-group@4.4.12(@types/react@19.0.10)':
'@types/react-transition-group@4.4.12(@types/react@19.0.11)':
dependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
'@types/react@19.0.10':
'@types/react@19.0.11':
dependencies:
csstype: 3.1.3
@@ -13664,9 +13664,9 @@ snapshots:
jju@1.4.0: {}
jotai@2.12.2(@types/react@19.0.10)(react@19.0.0):
jotai@2.12.2(@types/react@19.0.11)(react@19.0.0):
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
react: 19.0.0
js-cookie@2.2.1: {}
@@ -13966,13 +13966,13 @@ snapshots:
escape-string-regexp: 4.0.0
optional: true
material-react-table@3.2.1(2e84544a0e977e5cbb40e088279de64c):
material-react-table@3.2.1(654f09cb8207d585a138693171e30e7f):
dependencies:
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/icons-material': 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/icons-material': 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/match-sorter-utils': 8.19.4
'@tanstack/react-table': 8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-virtual': 3.11.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -14323,16 +14323,16 @@ snapshots:
muggle-string@0.4.1: {}
mui-color-input@5.0.1(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
mui-color-input@5.0.1(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@ctrl/tinycolor': 4.1.0
'@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@emotion/react': 11.14.0(@types/react@19.0.11)(react@19.0.0)
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react': 19.0.11
nano-css@5.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
@@ -14888,14 +14888,14 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
react-hook-form-mui@7.5.0(b98e4d9419cc277791cc5997c01ae06f):
react-hook-form-mui@7.5.0(ea3e5f5c412ba73f5e2ef92ffc8e5c95):
dependencies:
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
react-hook-form: 7.52.1(react@19.0.0)
optionalDependencies:
'@mui/icons-material': 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/icons-material': 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(react@19.0.0)
'@mui/x-date-pickers': 7.9.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react@19.0.0))(@types/react@19.0.11)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.11)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-hook-form@7.52.1(react@19.0.0):
dependencies:
@@ -14916,11 +14916,11 @@ snapshots:
react-is@19.0.0: {}
react-markdown@10.1.0(@types/react@19.0.10)(react@19.0.0):
react-markdown@10.1.0(@types/react@19.0.11)(react@19.0.0):
dependencies:
'@types/hast': 3.0.4
'@types/mdast': 4.0.3
'@types/react': 19.0.10
'@types/react': 19.0.11
devlop: 1.1.0
hast-util-to-jsx-runtime: 2.3.0
html-url-attributes: 3.0.0
-8
View File
@@ -269,9 +269,6 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable
- name: Add Rust Target
run: rustup target add ${{ matrix.target }}
@@ -313,11 +310,6 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
tagName: alpha
releaseName: "Clash Verge Rev Alpha"
releaseBody: "More new features are now supported."
releaseDraft: false
prerelease: true
tauriScript: pnpm
args: --target ${{ matrix.target }}
+12 -4
View File
@@ -4,13 +4,21 @@ use crate::module::mihomo::MihomoManager;
#[tauri::command]
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
let mannager = MihomoManager::global();
mannager.refresh_proxies().await.unwrap();
Ok(mannager.get_proxies())
let proxies = mannager
.refresh_proxies()
.await
.map(|_| mannager.get_proxies())
.or_else(|_| Ok(mannager.get_proxies()));
proxies
}
#[tauri::command]
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
let mannager = MihomoManager::global();
mannager.refresh_providers_proxies().await.unwrap();
Ok(mannager.get_providers_proxies())
let providers = mannager
.refresh_providers_proxies()
.await
.map(|_| mannager.get_providers_proxies())
.or_else(|_| Ok(mannager.get_providers_proxies()));
providers
}
@@ -41,6 +41,18 @@ impl Handle {
window
}
pub fn destroy_window(&self) -> Result<(), String> {
if let Some(window) = self.get_window() {
log_err!(window.close());
}
if let Some(window) = Self::global().get_window() {
if let Some(webview) = window.get_webview_window("main") {
log_err!(webview.destroy());
}
}
Ok(())
}
pub fn refresh_clash() {
if let Some(window) = Self::global().get_window() {
log_err!(window.emit("verge://refresh-clash-config", "yes"));
+5 -12
View File
@@ -194,18 +194,11 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
}
// Handle lite mode switch
if lite_mode.is_some() {
if let Some(window) = handle::Handle::global().get_window() {
if lite_mode.unwrap() {
// 完全退出 webview 进程
window.close()?; // 先关闭窗口
let app_handle = handle::Handle::global().app_handle().unwrap();
if let Some(webview) = app_handle.get_webview_window("main") {
webview.destroy()?; // 销毁 webview 进程
}
} else {
resolve::create_window(); // 重新创建窗口
}
if let Some(enable) = lite_mode {
if enable {
handle::Handle::global().destroy_window().ok();
} else {
resolve::create_window();
}
}
+21 -2
View File
@@ -11,9 +11,12 @@ use crate::{
};
use config::Config;
use std::sync::{Mutex, Once};
use tauri::AppHandle;
#[cfg(target_os = "macos")]
use tauri::Manager;
use tauri::{
menu::{Menu, MenuItem, Submenu},
AppHandle,
};
use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_deep_link::DeepLinkExt;
@@ -99,7 +102,6 @@ pub fn run() {
#[cfg(debug_assertions)]
let devtools = tauri_plugin_devtools::init();
#[allow(unused_mut)]
let mut builder = tauri::Builder::default()
.plugin(tauri_plugin_autostart::init(
@@ -220,6 +222,23 @@ pub fn run() {
builder = builder.plugin(devtools);
}
// Macos Application Menu
#[cfg(target_os = "macos")]
{
builder = builder.menu(|handle| {
Menu::with_items(
handle,
&[&Submenu::with_items(
handle,
"Menu",
true,
&[&MenuItem::new(handle, "Clash Verge", true, None::<String>).unwrap()],
)
.unwrap()],
)
});
}
let app = builder
.build(tauri::generate_context!())
.expect("error while running tauri application");
@@ -30,11 +30,5 @@
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
}
},
"app": {
"trayIcon": {
"iconPath": "icons/tray-icon.ico",
"iconAsTemplate": true
}
}
}
@@ -30,11 +30,5 @@
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
}
},
"app": {
"trayIcon": {
"iconPath": "icons/tray-icon.ico",
"iconAsTemplate": true
}
}
}
@@ -30,11 +30,5 @@
],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
}
},
"app": {
"trayIcon": {
"iconPath": "icons/tray-icon.ico",
"iconAsTemplate": true
}
}
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

@@ -0,0 +1,10 @@
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="36" height="36" rx="18" fill="url(#paint0_linear_3004_316)"/>
<path d="M23 14.6666H22.1667V13C22.1667 10.7 20.3 8.83331 18 8.83331C15.7 8.83331 13.8334 10.7 13.8334 13H15.5C15.5 11.6166 16.6167 10.5 18 10.5C19.3834 10.5 20.5 11.6166 20.5 13V14.6666H13C12.0834 14.6666 11.3334 15.4166 11.3334 16.3333V24.6666C11.3334 25.5833 12.0834 26.3333 13 26.3333H23C23.9167 26.3333 24.6667 25.5833 24.6667 24.6666V16.3333C24.6667 15.4166 23.9167 14.6666 23 14.6666ZM23 24.6666H13V16.3333H23V24.6666ZM18 22.1666C18.9167 22.1666 19.6667 21.4166 19.6667 20.5C19.6667 19.5833 18.9167 18.8333 18 18.8333C17.0834 18.8333 16.3334 19.5833 16.3334 20.5C16.3334 21.4166 17.0834 22.1666 18 22.1666Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_3004_316" x1="31" y1="27.5" x2="6.5" y2="7" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFA800"/>
<stop offset="1" stop-color="#FFAC4B"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1020 B

@@ -182,22 +182,13 @@ export const EnhancedTrafficStats = () => {
try {
const connections = await getConnections();
if (connections && connections.connections) {
const uploadTotal = connections.connections.reduce(
(sum, conn) => sum + conn.upload,
0,
);
const downloadTotal = connections.connections.reduce(
(sum, conn) => sum + conn.download,
0,
);
if (connections) {
setStats(prev => ({
...prev,
connections: {
uploadTotal,
downloadTotal,
activeConnections: connections.connections.length,
uploadTotal: connections.uploadTotal || 0,
downloadTotal: connections.downloadTotal || 0,
activeConnections: connections.connections ? connections.connections.length : 0,
}
}));
}
+4 -3
View File
@@ -8,11 +8,13 @@ import HomePage from "./home";
import UnlockPage from "./unlock";
import { BaseErrorBoundary } from "@/components/base";
import HomeSvg from "@/assets/image/itemicon/home.svg?react";
import ProxiesSvg from "@/assets/image/itemicon/proxies.svg?react";
import ProfilesSvg from "@/assets/image/itemicon/profiles.svg?react";
import ConnectionsSvg from "@/assets/image/itemicon/connections.svg?react";
import RulesSvg from "@/assets/image/itemicon/rules.svg?react";
import LogsSvg from "@/assets/image/itemicon/logs.svg?react";
import UnlockSvg from "@/assets/image/itemicon/unlock.svg?react";
import SettingsSvg from "@/assets/image/itemicon/settings.svg?react";
import WifiRoundedIcon from "@mui/icons-material/WifiRounded";
@@ -20,7 +22,6 @@ import DnsRoundedIcon from "@mui/icons-material/DnsRounded";
import LanguageRoundedIcon from "@mui/icons-material/LanguageRounded";
import ForkRightRoundedIcon from "@mui/icons-material/ForkRightRounded";
import SubjectRoundedIcon from "@mui/icons-material/SubjectRounded";
import WifiTetheringRoundedIcon from "@mui/icons-material/WifiTetheringRounded";
import SettingsRoundedIcon from "@mui/icons-material/SettingsRounded";
import HomeRoundedIcon from "@mui/icons-material/HomeRounded";
import LockOpenRoundedIcon from "@mui/icons-material/LockOpenRounded";
@@ -29,7 +30,7 @@ export const routers = [
{
label: "Label-Home",
path: "/home",
icon: [<HomeRoundedIcon />],
icon: [<HomeRoundedIcon />, <HomeSvg />],
element: <HomePage />,
},
{
@@ -65,7 +66,7 @@ export const routers = [
{
label: "Label-Unlock",
path: "/unlock",
icon: [<LockOpenRoundedIcon />],
icon: [<LockOpenRoundedIcon />, <UnlockSvg />],
element: <UnlockPage />,
},
{
+10 -4
View File
@@ -23,6 +23,7 @@ import {
DnsOutlined,
SpeedOutlined,
HelpOutlineRounded,
HistoryEduOutlined,
} from "@mui/icons-material";
import { useNavigate } from "react-router-dom";
import { ProxyTunCard } from "@/components/home/proxy-tun-card";
@@ -36,7 +37,7 @@ import { BasePage } from "@/components/base";
import { ClashInfoCard } from "@/components/home/clash-info-card";
import { SystemInfoCard } from "@/components/home/system-info-card";
import { useLockFn } from "ahooks";
import { openWebUrl } from "@/services/cmds";
import { openWebUrl, patchVergeConfig } from "@/services/cmds";
import { TestCard } from "@/components/home/test-card";
import { IpInfoCard } from "@/components/home/ip-info-card";
@@ -258,6 +259,11 @@ const HomePage = () => {
contentStyle={{ padding: 2 }}
header={
<Box sx={{ display: "flex", alignItems: "center" }}>
<Tooltip title={t("Lite Mode")} arrow>
<IconButton onClick={() => patchVergeConfig({ enable_lite_mode: true })} size="small" color="inherit">
<HistoryEduOutlined />
</IconButton>
</Tooltip>
<Tooltip title={t("Manual")} arrow>
<IconButton onClick={toGithubDoc} size="small" color="inherit">
<HelpOutlineRounded />
@@ -275,9 +281,9 @@ const HomePage = () => {
{/* 订阅和当前节点部分 */}
{homeCards.profile && (
<Grid size={6}>
<HomeProfileCard
current={current}
onProfileUpdated={mutateProfiles}
<HomeProfileCard
current={current}
onProfileUpdated={mutateProfiles}
/>
</Grid>
)}
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/dts-v1/;
#include "mt7981b-cmcc-a10.dts"
/ {
model = "CMCC A10 (U-Boot mod)";
compatible = "cmcc,a10-mod", "mediatek,mt7981";
};
&spi0 {
spi_nand@0 {
partitions {
partition@580000 {
label = "ubi";
reg = <0x0580000 0x6000000>;
};
/delete-node/ partition@4580000;
};
};
};
@@ -0,0 +1,260 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "mt7981.dtsi"
/ {
model = "CMCC A10";
compatible = "cmcc,a10", "mediatek,mt7981";
aliases {
serial0 = &uart0;
label-mac-device = &gmac0;
led-boot = &led_status_red;
led-failsafe = &led_status_red;
led-running = &led_status_blue;
led-upgrade = &led_status_green;
};
chosen {
stdout-path = "serial0:115200n8";
};
memory {
reg = <0 0x40000000 0 0x10000000>;
};
gpio-keys {
compatible = "gpio-keys";
reset {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&pio 1 GPIO_ACTIVE_LOW>;
};
wps {
label = "wps";
linux,code = <KEY_WPS_BUTTON>;
gpios = <&pio 0 GPIO_ACTIVE_LOW>;
};
};
leds {
compatible = "gpio-leds";
led_status_blue: blue {
label = "blue:status";
gpios = <&pio 9 GPIO_ACTIVE_LOW>;
};
led_status_green: green {
label = "green:status";
gpios = <&pio 10 GPIO_ACTIVE_LOW>;
};
led_status_red: red {
label = "red:status";
gpios = <&pio 11 GPIO_ACTIVE_LOW>;
};
};
};
&eth {
status = "okay";
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "2500base-x";
nvmem-cells = <&macaddr_factory_2a>;
nvmem-cell-names = "mac-address";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
};
&mdio_bus {
switch: switch@0 {
compatible = "mediatek,mt7531";
reg = <31>;
reset-gpios = <&pio 39 GPIO_ACTIVE_HIGH>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&pio>;
interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
};
};
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_flash_pins>;
status = "okay";
spi_nand@0 {
compatible = "spi-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = <0>;
spi-max-frequency = <52000000>;
spi-tx-bus-width = <4>;
spi-rx-bus-width = <4>;
mediatek,nmbm;
mediatek,bmt-max-ratio = <1>;
mediatek,bmt-max-reserved-blocks = <64>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "BL2";
reg = <0x0000000 0x0100000>;
read-only;
};
partition@100000 {
label = "u-boot-env";
reg = <0x0100000 0x0080000>;
};
factory: partition@180000 {
label = "Factory";
reg = <0x0180000 0x0200000>;
read-only;
};
partition@380000 {
label = "FIP";
reg = <0x0380000 0x0200000>;
read-only;
};
partition@580000 {
label = "ubi";
reg = <0x0580000 0x4000000>;
};
partition@4580000 {
label = "backup";
reg = <0x4580000 0x2000000>;
};
partition@6580000 {
label = "zrsave";
reg = <0x6580000 0x0100000>;
};
partition@6680000 {
label = "config2";
reg = <0x6680000 0x0100000>;
read-only;
};
};
};
};
&switch {
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
port@3 {
reg = <3>;
label = "lan3";
};
port@4 {
reg = <4>;
label = "wan";
nvmem-cells = <&macaddr_factory_24>;
nvmem-cell-names = "mac-address";
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "2500base-x";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
};
};
&pio {
spi0_flash_pins: spi0-pins {
mux {
function = "spi";
groups = "spi0", "spi0_wp_hold";
};
conf-pu {
pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
drive-strength = <8>;
mediatek,pull-up-adv = <0>; /* bias-disable */
};
conf-pd {
pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
drive-strength = <8>;
mediatek,pull-up-adv = <0>; /* bias-disable */
};
};
};
&uart0 {
status = "okay";
};
&watchdog {
status = "okay";
};
&wifi {
status = "okay";
mediatek,mtd-eeprom = <&factory 0x0>;
};
&factory {
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_factory_24: macaddr@24 {
reg = <0x24 0x6>;
};
macaddr_factory_2a: macaddr@2a {
reg = <0x2a 0x6>;
};
};
};
@@ -42,6 +42,7 @@ mediatek_setup_interfaces()
ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 eth1" "wan eth2"
;;
cetron,ct3003*|\
cmcc,a10*|\
fzs,5gcpe-p3|\
jcg,q30-pro|\
qihoo,360t7|\
@@ -282,6 +282,35 @@ define Device/cetron_ct3003-mod
endef
TARGET_DEVICES += cetron_ct3003-mod
define Device/cmcc_a10
DEVICE_VENDOR := CMCC
DEVICE_MODEL := A10
DEVICE_DTS := mt7981b-cmcc-a10
DEVICE_DTS_DIR := ../dts
UBINIZE_OPTS := -E 5
BLOCKSIZE := 128k
PAGESIZE := 2048
KERNEL_IN_UBI := 1
SUPPORTED_DEVICES += mediatek,mt7981-spim-snand-rfb
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
DEVICE_PACKAGES := kmod-mt7981-firmware mt7981-wo-firmware
endef
TARGET_DEVICES += cmcc_a10
define Device/cmcc_a10-mod
DEVICE_VENDOR := CMCC
DEVICE_MODEL := A10 (U-Boot mod)
DEVICE_DTS := mt7981b-cmcc-a10-mod
DEVICE_DTS_DIR := ../dts
UBINIZE_OPTS := -E 5
BLOCKSIZE := 128k
PAGESIZE := 2048
KERNEL_IN_UBI := 1
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
DEVICE_PACKAGES := kmod-mt7981-firmware mt7981-wo-firmware
endef
TARGET_DEVICES += cmcc_a10-mod
define Device/cmcc_rax3000m-emmc
DEVICE_VENDOR := CMCC
DEVICE_MODEL := RAX3000M (eMMC version)
@@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrey Safonov <andrey.safonov@gmail.com>
Date: Sat, 16 Dec 2023 22:46:35 +0300
Subject: rk3399 PCIE PHY reset on probe
This patches the PCIE initialization error after warm reboot.
The root of cause is, when the device is booted after power on,
PHY stays in 'factory' state. After warm boot PHY stays in the
previous state and prevents any training, thus PCIE init fails.
Signed-off-by: Andrey Safonov <andrey.safonov@gmail.com>
---
drivers/phy/rockchip/phy-rockchip-pcie.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -344,6 +344,20 @@ static const struct of_device_id rockchi
MODULE_DEVICE_TABLE(of, rockchip_pcie_phy_dt_ids);
+static void rockchip_pcie_phy_reset(struct rockchip_pcie_phy *rk_phy)
+{
+ int i;
+
+ for (i = 0; i < PHY_MAX_LANE_NUM; i++)
+ regmap_write(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_laneoff,
+ HIWORD_UPDATE(PHY_LANE_IDLE_OFF,
+ PHY_LANE_IDLE_MASK,
+ PHY_LANE_IDLE_A_SHIFT + i));
+
+ reset_control_assert(rk_phy->phy_rst);
+}
+
static int rockchip_pcie_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -393,6 +407,8 @@ static int rockchip_pcie_phy_probe(struc
phy_num = (phy_num == 0) ? 1 : PHY_MAX_LANE_NUM;
dev_dbg(dev, "phy number is %d\n", phy_num);
+
+ rockchip_pcie_phy_reset(rk_phy);
for (i = 0; i < phy_num; i++) {
rk_phy->phys[i].phy = devm_phy_create(dev, dev->of_node, &ops);
@@ -0,0 +1,44 @@
From 77f6dfcb20c2dc6a4a2f5303709c6fa0c7b65f30 Mon Sep 17 00:00:00 2001
From: Valmantas Paliksa <walmis@gmail.com>
Date: Thu, 12 Dec 2024 12:24:33 +0200
Subject: [PATCH] Disable PHY_LANE_IDLE_OFF for each instance of rockchip_pcie_phy_power_one
This patch fixes an issue in the Rockchip PCIe PHY driver where, after
a warm restart of the rockchip_pcie_phy module, PCIe lanes other than
lane 0 could remain stuck in the PHY_LANE_IDLE_OFF state. This resulted
in the PCIe link being restricted to x1 mode, even in configurations
designed to use multiple lanes.
Signed-off-by: Valmantas Paliksa <walmis@gmail.com>
---
drivers/phy/rockchip/phy-rockchip-pcie.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -166,6 +166,12 @@ static int rockchip_pcie_phy_power_on(st
unsigned long timeout;
mutex_lock(&rk_phy->pcie_mutex);
+
+ regmap_write(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_laneoff,
+ HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
+ PHY_LANE_IDLE_MASK,
+ PHY_LANE_IDLE_A_SHIFT + inst->index));
if (rk_phy->pwr_cnt++)
goto err_out;
@@ -181,12 +187,6 @@ static int rockchip_pcie_phy_power_on(st
PHY_CFG_ADDR_MASK,
PHY_CFG_ADDR_SHIFT));
- regmap_write(rk_phy->reg_base,
- rk_phy->phy_data->pcie_laneoff,
- HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
- PHY_LANE_IDLE_MASK,
- PHY_LANE_IDLE_A_SHIFT + inst->index));
-
/*
* No documented timeout value for phy operation below,
* so we make it large enough here. And we use loop-break
+18 -18
View File
@@ -39,47 +39,37 @@ type PacketOverStreamTunnel struct {
var _ net.PacketConn = (*PacketOverStreamTunnel)(nil)
func (c *PacketOverStreamTunnel) Read(p []byte) (n int, err error) {
n, _, err = c.ReadFrom(p)
return
}
func (c *PacketOverStreamTunnel) Write(p []byte) (int, error) {
return c.WriteTo(p, c.RemoteAddr())
}
func (c *PacketOverStreamTunnel) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
addr = c.RemoteAddr()
delim := make([]byte, 1)
if _, err = io.ReadFull(c.Conn, delim); err != nil {
return 0, addr, err
return 0, err
}
if delim[0] != 0x00 {
return 0, addr, fmt.Errorf("packet prefix 0x%x is not 0x00", delim[0])
return 0, fmt.Errorf("packet prefix 0x%x is not 0x00", delim[0])
}
lengthBytes := make([]byte, 2)
if _, err = io.ReadFull(c.Conn, lengthBytes); err != nil {
return 0, addr, err
return 0, err
}
length := int(binary.BigEndian.Uint16(lengthBytes))
if length > len(p) {
return 0, addr, io.ErrShortBuffer
return 0, io.ErrShortBuffer
}
if n, err = io.ReadFull(c.Conn, p[:length]); err != nil {
return 0, addr, err
return 0, err
}
if _, err = io.ReadFull(c.Conn, delim); err != nil {
return 0, addr, err
return 0, err
}
if delim[0] != 0xff {
return 0, addr, fmt.Errorf("packet suffix 0x%x is not 0xff", delim[0])
return 0, fmt.Errorf("packet suffix 0x%x is not 0xff", delim[0])
}
return
}
func (c *PacketOverStreamTunnel) WriteTo(p []byte, _ net.Addr) (n int, err error) {
func (c *PacketOverStreamTunnel) Write(p []byte) (int, error) {
if len(p) > 65535 {
return 0, fmt.Errorf("packet length %d is larger than maximum length 65535", len(p))
}
@@ -95,6 +85,16 @@ func (c *PacketOverStreamTunnel) WriteTo(p []byte, _ net.Addr) (n int, err error
return len(p), nil
}
func (c *PacketOverStreamTunnel) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
addr = c.RemoteAddr()
n, err = c.Read(p)
return
}
func (c *PacketOverStreamTunnel) WriteTo(p []byte, _ net.Addr) (n int, err error) {
return c.Write(p)
}
func (c *PacketOverStreamTunnel) Close() error {
return c.Conn.Close()
}
@@ -10,6 +10,7 @@ proxies:
type: mieru
server: 127.0.0.1
port: 8964
udp: true
transport: TCP
username: baozi
password: manlianpenfen
+9 -1
View File
@@ -75,7 +75,15 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string
//log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16])
ecdheKey := uConn.HandshakeState.State13.EcdheKey
keyShareKeys := uConn.HandshakeState.State13.KeyShareKeys
if keyShareKeys == nil {
// WTF???
if retry > 2 {
return nil, errors.New("nil keyShareKeys")
}
continue // retry
}
ecdheKey := keyShareKeys.Ecdhe
if ecdheKey == nil {
// WTF???
if retry > 2 {
+1 -1
View File
@@ -32,7 +32,7 @@ require (
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422
github.com/metacubex/utls v1.6.6
github.com/metacubex/utls v1.6.8-alpha.4
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63
github.com/mroth/weightedrand/v2 v2.1.0
+2 -2
View File
@@ -129,8 +129,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
+8 -8
View File
@@ -813,9 +813,9 @@ dependencies = [
[[package]]
name = "deranged"
version = "0.3.11"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [
"powerfmt",
]
@@ -3783,9 +3783,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.39"
version = "0.3.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8"
checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
dependencies = [
"deranged",
"itoa",
@@ -3800,15 +3800,15 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "time-macros"
version = "0.2.20"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c"
checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
dependencies = [
"num-conv",
"time-core",
+52
View File
@@ -5,6 +5,8 @@ import (
"errors"
"net"
"net/netip"
"runtime"
"strings"
"syscall"
"time"
@@ -20,6 +22,8 @@ import (
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
"github.com/vishvananda/netns"
)
var (
@@ -35,6 +39,7 @@ type DefaultDialer struct {
udpListener net.ListenConfig
udpAddr4 string
udpAddr6 string
netns string
networkManager adapter.NetworkManager
networkStrategy *C.NetworkStrategy
defaultNetworkStrategy bool
@@ -198,6 +203,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
udpListener: listener,
udpAddr4: udpAddr4,
udpAddr6: udpAddr6,
netns: options.NetNs,
networkManager: networkManager,
networkStrategy: networkStrategy,
defaultNetworkStrategy: defaultNetworkStrategy,
@@ -214,6 +220,29 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
return nil, E.New("domain not resolved")
}
if d.networkStrategy == nil {
if d.netns != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
currentNs, err := netns.Get()
if err != nil {
return nil, E.Cause(err, "get current netns")
}
defer netns.Set(currentNs)
var targetNs netns.NsHandle
if strings.HasPrefix(d.netns, "/") {
targetNs, err = netns.GetFromPath(d.netns)
} else {
targetNs, err = netns.GetFromName(d.netns)
}
if err != nil {
return nil, E.Cause(err, "get netns ", d.netns)
}
defer targetNs.Close()
err = netns.Set(targetNs)
if err != nil {
return nil, E.Cause(err, "set netns to ", d.netns)
}
}
switch N.NetworkName(network) {
case N.NetworkUDP:
if !address.IsIPv6() {
@@ -282,6 +311,29 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if d.networkStrategy == nil {
if d.netns != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
currentNs, err := netns.Get()
if err != nil {
return nil, E.Cause(err, "get current netns")
}
defer netns.Set(currentNs)
var targetNs netns.NsHandle
if strings.HasPrefix(d.netns, "/") {
targetNs, err = netns.GetFromPath(d.netns)
} else {
targetNs, err = netns.GetFromName(d.netns)
}
if err != nil {
return nil, E.Cause(err, "get netns ", d.netns)
}
defer targetNs.Close()
err = netns.Set(targetNs)
if err != nil {
return nil, E.Cause(err, "set netns to ", d.netns)
}
}
if destination.IsIPv6() {
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6))
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
+26
View File
@@ -3,6 +3,8 @@ package listener
import (
"net"
"net/netip"
"runtime"
"strings"
"time"
"github.com/sagernet/sing-box/adapter"
@@ -13,6 +15,7 @@ import (
N "github.com/sagernet/sing/common/network"
"github.com/metacubex/tfo-go"
"github.com/vishvananda/netns"
)
func (l *Listener) ListenTCP() (net.Listener, error) {
@@ -37,6 +40,29 @@ func (l *Listener) ListenTCP() (net.Listener, error) {
}
setMultiPathTCP(&listenConfig)
}
if l.listenOptions.NetNs != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
currentNs, err := netns.Get()
if err != nil {
return nil, E.Cause(err, "get current netns")
}
defer netns.Set(currentNs)
var targetNs netns.NsHandle
if strings.HasPrefix(l.listenOptions.NetNs, "/") {
targetNs, err = netns.GetFromPath(l.listenOptions.NetNs)
} else {
targetNs, err = netns.GetFromName(l.listenOptions.NetNs)
}
if err != nil {
return nil, E.Cause(err, "get netns ", l.listenOptions.NetNs)
}
defer targetNs.Close()
err = netns.Set(targetNs)
if err != nil {
return nil, E.Cause(err, "set netns to ", l.listenOptions.NetNs)
}
}
if l.listenOptions.TCPFastOpen {
var tfoConfig tfo.ListenConfig
tfoConfig.ListenConfig = listenConfig
+27
View File
@@ -4,12 +4,16 @@ import (
"net"
"net/netip"
"os"
"runtime"
"strings"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/vishvananda/netns"
)
func (l *Listener) ListenUDP() (net.PacketConn, error) {
@@ -24,6 +28,29 @@ func (l *Listener) ListenUDP() (net.PacketConn, error) {
if !udpFragment {
lc.Control = control.Append(lc.Control, control.DisableUDPFragment())
}
if l.listenOptions.NetNs != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
currentNs, err := netns.Get()
if err != nil {
return nil, E.Cause(err, "get current netns")
}
defer netns.Set(currentNs)
var targetNs netns.NsHandle
if strings.HasPrefix(l.listenOptions.NetNs, "/") {
targetNs, err = netns.GetFromPath(l.listenOptions.NetNs)
} else {
targetNs, err = netns.GetFromName(l.listenOptions.NetNs)
}
if err != nil {
return nil, E.Cause(err, "get netns ", l.listenOptions.NetNs)
}
defer targetNs.Close()
err = netns.Set(targetNs)
if err != nil {
return nil, E.Cause(err, "set netns to ", l.listenOptions.NetNs)
}
}
udpConn, err := lc.ListenPacket(l.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String())
if err != nil {
return nil, err
+1 -14
View File
@@ -263,20 +263,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
return nil, tun.ErrDrop
}
case *R.RuleActionPredefined:
return &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
Id: message.Id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: action.Rcode,
},
Question: message.Question,
Answer: action.Answer,
Ns: action.Ns,
Extra: action.Extra,
}, nil
return action.Response(message), nil
}
}
var responseCheck func(responseAddrs []netip.Addr) bool
+28 -16
View File
@@ -5,7 +5,8 @@ icon: material/new-box
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [domain_resolver](#domain_resolver)
:material-delete-clock: [domain_strategy](#domain_strategy)
:material-delete-clock: [domain_strategy](#domain_strategy)
:material-plus: [netns](#netns)
!!! quote "Changes in sing-box 1.11.0"
@@ -18,24 +19,25 @@ icon: material/new-box
```json
{
"detour": "upstream-out",
"bind_interface": "en0",
"inet4_bind_address": "0.0.0.0",
"inet6_bind_address": "::",
"routing_mark": 1234,
"detour": "",
"bind_interface": "",
"inet4_bind_address": "",
"inet6_bind_address": "",
"routing_mark": 0,
"reuse_addr": false,
"connect_timeout": "5s",
"connect_timeout": "",
"tcp_fast_open": false,
"tcp_multi_path": false,
"udp_fragment": false,
"netns": "",
"domain_resolver": "", // or {}
"network_strategy": "default",
"network_strategy": "",
"network_type": [],
"fallback_network_type": [],
"fallback_delay": "300ms",
"fallback_delay": "",
// Deprecated
"domain_strategy": "prefer_ipv6"
"domain_strategy": ""
}
```
@@ -75,6 +77,15 @@ Set netfilter routing mark.
Reuse listener address.
#### connect_timeout
Connect timeout, in golang's Duration format.
A duration string is a possibly signed sequence of
decimal numbers, each with optional fraction and a unit suffix,
such as "300ms", "-1.5h" or "2h45m".
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
#### tcp_fast_open
Enable TCP Fast Open.
@@ -91,14 +102,15 @@ Enable TCP Multi Path.
Enable UDP fragmentation.
#### connect_timeout
#### netns
Connect timeout, in golang's Duration format.
!!! question "Since sing-box 1.12.0"
A duration string is a possibly signed sequence of
decimal numbers, each with optional fraction and a unit suffix,
such as "300ms", "-1.5h" or "2h45m".
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
!!! quote ""
Only supported on Linux.
Set network namespace, name or path.
#### domain_resolver
+25 -13
View File
@@ -5,7 +5,8 @@ icon: material/new-box
!!! quote "sing-box 1.12.0 中的更改"
:material-plus: [domain_resolver](#domain_resolver)
:material-delete-clock: [domain_strategy](#domain_strategy)
:material-delete-clock: [domain_strategy](#domain_strategy)
:material-plus: [netns](#netns)
!!! quote "sing-box 1.11.0 中的更改"
@@ -18,25 +19,26 @@ icon: material/new-box
```json
{
"detour": "upstream-out",
"bind_interface": "en0",
"inet4_bind_address": "0.0.0.0",
"inet6_bind_address": "::",
"routing_mark": 1234,
"detour": "",
"bind_interface": "",
"inet4_bind_address": "",
"inet6_bind_address": "",
"routing_mark": 0,
"reuse_addr": false,
"connect_timeout": "5s",
"connect_timeout": "",
"tcp_fast_open": false,
"tcp_multi_path": false,
"udp_fragment": false,
"netns": "",
"domain_resolver": "", // 或 {}
"network_strategy": "",
"network_type": [],
"fallback_network_type": [],
"fallback_delay": "300ms",
"fallback_delay": "",
// 废弃的
"domain_strategy": "prefer_ipv6"
"domain_strategy": ""
}
```
@@ -76,6 +78,13 @@ icon: material/new-box
重用监听地址。
#### connect_timeout
连接超时,采用 golang 的 Duration 格式。
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
#### tcp_fast_open
启用 TCP Fast Open。
@@ -92,12 +101,15 @@ icon: material/new-box
启用 UDP 分段。
#### connect_timeout
#### netns
连接超时,采用 golang 的 Duration 格式。
!!! question "自 sing-box 1.12.0 起"
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
!!! quote ""
仅支持 Linux。
设置网络命名空间,名称或路径。
#### domain_resolver
+22 -7
View File
@@ -1,7 +1,11 @@
---
icon: material/delete-clock
icon: material/new-box
---
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [netns](#netns)
!!! quote "Changes in sing-box 1.11.0"
:material-delete-clock: [sniff](#sniff)
@@ -14,17 +18,18 @@ icon: material/delete-clock
```json
{
"listen": "::",
"listen_port": 5353,
"listen": "",
"listen_port": 0,
"tcp_fast_open": false,
"tcp_multi_path": false,
"udp_fragment": false,
"udp_timeout": "5m",
"detour": "another-in",
"udp_timeout": "",
"netns": "",
"detour": "",
"sniff": false,
"sniff_override_destination": false,
"sniff_timeout": "300ms",
"domain_strategy": "prefer_ipv6",
"sniff_timeout": "",
"domain_strategy": "",
"udp_disable_domain_unmapping": false
}
```
@@ -72,6 +77,16 @@ UDP NAT expiration time.
`5m` will be used by default.
#### netns
!!! question "Since sing-box 1.12.0"
!!! quote ""
Only supported on Linux.
Set network namespace, name or path.
#### detour
If set, connections will be forwarded to the specified inbound.
@@ -1,7 +1,11 @@
---
icon: material/delete-clock
icon: material/new-box
---
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [netns](#netns)
!!! quote "sing-box 1.11.0 中的更改"
:material-delete-clock: [sniff](#sniff)
@@ -14,17 +18,18 @@ icon: material/delete-clock
```json
{
"listen": "::",
"listen_port": 5353,
"listen": "",
"listen_port": 0,
"tcp_fast_open": false,
"tcp_multi_path": false,
"udp_fragment": false,
"udp_timeout": "5m",
"detour": "another-in",
"udp_timeout": "",
"netns": "",
"detour": "",
"sniff": false,
"sniff_override_destination": false,
"sniff_timeout": "300ms",
"domain_strategy": "prefer_ipv6",
"sniff_timeout": "",
"domain_strategy": "",
"udp_disable_domain_unmapping": false
}
```
@@ -73,6 +78,16 @@ UDP NAT 过期时间。
默认使用 `5m`
#### netns
!!! question "自 sing-box 1.12.0 起"
!!! quote ""
仅支持 Linux。
设置网络命名空间,名称或路径。
#### detour
如果设置,连接将被转发到指定的入站。
+15 -26
View File
@@ -191,34 +191,23 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
serverType = C.DNSTypeUDP
}
}
var remoteOptions RemoteDNSServerOptions
if options.Detour == "" {
remoteOptions = RemoteDNSServerOptions{
LocalDNSServerOptions: LocalDNSServerOptions{
LegacyStrategy: options.Strategy,
LegacyDefaultDialer: options.Detour == "",
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
},
LegacyAddressResolver: options.AddressResolver,
LegacyAddressStrategy: options.AddressStrategy,
LegacyAddressFallbackDelay: options.AddressFallbackDelay,
}
} else {
remoteOptions = RemoteDNSServerOptions{
LocalDNSServerOptions: LocalDNSServerOptions{
DialerOptions: DialerOptions{
Detour: options.Detour,
DomainResolver: &DomainResolveOptions{
Server: options.AddressResolver,
Strategy: options.AddressStrategy,
},
FallbackDelay: options.AddressFallbackDelay,
remoteOptions := RemoteDNSServerOptions{
LocalDNSServerOptions: LocalDNSServerOptions{
DialerOptions: DialerOptions{
Detour: options.Detour,
DomainResolver: &DomainResolveOptions{
Server: options.AddressResolver,
Strategy: options.AddressStrategy,
},
LegacyStrategy: options.Strategy,
LegacyDefaultDialer: options.Detour == "",
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
FallbackDelay: options.AddressFallbackDelay,
},
}
LegacyStrategy: options.Strategy,
LegacyDefaultDialer: options.Detour == "",
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
},
LegacyAddressResolver: options.AddressResolver,
LegacyAddressStrategy: options.AddressStrategy,
LegacyAddressFallbackDelay: options.AddressFallbackDelay,
}
switch serverType {
case C.DNSTypeLocal:
+1
View File
@@ -68,6 +68,7 @@ type ListenOptions struct {
UDPFragment *bool `json:"udp_fragment,omitempty"`
UDPFragmentDefault bool `json:"-"`
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
NetNs string `json:"netns,omitempty"`
// Deprecated: removed
ProxyProtocol bool `json:"proxy_protocol,omitempty"`
+1
View File
@@ -77,6 +77,7 @@ type DialerOptions struct {
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
UDPFragment *bool `json:"udp_fragment,omitempty"`
UDPFragmentDefault bool `json:"-"`
NetNs string `json:"netns,omitempty"`
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
+8 -7
View File
@@ -4,17 +4,18 @@ import (
"encoding/json"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json/badjson"
)
type ShadowTLSInboundOptions struct {
ListenOptions
Version int `json:"version,omitempty"`
Password string `json:"password,omitempty"`
Users []ShadowTLSUser `json:"users,omitempty"`
Handshake ShadowTLSHandshakeOptions `json:"handshake,omitempty"`
HandshakeForServerName map[string]ShadowTLSHandshakeOptions `json:"handshake_for_server_name,omitempty"`
StrictMode bool `json:"strict_mode,omitempty"`
WildcardSNI WildcardSNI `json:"wildcard_sni,omitempty"`
Version int `json:"version,omitempty"`
Password string `json:"password,omitempty"`
Users []ShadowTLSUser `json:"users,omitempty"`
Handshake ShadowTLSHandshakeOptions `json:"handshake,omitempty"`
HandshakeForServerName *badjson.TypedMap[string, ShadowTLSHandshakeOptions] `json:"handshake_for_server_name,omitempty"`
StrictMode bool `json:"strict_mode,omitempty"`
WildcardSNI WildcardSNI `json:"wildcard_sni,omitempty"`
}
type WildcardSNI int
+10 -8
View File
@@ -46,14 +46,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
var handshakeForServerName map[string]shadowtls.HandshakeConfig
if options.Version > 1 {
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
for serverName, serverOptions := range options.HandshakeForServerName {
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions, serverOptions.ServerIsDomain())
if err != nil {
return nil, err
}
handshakeForServerName[serverName] = shadowtls.HandshakeConfig{
Server: serverOptions.ServerOptions.Build(),
Dialer: handshakeDialer,
if options.HandshakeForServerName != nil {
for _, entry := range options.HandshakeForServerName.Entries() {
handshakeDialer, err := dialer.New(ctx, entry.Value.DialerOptions, entry.Value.ServerIsDomain())
if err != nil {
return nil, err
}
handshakeForServerName[entry.Key] = shadowtls.HandshakeConfig{
Server: entry.Value.ServerOptions.Build(),
Dialer: handshakeDialer,
}
}
}
}
+29
View File
@@ -444,3 +444,32 @@ func (r *RuleActionPredefined) String() string {
options = append(options, common.Map(r.Extra, dns.RR.String)...)
return F.ToString("predefined(", strings.Join(options, ","), ")")
}
func (r *RuleActionPredefined) Response(request *dns.Msg) *dns.Msg {
return &dns.Msg{
MsgHdr: dns.MsgHdr{
Id: request.Id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: r.Rcode,
},
Question: request.Question,
Answer: rewriteRecords(r.Answer, request.Question[0]),
Ns: rewriteRecords(r.Ns, request.Question[0]),
Extra: rewriteRecords(r.Extra, request.Question[0]),
}
}
func rewriteRecords(records []dns.RR, question dns.Question) []dns.RR {
return common.Map(records, func(it dns.RR) dns.RR {
if strings.HasPrefix(it.Header().Name, "*") {
if strings.HasSuffix(question.Name, it.Header().Name[1:]) {
it = dns.Copy(it)
it.Header().Name = question.Name
}
}
return it
})
}
+2 -19
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ssr-plus
PKG_VERSION:=189
PKG_RELEASE:=5
PKG_RELEASE:=6
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY \
@@ -34,10 +34,7 @@ LUCI_PKGARCH:=all
LUCI_DEPENDS:= \
+coreutils +coreutils-base64 +dns2socks +dns2tcp +dnsmasq-full +@PACKAGE_dnsmasq_full_ipset +ipset +kmod-ipt-nat +jq \
+ip-full +iptables +iptables-mod-tproxy +lua +lua-neturl +libuci-lua +microsocks \
+tcping +resolveip +shadowsocksr-libev-ssr-check +uclient-fetch \
+PACKAGE_$(PKG_NAME)_INCLUDE_libustream-mbedtls:libustream-mbedtls \
+PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl:libustream-openssl \
+PACKAGE_$(PKG_NAME)_INCLUDE_libustream-wolfssl:libustream-wolfssl \
+tcping +resolveip +shadowsocksr-libev-ssr-check +wget-ssl \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:curl \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray-core \
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:curl \
@@ -67,20 +64,6 @@ LUCI_DEPENDS:= \
define Package/$(PKG_NAME)/config
select PACKAGE_luci-lib-ipkg if PACKAGE_$(PKG_NAME)
choice
prompt "Uclient SSL Lib Selection"
default PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl
config PACKAGE_$(PKG_NAME)_INCLUDE_libustream-mbedtls
bool "libustream-mbedtls"
config PACKAGE_$(PKG_NAME)_INCLUDE_libustream-openssl
bool "libustream-openssl"
config PACKAGE_$(PKG_NAME)_INCLUDE_PACKAGE_libustream-wolfssl
bool "libustream-wolfssl"
endchoice
choice
prompt "Shadowsocks Client Selection"
default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client if aarch64 || x86_64
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
uses: actions/setup-dotnet@v4.3.1
with:
dotnet-version: '8.0.x'
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
uses: actions/setup-dotnet@v4.3.1
with:
dotnet-version: '8.0.x'
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
uses: actions/setup-dotnet@v4.3.1
with:
dotnet-version: '8.0.x'
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
uses: actions/checkout@v4.2.2
- name: Setup
uses: actions/setup-dotnet@v4.3.0
uses: actions/setup-dotnet@v4.3.1
with:
dotnet-version: '8.0.x'
@@ -63,6 +63,10 @@ public partial class App : Application
if (desktop.MainWindow != null)
{
var clipboardData = await AvaUtils.GetClipboardData(desktop.MainWindow);
if (clipboardData.IsNullOrEmpty())
{
return;
}
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null)
{
@@ -14,7 +14,10 @@ namespace v2rayN.Desktop.Common
{
var clipboard = TopLevel.GetTopLevel(owner)?.Clipboard;
if (clipboard == null)
{
return null;
}
return await clipboard.GetTextAsync();
}
catch
@@ -247,7 +247,7 @@ namespace v2rayN.Desktop.Views
case EViewAction.AddServerViaClipboard:
var clipboardData = await AvaUtils.GetClipboardData(this);
if (ViewModel != null)
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
@@ -315,7 +315,7 @@ namespace v2rayN.Desktop.Views
{
case Key.V:
var clipboardData = await AvaUtils.GetClipboardData(this);
if (ViewModel != null)
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
@@ -109,13 +109,20 @@ namespace v2rayN.Desktop.Views
case EViewAction.SetClipboardData:
if (obj is null)
{
return false;
}
await AvaUtils.SetClipboardData(this, (string)obj);
break;
case EViewAction.ImportRulesFromClipboard:
var clipboardData = await AvaUtils.GetClipboardData(this);
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
if (clipboardData.IsNotEmpty())
{
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
}
break;
}
+3 -3
View File
@@ -18,11 +18,11 @@ namespace v2rayN
/// <returns></returns>
public static string? GetClipboardData()
{
string? strData = string.Empty;
var strData = string.Empty;
try
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText))
var data = Clipboard.GetDataObject();
if (data?.GetDataPresent(DataFormats.UnicodeText) == true)
{
strData = data.GetData(DataFormats.UnicodeText)?.ToString();
}
+16 -4
View File
@@ -232,7 +232,10 @@ namespace v2rayN.Views
case EViewAction.AddServerViaClipboard:
var clipboardData = WindowsUtils.GetClipboardData();
ViewModel?.AddServerViaClipboardAsync(clipboardData);
if (clipboardData.IsNotEmpty())
{
ViewModel?.AddServerViaClipboardAsync(clipboardData);
}
break;
case EViewAction.AdjustMainLvColWidth:
@@ -284,11 +287,20 @@ namespace v2rayN.Views
{
case Key.V:
if (Keyboard.FocusedElement is TextBox)
{
return;
}
var clipboardData = WindowsUtils.GetClipboardData();
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null)
_ = service.AddServerViaClipboardAsync(clipboardData);
if (clipboardData.IsNotEmpty())
{
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null)
{
_ = service.AddServerViaClipboardAsync(clipboardData);
}
}
break;
case Key.S:
@@ -110,7 +110,10 @@ namespace v2rayN.Views
case EViewAction.ImportRulesFromClipboard:
var clipboardData = WindowsUtils.GetClipboardData();
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
if (clipboardData.IsNotEmpty())
{
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
}
break;
}
+12 -12
View File
@@ -1,10 +1,10 @@
module github.com/2dust/AndroidLibXrayLite
go 1.24
go 1.24.1
require (
github.com/xtls/xray-core v1.8.25-0.20250306135015-2cba2c4d59e4
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3
golang.org/x/mobile v0.0.0-20250305212854-3a7bc9f8a4de
golang.org/x/sys v0.31.0
)
@@ -16,18 +16,18 @@ require (
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/onsi/ginkgo/v2 v2.23.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pires/go-proxyproto v0.8.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.50.0 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/sagernet/sing v0.6.1 // indirect
github.com/sagernet/sing v0.6.2 // indirect
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
@@ -37,16 +37,16 @@ require (
go.uber.org/mock v0.5.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/mod v0.23.0 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.10.0 // indirect
golang.org/x/tools v0.30.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.31.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
+24 -24
View File
@@ -1,5 +1,5 @@
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I=
github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
github.com/OmarTariq612/goech v0.0.1 h1:/0c918Bk1ik65GXDj2k7SOK78DyZr30Jmq9euy1/HXg=
github.com/OmarTariq612/goech v0.0.1/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
@@ -26,20 +26,20 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 h1:+J3r2e8+RsmN3vKfo75g0YSY61ms37qzPglu4p0sGro=
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
@@ -56,8 +56,8 @@ github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/sagernet/sing v0.6.1 h1:mJ6e7Ir2wtCoGLbdnnXWBsNJu5YHtbXmv66inoE0zFA=
github.com/sagernet/sing v0.6.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.6.2 h1:TR9WeH0yDJMjSFThqgFYe/i2pdH69Gb0tDJzJLPuVec=
github.com/sagernet/sing v0.6.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
@@ -97,12 +97,12 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3 h1:0V/7Y1FEaFdAzb9DkVDh4QFp4vL4yYCiJ5cjk80lZyA=
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3/go.mod h1:j5VYNgQ6lZYZlzHFjdgS2UeqRSZunDk+/zXVTAIA3z4=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/mobile v0.0.0-20250305212854-3a7bc9f8a4de h1:WuckfUoaRGJfaQTPZvlmcaQwg4Xj9oS2cvvh3dUqpDo=
golang.org/x/mobile v0.0.0-20250305212854-3a7bc9f8a4de/go.mod h1:/IZuixag1ELW37+FftdmIt59/3esqpAWM/QqWtf7HUI=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
@@ -113,16 +113,16 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+1 -1
View File
@@ -12,7 +12,7 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 636
versionCode = 638
versionName = "1.9.39"
multiDexEnabled = true
@@ -4,6 +4,7 @@ au.com.shiftyjelly.pocketcasts
bbc.mobile.news.ww
be.mygod.vpnhotspot
ch.protonmail.android
cm.aptoide.pt
co.wanqu.android
com.alphainventor.filemanager
com.amazon.kindle
@@ -34,7 +35,9 @@ com.chrome.canary
com.chrome.dev
com.cl.newt66y
com.cradle.iitc_mobile
org.exarhteam.iitc_mobile
com.cygames.shadowverse
com.dcard.freedom
com.devhd.feedly
com.devolver.reigns2
com.discord
@@ -108,6 +111,7 @@ com.ifttt.ifttt
com.imgur.mobile
com.innologica.inoreader
com.instagram.android
com.instagram.lite
com.instapaper.android
com.jarvanh.vpntether
com.kapp.youtube.final
@@ -115,6 +119,7 @@ com.klinker.android.twitter_l
com.lastpass.lpandroid
com.linecorp.linelite
com.lingodeer
com.ltnnews.news
com.mediapods.tumbpods
com.mgoogle.android.gms
com.microsoft.emmx
@@ -159,6 +164,7 @@ com.slack
com.snaptube.premium
com.sololearn
com.sonelli.juicessh
com.sparkslab.dcardreader
com.spotify.music
com.tencent.huatuo
com.termux
@@ -173,10 +179,13 @@ com.twitter.android
com.u91porn
com.u9porn
com.ubisoft.dance.justdance2015companion
com.udn.news
com.utopia.pxview
com.valvesoftware.android.steam.communimunity
com.valvesoftware.android.steam.community
com.vanced.manager
com.vanced.android.youtube
com.vanced.android.apps.youtube.music
com.mgoogle.android.gms
com.vimeo.android.videoapp
com.vivaldi.browser
com.vivaldi.browser.snapshot
@@ -186,10 +195,12 @@ com.wire
com.wuxiangai.refactor
com.xda.labs
com.xvideos.app
com.yahoo.mobile.client.android.superapp
com.yandex.browser
com.yandex.browser.beta
com.yandex.browser.alpha
com.z28j.feel
com.zhiliaoapp.musically
con.medium.reader
de.apkgrabber
de.robv.android.xposed.installer
@@ -210,6 +221,7 @@ jp.bokete.app.android
jp.naver.line.android
jp.pxv.android
luo.speedometergpspro
m.cna.com.tw.App
mark.via.gp
me.tshine.easymark
net.teeha.android.url_shortener
@@ -226,6 +238,7 @@ org.mozilla.firefox_beta
org.mozilla.focus
org.schabi.newpipe
org.telegram.messenger
org.telegram.messenger.web
org.telegram.multi
org.telegram.plus
org.thunderdog.challegram
@@ -239,3 +252,162 @@ tw.com.gamer.android.activecenter
videodownloader.downloadvideo.downloader
uk.co.bbc.learningenglish
com.ted.android
de.danoeh.antennapod
com.kiwibrowser.browser
nekox.messenger
com.nextcloud.client
com.aurora.store
com.aurora.adroid
chat.simplex.app
im.vector.app
network.loki.messenger
eu.siacs.conversations
xyz.nextalone.nagram
net.programmierecke.radiodroid2
im.fdx.v2ex
ml.docilealligator.infinityforreddit
com.bytemyth.ama
app.vanadium.browser
com.cakewallet.cake_wallet
org.purplei2p.i2pd
dk.tacit.android.foldersync.lite
com.nononsenseapps.feeder
com.m2049r.xmrwallet
com.paypal.android.p2pmobile
com.google.android.apps.googlevoice
com.readdle.spark
org.torproject.torbrowser
com.deepl.mobiletranslator
com.microsoft.bing
com.keylesspalace.tusky
com.ottplay.ottplay
ru.iptvremote.android.iptv.pro
jp.naver.line.android
com.xmflsct.app.tooot
com.forem.android
app.revanced.android.youtube
com.mgoogle.android.gms
com.pionex.client
vip.mytokenpocket
im.token.app
com.linekong.mars24
com.feixiaohao
com.aicoin.appandroid
com.binance.dev
com.kraken.trade
com.okinc.okex.gp
com.authy.authy
air.com.rosettastone.mobile.CoursePlayer
com.blizzard.bma
com.amazon.kindle
com.google.android.apps.fitness
net.tsapps.appsales
com.wemesh.android
com.google.android.apps.googleassistant
allen.town.focus.reader
me.hyliu.fluent_reader_lite
com.aljazeera.mobile
com.ft.news
de.marmaro.krt.ffupdater
myradio.radio.fmradio.liveradio.radiostation
com.google.earth
eu.kanade.tachiyomi.j2k
com.audials
com.microsoft.skydrive
com.mb.android.tg
com.melodis.midomiMusicIdentifier.freemium
com.foxnews.android
ch.threema.app
com.briarproject.briar.android
foundation.e.apps
com.valvesoftware.android.steam.friendsui
com.imback.yeetalk
so.onekey.app.wallet
com.xc3fff0e.xmanager
meditofoundation.medito
com.picol.client
com.streetwriters.notesnook
shanghai.panewsApp.com
org.coursera.android
com.positron_it.zlib
com.blizzard.messenger
com.javdb.javrocket
com.picacomic.fregata
com.fxl.chacha
me.proton.android.drive
com.lastpass.lpandroid
com.tradingview.tradingviewapp
com.deviantart.android.damobile
com.fusionmedia.investing
com.ewa.ewaapp
com.duolingo
com.hellotalk
io.github.huskydg.magisk
com.jsy.xpgbox
com.hostloc.app.hostloc
com.dena.pokota
com.vitorpamplona.amethyst
com.zhiliaoapp.musically
us.spotco.fennec_dos
com.fongmi.android.tv
com.pocketprep.android.itcybersecurity
com.cloudtv
com.glassdoor.app
com.indeed.android.jobsearch
com.linkedin.android
com.github.tvbox.osc.bh
com.example.douban
com.sipnetic.app
com.microsoft.rdc.androidx
org.zwanoo.android.speedtest
com.sonelli.juicessh
com.scmp.newspulse
org.lsposed.manager
mnn.Android
com.thomsonretuers.reuters
com.guardian
com.ttxapps.onesyncv2
org.fcitx.fcitx5.android.updater
com.tailscale.ipn
tw.nekomimi.nekogram
com.nexon.kartdrift
io.syncapps.lemmy_sync
com.seazon.feedme
com.readwise
de.spiritcroc.riotx
com.openai.chatgpt
io.changenow.changenow
com.poe.android
com.twingate
com.blinkslabs.blinkist.android
com.ichi2.anki
md.obsidian
com.musixmatch.android.lyrify
com.cyber.turbo
com.offsec.nethunter
me.ghui.v2er
com.samruston.twitter
org.adaway
org.swiftapps.swiftbackup
com.zerotier.one
com.quietmobile
com.instagram.barcelona
im.molly.app
com.rvx.android.youtube
com.deepl.mobiletranslator
com.qingsong.yingmi
com.lemurbrowser.exts
com.silverdev.dnartdroid
me.ash.reader
de.tutao.tutanota
dev.imranr.obtainium
com.getsomeheadspace.android
org.cromite.cromite
com.nutomic.syncthingandroid
com.bumble.app
com.cnn.mobile.android.phone
com.google.android.apps.authenticator2
com.microsoft.copilot
com.netflix.NGP.Storyteller
com.Slack
com.server.auditor.ssh.client
@@ -1,8 +1,6 @@
package com.v2ray.ang
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.multidex.MultiDexApplication
import androidx.work.Configuration
import androidx.work.WorkManager
@@ -8,8 +8,10 @@ import com.google.gson.JsonSerializer
import com.google.gson.annotations.SerializedName
import com.google.gson.reflect.TypeToken
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.*
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.*
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.ServersBean
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.VnextBean
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean
import com.v2ray.ang.util.Utils
import java.lang.reflect.Type
@@ -4,7 +4,6 @@ import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.V2rayConfig.OutboundBean
import com.v2ray.ang.extension.isNotNullEmpty
import kotlin.text.orEmpty
object HttpFmt : FmtBase() {
fun toOutbound(profileItem: ProfileItem): OutboundBean? {
@@ -7,7 +7,6 @@ import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.extension.isNotNullEmpty
import com.v2ray.ang.util.Utils
import java.net.URI
import kotlin.text.orEmpty
object SocksFmt : FmtBase() {
fun parse(str: String): ProfileItem? {
@@ -9,7 +9,6 @@ import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.util.Utils
import java.net.URI
import kotlin.text.orEmpty
object TrojanFmt : FmtBase() {
fun parse(str: String): ProfileItem? {
@@ -14,7 +14,6 @@ import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.Utils
import java.net.URI
import kotlin.text.orEmpty
object VmessFmt : FmtBase() {
fun parse(str: String): ProfileItem? {
@@ -8,7 +8,6 @@ import com.v2ray.ang.dto.V2rayConfig.OutboundBean
import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.util.Utils
import java.net.URI
import kotlin.text.orEmpty
object WireguardFmt : FmtBase() {
fun parse(str: String): ProfileItem? {
@@ -16,6 +16,7 @@ import com.v2ray.ang.fmt.TrojanFmt
import com.v2ray.ang.fmt.VlessFmt
import com.v2ray.ang.fmt.VmessFmt
import com.v2ray.ang.fmt.WireguardFmt
import com.v2ray.ang.util.HttpUtil
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.QRCodeDecoder
import com.v2ray.ang.util.Utils
@@ -346,7 +347,7 @@ object AngConfigManager {
if (!it.second.enabled) {
return 0
}
val url = Utils.idnToASCII(it.second.url)
val url = HttpUtil.idnToASCII(it.second.url)
if (!Utils.isValidUrl(url)) {
return 0
}
@@ -354,7 +355,7 @@ object AngConfigManager {
var configText = try {
val httpPort = SettingsManager.getHttpPort()
Utils.getUrlContentWithCustomUserAgent(url, 30000, httpPort)
HttpUtil.getUrlContentWithUserAgent(url, 30000, httpPort)
} catch (e: Exception) {
Log.e(AppConfig.ANG_PACKAGE, "Update subscription: proxy not ready or other error, try……")
//e.printStackTrace()
@@ -362,7 +363,7 @@ object AngConfigManager {
}
if (configText.isEmpty()) {
configText = try {
Utils.getUrlContentWithCustomUserAgent(url)
HttpUtil.getUrlContentWithUserAgent(url)
} catch (e: Exception) {
e.printStackTrace()
""
@@ -22,7 +22,6 @@ import com.v2ray.ang.util.Utils.parseInt
import java.io.File
import java.io.FileOutputStream
import java.util.Collections
import kotlin.Int
object SettingsManager {
@@ -16,7 +16,6 @@
package com.v2ray.ang.helper
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.graphics.Canvas
import android.view.animation.DecelerateInterpolator
import androidx.recyclerview.widget.GridLayoutManager
@@ -13,6 +13,6 @@ class BootReceiver : BroadcastReceiver() {
//Check if flag is true and a server is selected
if (!MmkvManager.decodeStartOnBoot() || MmkvManager.getSelectServer().isNullOrEmpty()) return
//Start v2ray
V2RayServiceManager.startV2Ray(context)
V2RayServiceManager.startVService(context)
}
}
@@ -5,9 +5,7 @@ import android.content.Context
import android.content.Intent
import android.text.TextUtils
import com.v2ray.ang.AppConfig
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
class TaskerReceiver : BroadcastReceiver() {
@@ -22,13 +20,12 @@ class TaskerReceiver : BroadcastReceiver() {
return
} else if (switch) {
if (guid == AppConfig.TASKER_DEFAULT_GUID) {
Utils.startVServiceFromToggle(context)
V2RayServiceManager.startVServiceFromToggle(context)
} else {
MmkvManager.setSelectServer(guid)
V2RayServiceManager.startV2Ray(context)
V2RayServiceManager.startVService(context, guid)
}
} else {
Utils.stopVService(context)
V2RayServiceManager.stopVService(context)
}
} catch (e: Exception) {
e.printStackTrace()
@@ -11,7 +11,6 @@ import android.widget.RemoteViews
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
class WidgetProvider : AppWidgetProvider() {
/**
@@ -19,7 +18,7 @@ class WidgetProvider : AppWidgetProvider() {
*/
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
updateWidgetBackground(context, appWidgetManager, appWidgetIds, V2RayServiceManager.v2rayPoint.isRunning)
updateWidgetBackground(context, appWidgetManager, appWidgetIds, V2RayServiceManager.isRunning())
}
@@ -57,10 +56,10 @@ class WidgetProvider : AppWidgetProvider() {
override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
if (AppConfig.BROADCAST_ACTION_WIDGET_CLICK == intent.action) {
if (V2RayServiceManager.v2rayPoint.isRunning) {
Utils.stopVService(context)
if (V2RayServiceManager.isRunning()) {
V2RayServiceManager.stopVService(context)
} else {
Utils.startVServiceFromToggle(context)
V2RayServiceManager.startVServiceFromToggle(context)
}
} else if (AppConfig.BROADCAST_ACTION_ACTIVITY == intent.action) {
AppWidgetManager.getInstance(context)?.let { manager ->
@@ -0,0 +1,214 @@
package com.v2ray.ang.service
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.R
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.toSpeedString
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.ui.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlin.math.min
object NotificationService {
private const val NOTIFICATION_ID = 1
private const val NOTIFICATION_PENDING_INTENT_CONTENT = 0
private const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
private const val NOTIFICATION_PENDING_INTENT_RESTART_V2RAY = 2
private const val NOTIFICATION_ICON_THRESHOLD = 3000
private var lastQueryTime = 0L
private var mBuilder: NotificationCompat.Builder? = null
private var speedNotificationJob: Job? = null
private var mNotificationManager: NotificationManager? = null
fun startSpeedNotification(currentConfig: ProfileItem?) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_SPEED_ENABLED) != true) return
if (speedNotificationJob != null || V2RayServiceManager.isRunning() == false) return
lastQueryTime = System.currentTimeMillis()
var lastZeroSpeed = false
val outboundTags = currentConfig?.getAllOutboundTags()
outboundTags?.remove(TAG_DIRECT)
speedNotificationJob = CoroutineScope(Dispatchers.IO).launch {
while (isActive) {
val queryTime = System.currentTimeMillis()
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
var proxyTotal = 0L
val text = StringBuilder()
outboundTags?.forEach {
val up = V2RayServiceManager.queryStats(it, AppConfig.UPLINK)
val down = V2RayServiceManager.queryStats(it, AppConfig.DOWNLINK)
if (up + down > 0) {
appendSpeedString(text, it, up / sinceLastQueryInSeconds, down / sinceLastQueryInSeconds)
proxyTotal += up + down
}
}
val directUplink = V2RayServiceManager.queryStats(TAG_DIRECT, AppConfig.UPLINK)
val directDownlink = V2RayServiceManager.queryStats(TAG_DIRECT, AppConfig.DOWNLINK)
val zeroSpeed = proxyTotal == 0L && directUplink == 0L && directDownlink == 0L
if (!zeroSpeed || !lastZeroSpeed) {
if (proxyTotal == 0L) {
appendSpeedString(text, outboundTags?.firstOrNull(), 0.0, 0.0)
}
appendSpeedString(
text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds
)
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
}
lastZeroSpeed = zeroSpeed
lastQueryTime = queryTime
delay(3000)
}
}
}
fun showNotification(currentConfig: ProfileItem?) {
val service = getService() ?: return
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
val startMainIntent = Intent(service, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(service, NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent, flags)
val stopV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
stopV2RayIntent.`package` = ANG_PACKAGE
stopV2RayIntent.putExtra("key", AppConfig.MSG_STATE_STOP)
val stopV2RayPendingIntent = PendingIntent.getBroadcast(service, NOTIFICATION_PENDING_INTENT_STOP_V2RAY, stopV2RayIntent, flags)
val restartV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
restartV2RayIntent.`package` = ANG_PACKAGE
restartV2RayIntent.putExtra("key", AppConfig.MSG_STATE_RESTART)
val restartV2RayPendingIntent = PendingIntent.getBroadcast(service, NOTIFICATION_PENDING_INTENT_RESTART_V2RAY, restartV2RayIntent, flags)
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
} else {
// If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
""
}
mBuilder = NotificationCompat.Builder(service, channelId)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(currentConfig?.remarks)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true)
.setShowWhen(false)
.setOnlyAlertOnce(true)
.setContentIntent(contentPendingIntent)
.addAction(
R.drawable.ic_delete_24dp,
service.getString(R.string.notification_action_stop_v2ray),
stopV2RayPendingIntent
)
.addAction(
R.drawable.ic_delete_24dp,
service.getString(R.string.title_service_restart),
restartV2RayPendingIntent
)
//.build()
//mBuilder?.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) //取消震动,铃声其他都不好使
service.startForeground(NOTIFICATION_ID, mBuilder?.build())
}
fun cancelNotification() {
val service = getService() ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
service.stopForeground(Service.STOP_FOREGROUND_REMOVE)
} else {
service.stopForeground(true)
}
mBuilder = null
speedNotificationJob?.cancel()
speedNotificationJob = null
}
fun stopSpeedNotification(currentConfig: ProfileItem?) {
speedNotificationJob?.let {
it.cancel()
speedNotificationJob = null
updateNotification(currentConfig?.remarks, 0, 0)
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String {
val channelId = AppConfig.RAY_NG_CHANNEL_ID
val channelName = AppConfig.RAY_NG_CHANNEL_NAME
val chan = NotificationChannel(
channelId,
channelName, NotificationManager.IMPORTANCE_HIGH
)
chan.lightColor = Color.DKGRAY
chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
getNotificationManager()?.createNotificationChannel(chan)
return channelId
}
private fun updateNotification(contentText: String?, proxyTraffic: Long, directTraffic: Long) {
if (mBuilder != null) {
if (proxyTraffic < NOTIFICATION_ICON_THRESHOLD && directTraffic < NOTIFICATION_ICON_THRESHOLD) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_name)
} else if (proxyTraffic > directTraffic) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_proxy)
} else {
mBuilder?.setSmallIcon(R.drawable.ic_stat_direct)
}
mBuilder?.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
mBuilder?.setContentText(contentText) // Emui4.1 need content text even if style is set as BigTextStyle
getNotificationManager()?.notify(NOTIFICATION_ID, mBuilder?.build())
}
}
private fun getNotificationManager(): NotificationManager? {
if (mNotificationManager == null) {
val service = getService() ?: return null
mNotificationManager = service.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
return mNotificationManager
}
private fun appendSpeedString(text: StringBuilder, name: String?, up: Double, down: Double) {
var n = name ?: "no tag"
n = n.substring(0, min(n.length, 6))
text.append(n)
for (i in n.length..6 step 2) {
text.append("\t")
}
text.append("${up.toLong().toSpeedString()}${down.toLong().toSpeedString()}\n")
}
private fun getService(): Service? {
return V2RayServiceManager.serviceControl?.get()?.getService()
}
}
@@ -26,7 +26,7 @@ class QSTileService : TileService() {
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
} else if (state == Tile.STATE_ACTIVE) {
qsTile?.state = Tile.STATE_ACTIVE
qsTile?.label = V2RayServiceManager.currentConfig?.remarks
qsTile?.label = V2RayServiceManager.getRunningServerName()
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
}
@@ -64,11 +64,11 @@ class QSTileService : TileService() {
super.onClick()
when (qsTile.state) {
Tile.STATE_INACTIVE -> {
Utils.startVServiceFromToggle(this)
V2RayServiceManager.startVServiceFromToggle(this)
}
Tile.STATE_ACTIVE -> {
Utils.stopVService(this)
V2RayServiceManager.stopVService(this)
}
}
}
@@ -1,57 +1,38 @@
package com.v2ray.ang.service
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.AppConfig.VPN
import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.toSpeedString
import com.v2ray.ang.extension.toast
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.V2rayConfigManager
import com.v2ray.ang.ui.MainActivity
import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.PluginUtil
import com.v2ray.ang.util.Utils
import go.Seq
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import libv2ray.Libv2ray
import libv2ray.V2RayPoint
import libv2ray.V2RayVPNServiceSupportsSet
import java.lang.ref.SoftReference
import kotlin.math.min
object V2RayServiceManager {
private const val NOTIFICATION_ID = 1
private const val NOTIFICATION_PENDING_INTENT_CONTENT = 0
private const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
private const val NOTIFICATION_PENDING_INTENT_RESTART_V2RAY = 2
private const val NOTIFICATION_ICON_THRESHOLD = 3000
val v2rayPoint: V2RayPoint = Libv2ray.newV2RayPoint(V2RayCallback(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
private val v2rayPoint: V2RayPoint = Libv2ray.newV2RayPoint(V2RayCallback(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
private val mMsgReceive = ReceiveMessageHandler()
private var currentConfig: ProfileItem? = null
var serviceControl: SoftReference<ServiceControl>? = null
set(value) {
@@ -59,14 +40,33 @@ object V2RayServiceManager {
Seq.setContext(value?.get()?.getService()?.applicationContext)
Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()), Utils.getDeviceIdForXUDPBaseKey())
}
var currentConfig: ProfileItem? = null
private var lastQueryTime = 0L
private var mBuilder: NotificationCompat.Builder? = null
private var speedNotificationJob: Job? = null
private var mNotificationManager: NotificationManager? = null
fun startVServiceFromToggle(context: Context): Boolean {
if (MmkvManager.getSelectServer().isNullOrEmpty()) {
context.toast(R.string.app_tile_first_use)
return false
}
startContextService(context)
return true
}
fun startV2Ray(context: Context) {
fun startVService(context: Context, guid: String? = null) {
if (guid != null) {
MmkvManager.setSelectServer(guid)
}
startContextService(context)
}
fun stopVService(context: Context) {
context.toast(R.string.toast_services_stop)
MessageUtil.sendMsg2Service(context, AppConfig.MSG_STATE_STOP, "")
}
fun isRunning() = v2rayPoint.isRunning
fun getRunningServerName() = currentConfig?.remarks.orEmpty()
private fun startContextService(context: Context) {
if (v2rayPoint.isRunning) return
val guid = MmkvManager.getSelectServer() ?: return
val config = MmkvManager.decodeServerConfig(guid) ?: return
@@ -82,7 +82,7 @@ object V2RayServiceManager {
} else {
context.toast(R.string.toast_services_start)
}
val intent = if ((MmkvManager.decodeSettingsString(AppConfig.PREF_MODE) ?: VPN) == VPN) {
val intent = if ((MmkvManager.decodeSettingsString(AppConfig.PREF_MODE) ?: AppConfig.VPN) == AppConfig.VPN) {
Intent(context.applicationContext, V2RayVpnService::class.java)
} else {
Intent(context.applicationContext, V2RayProxyOnlyService::class.java)
@@ -94,6 +94,116 @@ object V2RayServiceManager {
}
}
/**
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
*/
fun startV2rayPoint() {
val service = getService() ?: return
val guid = MmkvManager.getSelectServer() ?: return
val config = MmkvManager.decodeServerConfig(guid) ?: return
if (v2rayPoint.isRunning) {
return
}
val result = V2rayConfigManager.getV2rayConfig(service, guid)
if (!result.status)
return
try {
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE)
mFilter.addAction(Intent.ACTION_SCREEN_ON)
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
mFilter.addAction(Intent.ACTION_USER_PRESENT)
ContextCompat.registerReceiver(service, mMsgReceive, mFilter, Utils.receiverFlags())
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
v2rayPoint.configureFileContent = result.content
v2rayPoint.domainName = result.domainPort
currentConfig = config
try {
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6))
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
if (v2rayPoint.isRunning) {
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_START_SUCCESS, "")
NotificationService.showNotification(currentConfig)
PluginUtil.runPlugin(service, config, result.domainPort)
} else {
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_START_FAILURE, "")
NotificationService.cancelNotification()
}
}
fun stopV2rayPoint() {
val service = getService() ?: return
if (v2rayPoint.isRunning) {
CoroutineScope(Dispatchers.IO).launch {
try {
v2rayPoint.stopLoop()
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
}
}
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_STOP_SUCCESS, "")
NotificationService.cancelNotification()
try {
service.unregisterReceiver(mMsgReceive)
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
PluginUtil.stopPlugin()
}
fun queryStats(tag: String, link: String): Long {
return v2rayPoint.queryStats(tag, link)
}
private fun measureV2rayDelay() {
CoroutineScope(Dispatchers.IO).launch {
val service = getService() ?: return@launch
var time = -1L
var errstr = ""
if (v2rayPoint.isRunning) {
try {
time = v2rayPoint.measureDelay(Utils.getDelayTestUrl())
} catch (e: Exception) {
Log.d(ANG_PACKAGE, "measureV2rayDelay: $e")
errstr = e.message?.substringAfter("\":") ?: "empty message"
}
if (time == -1L) {
try {
time = v2rayPoint.measureDelay(Utils.getDelayTestUrl(true))
} catch (e: Exception) {
Log.d(ANG_PACKAGE, "measureV2rayDelay: $e")
errstr = e.message?.substringAfter("\":") ?: "empty message"
}
}
}
val result = if (time == -1L) {
service.getString(R.string.connection_test_error, errstr)
} else {
service.getString(R.string.connection_test_available, time)
}
MessageUtil.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_SUCCESS, result)
}
}
private fun getService(): Service? {
return serviceControl?.get()?.getService()
}
private class V2RayCallback : V2RayVPNServiceSupportsSet {
override fun shutdown(): Long {
val serviceControl = serviceControl?.get() ?: return -1
@@ -124,8 +234,7 @@ object V2RayServiceManager {
val serviceControl = serviceControl?.get() ?: return -1
return try {
serviceControl.startService()
lastQueryTime = System.currentTimeMillis()
startSpeedNotification()
NotificationService.startSpeedNotification(currentConfig)
0
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
@@ -134,77 +243,6 @@ object V2RayServiceManager {
}
}
/**
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
*/
fun startV2rayPoint() {
val service = serviceControl?.get()?.getService() ?: return
val guid = MmkvManager.getSelectServer() ?: return
val config = MmkvManager.decodeServerConfig(guid) ?: return
if (v2rayPoint.isRunning) {
return
}
val result = V2rayConfigManager.getV2rayConfig(service, guid)
if (!result.status)
return
try {
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE)
mFilter.addAction(Intent.ACTION_SCREEN_ON)
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
mFilter.addAction(Intent.ACTION_USER_PRESENT)
ContextCompat.registerReceiver(service, mMsgReceive, mFilter, Utils.receiverFlags())
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
v2rayPoint.configureFileContent = result.content
v2rayPoint.domainName = result.domainPort
currentConfig = config
try {
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6))
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
if (v2rayPoint.isRunning) {
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_START_SUCCESS, "")
showNotification()
PluginUtil.runPlugin(service, config, result.domainPort)
} else {
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_START_FAILURE, "")
cancelNotification()
}
}
fun stopV2rayPoint() {
val service = serviceControl?.get()?.getService() ?: return
if (v2rayPoint.isRunning) {
CoroutineScope(Dispatchers.IO).launch {
try {
v2rayPoint.stopLoop()
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
}
}
MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_STOP_SUCCESS, "")
cancelNotification()
try {
service.unregisterReceiver(mMsgReceive)
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
PluginUtil.stopPlugin()
}
private class ReceiveMessageHandler : BroadcastReceiver() {
override fun onReceive(ctx: Context?, intent: Intent?) {
val serviceControl = serviceControl?.get() ?: return
@@ -234,7 +272,7 @@ object V2RayServiceManager {
Log.d(ANG_PACKAGE, "Restart Service")
serviceControl.stopService()
Thread.sleep(500L)
startV2Ray(serviceControl.getService())
startVService(serviceControl.getService())
}
AppConfig.MSG_MEASURE_DELAY -> {
@@ -245,213 +283,14 @@ object V2RayServiceManager {
when (intent?.action) {
Intent.ACTION_SCREEN_OFF -> {
Log.d(ANG_PACKAGE, "SCREEN_OFF, stop querying stats")
stopSpeedNotification()
NotificationService.stopSpeedNotification(currentConfig)
}
Intent.ACTION_SCREEN_ON -> {
Log.d(ANG_PACKAGE, "SCREEN_ON, start querying stats")
startSpeedNotification()
NotificationService.startSpeedNotification(currentConfig)
}
}
}
}
private fun measureV2rayDelay() {
CoroutineScope(Dispatchers.IO).launch {
val service = serviceControl?.get()?.getService() ?: return@launch
var time = -1L
var errstr = ""
if (v2rayPoint.isRunning) {
try {
time = v2rayPoint.measureDelay(Utils.getDelayTestUrl())
} catch (e: Exception) {
Log.d(ANG_PACKAGE, "measureV2rayDelay: $e")
errstr = e.message?.substringAfter("\":") ?: "empty message"
}
if (time == -1L) {
try {
time = v2rayPoint.measureDelay(Utils.getDelayTestUrl(true))
} catch (e: Exception) {
Log.d(ANG_PACKAGE, "measureV2rayDelay: $e")
errstr = e.message?.substringAfter("\":") ?: "empty message"
}
}
}
val result = if (time == -1L) {
service.getString(R.string.connection_test_error, errstr)
} else {
service.getString(R.string.connection_test_available, time)
}
MessageUtil.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_SUCCESS, result)
}
}
private fun showNotification() {
val service = serviceControl?.get()?.getService() ?: return
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
val startMainIntent = Intent(service, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(service, NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent, flags)
val stopV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
stopV2RayIntent.`package` = ANG_PACKAGE
stopV2RayIntent.putExtra("key", AppConfig.MSG_STATE_STOP)
val stopV2RayPendingIntent = PendingIntent.getBroadcast(service, NOTIFICATION_PENDING_INTENT_STOP_V2RAY, stopV2RayIntent, flags)
val restartV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
restartV2RayIntent.`package` = ANG_PACKAGE
restartV2RayIntent.putExtra("key", AppConfig.MSG_STATE_RESTART)
val restartV2RayPendingIntent = PendingIntent.getBroadcast(service, NOTIFICATION_PENDING_INTENT_RESTART_V2RAY, restartV2RayIntent, flags)
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
} else {
// If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
""
}
mBuilder = NotificationCompat.Builder(service, channelId)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(currentConfig?.remarks)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true)
.setShowWhen(false)
.setOnlyAlertOnce(true)
.setContentIntent(contentPendingIntent)
.addAction(
R.drawable.ic_delete_24dp,
service.getString(R.string.notification_action_stop_v2ray),
stopV2RayPendingIntent
)
.addAction(
R.drawable.ic_delete_24dp,
service.getString(R.string.title_service_restart),
restartV2RayPendingIntent
)
//.build()
//mBuilder?.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) //取消震动,铃声其他都不好使
service.startForeground(NOTIFICATION_ID, mBuilder?.build())
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String {
val channelId = AppConfig.RAY_NG_CHANNEL_ID
val channelName = AppConfig.RAY_NG_CHANNEL_NAME
val chan = NotificationChannel(
channelId,
channelName, NotificationManager.IMPORTANCE_HIGH
)
chan.lightColor = Color.DKGRAY
chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
getNotificationManager()?.createNotificationChannel(chan)
return channelId
}
fun cancelNotification() {
val service = serviceControl?.get()?.getService() ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
service.stopForeground(Service.STOP_FOREGROUND_REMOVE)
} else {
service.stopForeground(true)
}
mBuilder = null
speedNotificationJob?.cancel()
speedNotificationJob = null
}
private fun updateNotification(contentText: String?, proxyTraffic: Long, directTraffic: Long) {
if (mBuilder != null) {
if (proxyTraffic < NOTIFICATION_ICON_THRESHOLD && directTraffic < NOTIFICATION_ICON_THRESHOLD) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_name)
} else if (proxyTraffic > directTraffic) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_proxy)
} else {
mBuilder?.setSmallIcon(R.drawable.ic_stat_direct)
}
mBuilder?.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
mBuilder?.setContentText(contentText) // Emui4.1 need content text even if style is set as BigTextStyle
getNotificationManager()?.notify(NOTIFICATION_ID, mBuilder?.build())
}
}
private fun getNotificationManager(): NotificationManager? {
if (mNotificationManager == null) {
val service = serviceControl?.get()?.getService() ?: return null
mNotificationManager = service.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
return mNotificationManager
}
private fun startSpeedNotification() {
if (speedNotificationJob == null &&
v2rayPoint.isRunning &&
MmkvManager.decodeSettingsBool(AppConfig.PREF_SPEED_ENABLED) == true
) {
var lastZeroSpeed = false
val outboundTags = currentConfig?.getAllOutboundTags()
outboundTags?.remove(TAG_DIRECT)
speedNotificationJob = CoroutineScope(Dispatchers.IO).launch {
while (isActive) {
val queryTime = System.currentTimeMillis()
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
var proxyTotal = 0L
val text = StringBuilder()
outboundTags?.forEach {
val up = v2rayPoint.queryStats(it, AppConfig.UPLINK)
val down = v2rayPoint.queryStats(it, AppConfig.DOWNLINK)
if (up + down > 0) {
appendSpeedString(text, it, up / sinceLastQueryInSeconds, down / sinceLastQueryInSeconds)
proxyTotal += up + down
}
}
val directUplink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.UPLINK)
val directDownlink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.DOWNLINK)
val zeroSpeed = proxyTotal == 0L && directUplink == 0L && directDownlink == 0L
if (!zeroSpeed || !lastZeroSpeed) {
if (proxyTotal == 0L) {
appendSpeedString(text, outboundTags?.firstOrNull(), 0.0, 0.0)
}
appendSpeedString(
text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds
)
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
}
lastZeroSpeed = zeroSpeed
lastQueryTime = queryTime
delay(3000)
}
}
}
}
private fun appendSpeedString(text: StringBuilder, name: String?, up: Double, down: Double) {
var n = name ?: "no tag"
n = n.substring(0, min(n.length, 6))
text.append(n)
for (i in n.length..6 step 2) {
text.append("\t")
}
text.append("${up.toLong().toSpeedString()}${down.toLong().toSpeedString()}\n")
}
private fun stopSpeedNotification() {
speedNotificationJob?.let {
it.cancel()
speedNotificationJob = null
updateNotification(currentConfig?.remarks, 0, 0)
}
}
}
@@ -105,7 +105,37 @@ class V2RayVpnService : VpnService(), ServiceControl {
override fun onDestroy() {
super.onDestroy()
V2RayServiceManager.cancelNotification()
NotificationService.cancelNotification()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
V2RayServiceManager.startV2rayPoint()
return START_STICKY
//return super.onStartCommand(intent, flags, startId)
}
override fun getService(): Service {
return this
}
override fun startService() {
setup()
}
override fun stopService() {
stopV2Ray(true)
}
override fun vpnProtect(socket: Int): Boolean {
return protect(socket)
}
@RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let {
MyContextWrapper.wrap(newBase, Utils.getLocale())
}
super.attachBaseContext(context)
}
private fun setup() {
@@ -114,6 +144,14 @@ class V2RayVpnService : VpnService(), ServiceControl {
return
}
if (setupVpnService() != true) {
return
}
runTun2socks()
}
private fun setupVpnService(): Boolean {
// If the old interface has exactly the same parameters, use it!
// Configure a builder while parsing the parameters.
val builder = Builder()
@@ -152,7 +190,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
}
// }
builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty())
builder.setSession(V2RayServiceManager.getRunningServerName())
val selfPackageName = BuildConfig.APPLICATION_ID
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY)) {
@@ -200,12 +238,13 @@ class V2RayVpnService : VpnService(), ServiceControl {
try {
mInterface = builder.establish()!!
isRunning = true
runTun2socks()
return true
} catch (e: Exception) {
// non-nullable lateinit var
e.printStackTrace()
stopV2Ray()
}
return false
}
private fun runTun2socks() {
@@ -279,12 +318,6 @@ class V2RayVpnService : VpnService(), ServiceControl {
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
V2RayServiceManager.startV2rayPoint()
return START_STICKY
//return super.onStartCommand(intent, flags, startId)
}
private fun stopV2Ray(isForced: Boolean = true) {
// val configName = defaultDPreference.getPrefString(PREF_CURR_CONFIG_GUID, "")
// val emptyInfo = VpnNetworkInfo()
@@ -324,27 +357,4 @@ class V2RayVpnService : VpnService(), ServiceControl {
}
}
override fun getService(): Service {
return this
}
override fun startService() {
setup()
}
override fun stopService() {
stopV2Ray(true)
}
override fun vpnProtect(socket: Int): Boolean {
return protect(socket)
}
@RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let {
MyContextWrapper.wrap(newBase, Utils.getLocale())
}
super.attachBaseContext(context)
}
}
@@ -7,7 +7,6 @@ import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.tencent.mmkv.MMKV
@@ -1,7 +1,6 @@
package com.v2ray.ang.ui
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.ColorStateList
@@ -39,6 +38,7 @@ import com.v2ray.ang.handler.MigrateManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.HttpUtil
import com.v2ray.ang.util.Utils
import com.v2ray.ang.viewmodel.MainViewModel
import kotlinx.coroutines.Dispatchers
@@ -46,7 +46,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.drakeet.support.toast.ToastCompat
import java.util.concurrent.TimeUnit
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
private val binding by lazy {
@@ -141,7 +140,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
binding.fab.setOnClickListener {
if (mainViewModel.isRunning.value == true) {
Utils.stopVService(this)
V2RayServiceManager.stopVService(this)
} else if ((MmkvManager.decodeSettingsString(AppConfig.PREF_MODE) ?: VPN) == VPN) {
val intent = VpnService.prepare(this)
if (intent == null) {
@@ -270,12 +269,12 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
toast(R.string.title_file_chooser)
return
}
V2RayServiceManager.startV2Ray(this)
V2RayServiceManager.startVService(this)
}
fun restartV2Ray() {
if (mainViewModel.isRunning.value == true) {
Utils.stopVService(this)
V2RayServiceManager.stopVService(this)
}
lifecycleScope.launch {
delay(500)
@@ -626,7 +625,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
lifecycleScope.launch(Dispatchers.IO) {
val configText = try {
Utils.getUrlContentWithCustomUserAgent(url)
HttpUtil.getUrlContentWithUserAgent(url)
} catch (e: Exception) {
e.printStackTrace()
""
@@ -26,7 +26,6 @@ import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.*
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>(), ItemTouchHelperAdapter {
companion object {
@@ -165,11 +164,11 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
}
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
if (isRunning) {
Utils.stopVService(mActivity)
V2RayServiceManager.stopVService(mActivity)
mActivity.lifecycleScope.launch {
try {
delay(500)
V2RayServiceManager.startV2Ray(mActivity)
V2RayServiceManager.startVService(mActivity)
} catch (e: Exception) {
e.printStackTrace()
}
@@ -19,6 +19,7 @@ import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.util.AppManagerUtil
import com.v2ray.ang.util.HttpUtil
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -154,7 +155,7 @@ class PerAppProxyActivity : BaseActivity() {
toast(R.string.msg_downloading_content)
val url = AppConfig.androidpackagenamelistUrl
lifecycleScope.launch(Dispatchers.IO) {
val content = Utils.getUrlContext(url, 5000)
val content = HttpUtil.getUrlContent(url, 5000)
launch(Dispatchers.Main) {
Log.d(ANG_PACKAGE, content)
selectProxyApp(content, true)

Some files were not shown because too many files have changed in this diff Show More