index_time.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. import { View, Text, Image } from "@tarojs/components";
  2. import './index_time.scss';
  3. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  4. import { getCommon, getDot } from "@/features/trackTimeDuration/hooks/RingData";
  5. import Rings, { RingCommon, BgRing, TargetRing, CurrentDot } from "@/features/trackTimeDuration/components/Rings";
  6. import { useEffect, useState } from "react";
  7. import DeviceInfo from 'react-native-device-info';
  8. import dayjs from "dayjs";
  9. import moment from 'moment-timezone'
  10. import Modal from "@/components/layout/Modal.weapp";
  11. import { loginAnonymous, place } from "./services/net";
  12. import Taro from "@tarojs/taro";
  13. import { useTranslation } from "react-i18next";
  14. import 'dayjs/locale/zh-cn';
  15. import 'dayjs/locale/en';
  16. // import 'moment/locale/en';
  17. let LinearGradient, useActionSheet, useNavigation
  18. if (process.env.TARO_ENV == 'rn') {
  19. LinearGradient = require('react-native-linear-gradient').default
  20. useActionSheet = require('@expo/react-native-action-sheet').useActionSheet
  21. useNavigation = require("@react-navigation/native").useNavigation
  22. }
  23. export default function IndexTimePage() {
  24. let navigation;
  25. if (useNavigation) {
  26. navigation = useNavigation()
  27. }
  28. const [count, setCount] = useState(0)
  29. const [showLanguage, setShowLanguage] = useState(false)
  30. const [isEn, setIsEn] = useState(true)
  31. const [showDst, setShowDst] = useState(false)
  32. const [current, setCurrent] = useState<any>(null)
  33. const { t, i18n } = useTranslation()
  34. useEffect(() => {
  35. getLanguage();
  36. login()
  37. setInterval(() => {
  38. setCount(t => t + 1)
  39. }, 1000)
  40. }, [])
  41. async function getLanguage() {
  42. var strLocation = await getStorage('lastLocation')
  43. if (strLocation) {
  44. setCurrent(JSON.parse(strLocation))
  45. }
  46. var language = await getStorage('language') || 'en'
  47. global.language = language;
  48. i18n.changeLanguage(language)
  49. setIsEn(language == 'en')
  50. dayjs.locale(language == 'en' ? 'en' : 'zh-cn');
  51. // moment.locale(language == 'en' ? 'en' : 'zh-cn');
  52. }
  53. async function getStorage(key: string) {
  54. try {
  55. const res = await Taro.getStorage({ key });
  56. return res.data;
  57. } catch {
  58. return '';
  59. }
  60. }
  61. function changeLanguage(isEnglish: boolean) {
  62. global.language = isEnglish ? 'en' : 'zh';
  63. i18n.changeLanguage(isEnglish ? 'en' : 'zh')
  64. setIsEn(isEnglish)
  65. Taro.setStorage({ key: 'language', data: isEnglish ? 'en' : 'zh' })
  66. setShowLanguage(false)
  67. dayjs.locale(isEnglish ? 'en' : 'zh-cn');
  68. // moment.locale(isEnglish ? 'en' : 'zh-cn');
  69. if (current) {
  70. chooseLocation({
  71. lat: current.geo.lat,
  72. lng: current.geo.lng
  73. })
  74. }
  75. }
  76. function login() {
  77. loginAnonymous(DeviceInfo.getDeviceSync()).then(res => {
  78. console.log('login success', res)
  79. }).catch(e => {
  80. console.log('login error', e)
  81. })
  82. }
  83. function goMap() {
  84. jumpPage('', 'map', navigation, {
  85. source: 'time_of_day',
  86. lat: current ? current.geo.lat : null,
  87. lng: current ? current.geo.lng : null,
  88. chooseLocation: chooseLocation
  89. })
  90. }
  91. function goRecords() {
  92. if (!current) {
  93. return
  94. }
  95. jumpPage('','MyPlaces',navigation)
  96. }
  97. function chooseLocation(res: any) {
  98. place(res.lat, res.lng).then(res => {
  99. console.log(res)
  100. setCurrent((res as any).location)
  101. saveLocation((res as any).location)
  102. }).catch(e => {
  103. console.log(e)
  104. })
  105. }
  106. function saveLocation(location: any) {
  107. Taro.setStorage({ key: 'lastLocation', data: JSON.stringify(location) })
  108. }
  109. function getLocation() {
  110. if (current.geo) {
  111. if (current.geo.city) {
  112. return current.geo.city
  113. }
  114. if (current.geo.country) {
  115. return current.geo.country
  116. }
  117. }
  118. return t('time_of_day.index.unknown')
  119. }
  120. function getTimezone() {
  121. if (current.time && current.time.timezone) {
  122. return current.time.timezone.abbrev + ' · ' + current.time.timezone.name
  123. }
  124. return ''
  125. }
  126. const common: RingCommon = {
  127. useCase: 'ChooseScenario',
  128. radius: 115,
  129. lineWidth: 26,
  130. isFast: true,
  131. status: 'WAIT_FOR_START'
  132. }
  133. const bgRing: BgRing = {
  134. color: '#EAE9E9'
  135. }
  136. function getArc() {
  137. var hour = new Date().getHours()
  138. var minute = new Date().getMinutes()
  139. var second = new Date().getSeconds()
  140. if (current) {
  141. var strHour = moment().tz(current.time.timezone.id).format('H')
  142. hour = parseInt(strHour)
  143. var strMin = moment().tz(current.time.timezone.id).format('m')
  144. minute = parseInt(strMin)
  145. var strSecond = moment().tz(current.time.timezone.id).format('s')
  146. second = parseInt(strSecond)
  147. }
  148. return (hour * 3600 + minute * 60 + second) / (24 * 3600) * 2 * Math.PI
  149. }
  150. function ring() {
  151. var offset = 0
  152. var hour = new Date().getHours()
  153. var minute = new Date().getMinutes()
  154. if (current) {
  155. var strHour = moment().tz(current.time.timezone.id).format('H')
  156. hour = parseInt(strHour)
  157. var strMin = moment().tz(current.time.timezone.id).format('m')
  158. minute = parseInt(strMin)
  159. }
  160. if (hour != new Date().getHours() || minute != new Date().getMinutes()) {
  161. offset = hour * 60 + minute - new Date().getHours() * 60 - new Date().getMinutes()
  162. }
  163. const currentDot: CurrentDot = {
  164. color: '#CACACA',
  165. lineWidth: 10,
  166. borderColor: '#ffffff',
  167. offset: offset
  168. }
  169. const targetRing: TargetRing = {
  170. color: '#CACACA',
  171. startArc: -Math.PI / 2,
  172. durationArc: getArc()
  173. }
  174. return <Rings common={common} bgRing={bgRing} targetRing={targetRing} currentDot={currentDot} canvasId={'smal11l'} />
  175. }
  176. function languageModalContent() {
  177. return <View className="modal_bg">
  178. <View className="language_content">
  179. <View className="language_item" onClick={() => changeLanguage(true)}>
  180. <Text className="language_text">English</Text>
  181. {
  182. isEn && <Image className="check" src={require('@assets/index_time/check.png')} />
  183. }
  184. </View>
  185. <View className="line" />
  186. <View className="language_item" onClick={() => changeLanguage(false)}>
  187. <Text className="language_text">中文</Text>
  188. {
  189. !isEn && <Image className="check" src={require('@assets/index_time/check.png')} />
  190. }
  191. </View>
  192. </View>
  193. </View>
  194. }
  195. function formatTime(format: string, timestamp?: number) {
  196. // var moment = require('moment-timezone');
  197. if (current) {
  198. if (timestamp) {
  199. return moment(timestamp).tz(current.time.timezone.id).format(format)
  200. }
  201. return moment().tz(current.time.timezone.id).format(format)
  202. }
  203. return dayjs().format(format)
  204. }
  205. function dstTitle(index: number) {
  206. if (index == 0) {
  207. return t('time_of_day.index.last_change')
  208. }
  209. return t('time_of_day.index.next_change')
  210. }
  211. function dstDesc(item: any, index: number) {
  212. if (index == 0) {
  213. if (item.new_dst > 0) {
  214. return t('time_of_day.index.summer_started')
  215. }
  216. return t('time_of_day.index.winter_started')
  217. }
  218. if (item.new_dst > 0) {
  219. return t('time_of_day.index.summer_starts')
  220. }
  221. return t('time_of_day.index.winter_starts')
  222. }
  223. function isNight() {
  224. var hour = new Date().getHours()
  225. if (current) {
  226. var strHour = moment().tz(current.time.timezone.id).format('H')
  227. hour = parseInt(strHour)
  228. }
  229. if (hour >= 18 || hour < 6) {
  230. return true
  231. }
  232. return false
  233. }
  234. function dstModalContent() {
  235. return <View className="modal_bg">
  236. {
  237. current.time_changes.map((item, index) => {
  238. return <View className="dst_content" key={index}>
  239. <View className="dst_item">
  240. <View className="dst_card">
  241. <Text className="month">{formatTime('MMMM', item.timestamp)}</Text>
  242. <Text className="day">{formatTime('D', item.timestamp)}</Text>
  243. <Text className="week">{formatTime('dddd', item.timestamp)}</Text>
  244. <Text className="year">{formatTime('YYYY', item.timestamp)}</Text>
  245. </View>
  246. </View>
  247. <View style={{ flex: 1 }}>
  248. <Text className="dst_title">{dstTitle(index)}</Text>
  249. <Text className="dst_desc" style={{ marginBottom: 10 }}>{dstDesc(item, index)}</Text>
  250. {
  251. item.descriptions.map((desc, j) => {
  252. return <Text className="dst_note" key={j * 100}>· {desc}</Text>
  253. })
  254. }
  255. </View>
  256. </View>
  257. })
  258. }
  259. </View>
  260. }
  261. return <View className="page_container">
  262. <View style={{ position: 'relative' }}>
  263. {
  264. ring()
  265. }
  266. <View className="ring_center">
  267. <Image className="sun" src={isNight() ? require('@assets/index_time/moon.png') : require('@assets/index_time/sun.png')} />
  268. <Text className="time">{formatTime('HH:mm:ss')}</Text>
  269. <Text className="date">{global.language == 'en' ? formatTime('dddd, MMM DD') : formatTime('MMMD dddd')}</Text>
  270. </View>
  271. </View>
  272. <View className="location">
  273. <Image className="location_icon" src={require('@assets/index_time/pin.png')} />
  274. <Text className="location_text">{current ? getLocation() : t('time_of_day.index.unknown')}</Text>
  275. </View>
  276. <View style={{ flexDirection: 'row', marginTop: 10, alignItems: 'center' }} onClick={() => {
  277. if (current && current.time && current.time.timezone.use_dst) {
  278. setShowDst(true)
  279. }
  280. }}>
  281. <Text className="timezone">{current ? getTimezone() : 'UTC+8'}</Text>
  282. {
  283. current && current.time && current.time.timezone.use_dst && <Image className="location_icon" src={require('@assets/index_time/arrow_right.png')} />
  284. }
  285. </View>
  286. <View className="btn_bg" onClick={goMap} onLongClick={goRecords}>
  287. <Text className="btn_text">{t('time_of_day.index.pick_location')}</Text>
  288. {
  289. current && <Image className="more" onClick={goRecords} src={require('@assets/index_time/more.png')} />
  290. }
  291. </View>
  292. <View className="footer" onClick={() => setShowLanguage(true)}>
  293. <Text className="footer_text">{isEn ? 'English' : '中文'}</Text>
  294. <Image className="footer_icon" src={require('@assets/index_time/arrow.png')} />
  295. </View>
  296. {
  297. showLanguage && <Modal
  298. testInfo={null}
  299. themeIsWhite={true}
  300. dismiss={() => {
  301. setShowLanguage(false)
  302. }}
  303. confirm={() => { }}>
  304. {
  305. languageModalContent()
  306. }
  307. </Modal>
  308. }
  309. {
  310. showDst && <Modal
  311. testInfo={null}
  312. themeIsWhite={true}
  313. dismiss={() => {
  314. setShowDst(false)
  315. }}
  316. confirm={() => { }}>
  317. {
  318. dstModalContent()
  319. }
  320. </Modal>
  321. }
  322. </View>
  323. }