proxy-head.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { useEffect, useState } from "react";
  2. import { useTranslation } from "react-i18next";
  3. import { Box, IconButton, TextField, SxProps } from "@mui/material";
  4. import {
  5. AccessTimeRounded,
  6. MyLocationRounded,
  7. NetworkCheckRounded,
  8. FilterAltRounded,
  9. FilterAltOffRounded,
  10. VisibilityRounded,
  11. VisibilityOffRounded,
  12. WifiTetheringRounded,
  13. WifiTetheringOffRounded,
  14. SortByAlphaRounded,
  15. SortRounded,
  16. } from "@mui/icons-material";
  17. import { useVerge } from "@/hooks/use-verge";
  18. import type { HeadState } from "./use-head-state";
  19. import type { ProxySortType } from "./use-filter-sort";
  20. import delayManager from "@/services/delay";
  21. interface Props {
  22. sx?: SxProps;
  23. groupName: string;
  24. headState: HeadState;
  25. onLocation: () => void;
  26. onCheckDelay: () => void;
  27. onHeadState: (val: Partial<HeadState>) => void;
  28. }
  29. export const ProxyHead = (props: Props) => {
  30. const { sx = {}, groupName, headState, onHeadState } = props;
  31. const { showType, sortType, filterText, textState, testUrl } = headState;
  32. const { t } = useTranslation();
  33. const [autoFocus, setAutoFocus] = useState(false);
  34. useEffect(() => {
  35. // fix the focus conflict
  36. const timer = setTimeout(() => setAutoFocus(true), 100);
  37. return () => clearTimeout(timer);
  38. }, []);
  39. const { verge } = useVerge();
  40. useEffect(() => {
  41. delayManager.setUrl(groupName, testUrl || verge?.default_latency_test!);
  42. }, [groupName, testUrl, verge?.default_latency_test]);
  43. return (
  44. <Box sx={{ display: "flex", alignItems: "center", ...sx }}>
  45. <IconButton
  46. size="small"
  47. color="inherit"
  48. title={t("Location")}
  49. onClick={props.onLocation}
  50. >
  51. <MyLocationRounded />
  52. </IconButton>
  53. <IconButton
  54. size="small"
  55. color="inherit"
  56. title={t("Delay check")}
  57. onClick={() => {
  58. // Remind the user that it is custom test url
  59. if (testUrl?.trim() && textState !== "filter") {
  60. onHeadState({ textState: "url" });
  61. }
  62. props.onCheckDelay();
  63. }}
  64. >
  65. <NetworkCheckRounded />
  66. </IconButton>
  67. <IconButton
  68. size="small"
  69. color="inherit"
  70. title={
  71. [t("Sort by default"), t("Sort by delay"), t("Sort by name")][
  72. sortType
  73. ]
  74. }
  75. onClick={() =>
  76. onHeadState({ sortType: ((sortType + 1) % 3) as ProxySortType })
  77. }
  78. >
  79. {sortType === 0 && <SortRounded />}
  80. {sortType === 1 && <AccessTimeRounded />}
  81. {sortType === 2 && <SortByAlphaRounded />}
  82. </IconButton>
  83. <IconButton
  84. size="small"
  85. color="inherit"
  86. title={t("Delay check URL")}
  87. onClick={() =>
  88. onHeadState({ textState: textState === "url" ? null : "url" })
  89. }
  90. >
  91. {textState === "url" ? (
  92. <WifiTetheringRounded />
  93. ) : (
  94. <WifiTetheringOffRounded />
  95. )}
  96. </IconButton>
  97. <IconButton
  98. size="small"
  99. color="inherit"
  100. title={t("Proxy detail")}
  101. onClick={() => onHeadState({ showType: !showType })}
  102. >
  103. {showType ? <VisibilityRounded /> : <VisibilityOffRounded />}
  104. </IconButton>
  105. <IconButton
  106. size="small"
  107. color="inherit"
  108. title={t("Filter")}
  109. onClick={() =>
  110. onHeadState({ textState: textState === "filter" ? null : "filter" })
  111. }
  112. >
  113. {textState === "filter" ? (
  114. <FilterAltRounded />
  115. ) : (
  116. <FilterAltOffRounded />
  117. )}
  118. </IconButton>
  119. {textState === "filter" && (
  120. <TextField
  121. autoFocus={autoFocus}
  122. hiddenLabel
  123. value={filterText}
  124. size="small"
  125. variant="outlined"
  126. placeholder={t("Filter conditions")}
  127. onChange={(e) => onHeadState({ filterText: e.target.value })}
  128. sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
  129. />
  130. )}
  131. {textState === "url" && (
  132. <TextField
  133. autoFocus={autoFocus}
  134. hiddenLabel
  135. autoSave="off"
  136. autoComplete="off"
  137. value={testUrl}
  138. size="small"
  139. variant="outlined"
  140. placeholder={t("Delay check URL")}
  141. onChange={(e) => onHeadState({ testUrl: e.target.value })}
  142. sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
  143. />
  144. )}
  145. </Box>
  146. );
  147. };