我們使用中央氣象局的氣象開放資料平台
我們先註冊後獲取API授權碼
先來看一下API Docs
我們這邊要使用現在天氣觀測
測試並觀察
打開tauri.conf.json
加入
{
"tauri": {
"allowlist": {
"http": {
"all": true,
"request": true ,
"scope": ["https://opendata.cwb.gov.tw/api/*"]
}
}
}
}
打開todo\src\pages\index.tsx
並加入
//
import { fetch } from '@tauri-apps/api/http';
//
cont url = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/O-A0003-001?Authorization=CWB-DB6D5CC3-504F-4A00-ADFC-3730E9A2C95D&stationId=466920&elementName=TEMP¶meterName=CITY";
const response = await fetch(url, {
method: 'GET',
timeout: 30,
});
//
<div>
<h1>Temp is : {temp}</h1>
</div>
新增todo\src\pages\index.tsx
import { useEffect, useState } from "react";
import { invoke } from '@tauri-apps/api/tauri';
import { message, confirm, ask } from '@tauri-apps/api/dialog';
import { sendNotification } from "@tauri-apps/api/notification";
import { writeTextFile, BaseDirectory, readTextFile } from '@tauri-apps/api/fs';
import { unregister, register } from '@tauri-apps/api/globalShortcut';
import { fetch } from '@tauri-apps/api/http';
const itemStyle = {
padding: '8px',
};
const buttons = [
{
value: 10, display: "10s",
},
{
value: 1800, display: "30m",
}
];
interface Todo {
id: number,
title: string,
date: string,
done: boolean
}
function App() {
const [todos, setTodos] = useState<Todo[]>([]);
const [todo, setTodo] = useState<Todo>({id: -1, title: "", date: "None", done: false});
// Timer
const [time, setTime] = useState(0);
const [timerStart, setTimerStart] = useState(false);
// weather
const [temp, setTemp] = useState();
// Weather
const url = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/O-A0003-001?Authorization=CWB-DB6D5CC3-504F-4A00-ADFC-3730E9A2C95D&stationId=466920&elementName=TEMP¶meterName=CITY";
const handleGetWeather = async () => {
const response = await fetch(url, {
method: 'GET'
});
let data: any = response.data;
setTemp(data.records.location[0].weatherElement[0].elementValue);
}
useEffect(() => {
handleGetWeather();
}, []);
// Shorcut
const handleShortcutWithImport = async () => {
await register('Control+Shift+P', () => {
console.log('Shortcut triggered');
handleImportFile();
});
}
useEffect(() => {
handleShortcutWithImport();
},[]);
// Export
const handleExportFile = async () => {
const separator = ',';
const keys = Object.keys(todos[0]);
const csvContent =
keys.join(separator) +
'\n' +
todos.map(row => {
return keys.map(k => {
let cell = row[k] === null || row[k] === undefined ? '' : row[k];
cell = cell instanceof Date
? cell.toLocaleString()
: cell.toString().replace(/"/g, '""');
if (cell.search(/("|,|\n)/g) >= 0) {
cell = `"${cell}"`;
}
return cell;
}).join(separator);
}).join('\n');
console.log(csvContent);
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
let text = await blob.text();
await writeTextFile('todos.csv', text, { dir: BaseDirectory.Download });
await message('Export todos!!', 'Export done!!');
}
// Import
const handleImportFile = async () => {
const csv = await readTextFile('todos.csv', { dir: BaseDirectory.Download });
var lines=csv.split("\n");
let result = [];
var headers=lines[0].split(",");
for(var i=1;i<lines.length;i++){
var obj = {};
var currentline=lines[i].split(",");
for(var j=0;j<headers.length;j++){
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
result.forEach(async (element: Todo) => {
await invoke("new_todo", { title: element.title, date: element.date });
});
await message('Import all todos!!', 'Import done!!');
}
// Pomodoro
useEffect(() => {
const hanleInterval = setInterval(() => {
if(timerStart) {
if(time > 0) {
setTime(time -1);
} else if (time == 0) {
sendNotification({
title: `Time up!!`,
body: `Done Pomodoro`,
});
clearInterval(hanleInterval);
}
}
}, 1000);
return () => clearInterval(hanleInterval);
}, [timerStart, time]);
const toggleTimer = () => {
setTimerStart(!timerStart);
}
const triggerResetDialog = async () => {
let shouldReset = await ask("Reset?", {
title: "Pomodoro Timer",
type: "warning",
})
if(shouldReset) {
setTime(900);
setTimerStart(false);
}
}
// Todo
useEffect(()=> {
fetchAllTodo();
}, [todos]);
const fetchAllTodo = async () => {
setTodos(await invoke("get_todos"));
}
const handleTitleChange = (e: React.FormEvent<HTMLInputElement>) => {
let value = e.currentTarget.value;
setTodo({...todo, title: value});
}
const handleTodoAdd = async () => {
let date = Date.now().toString();
await invoke("new_todo", { title: todo.title, date: date });
setTodo({...todo, title: ""});
}
const handleTodoDelete = async (id: number) => {
console.log(id);
const confirmed = await confirm('This action cannot be reverted. Are you sure?', { title: 'Tauri', type: 'warning' });
if(confirmed) {
await invoke("delete_todo", { id: id});
}
setTodo({...todo, title: ""});
}
const handleChecked = async (index: number) => {
await invoke("done_todo", {id : todos[index].id, msg: todos[index].title});
if(!todos[index].done) {
await message("Done", { title: 'Todo' });
await handleDoneNotification();
}
}
const handleDoneNotification = async () => {
await sendNotification({
title: `Todo is done`,
body: `Great, you did it!!!!!!!!!`,
});
}
return (
<div className="container">
<div>
<h1>Temp is : {temp}</h1>
</div>
<div>
<h1>
{`${
Math.floor(time / 60) < 10
? `0${Math.floor(time / 60)}`
: `${Math.floor(time / 60)}`
}:${time % 60 < 10 ? `0${time % 60}` : time % 60}`}
</h1>
</div>
<div className="row" style={{margin: 10}}>
<button onClick={toggleTimer}>
{!timerStart ? "Start" : "Pause"}
</button>
<button onClick={triggerResetDialog}>
Reset Timer
</button>
</div>
<div>
{buttons.map(({value, display}) => (
<button type="button" onClick={() => {
setTimerStart(false);
setTime(value);
}}>
{display}
</button>
))}
</div>
<h1>Todo List</h1>
<div className="row">
<input
id="greet-input"
onChange={(e) => handleTitleChange(e)}
placeholder="Enter a task..."
value={todo.title}
/>
<button type="button" onClick={() => handleTodoAdd()}>
Add
</button>
</div>
<hr />
{todos.map((todo, index) => {
return (
<div className="row" key={index}>
<div style={itemStyle}></div>
<span
onClick={() => handleChecked(index)}
style={{
textDecoration: todos[index].done && 'line-through',
}}
>
{todo.title}
</span>
<button type="button" onClick={() => handleTodoDelete(todo.id)}>
Delete
</button>
</div>
);
})}
{/* export */}
<hr/>
<div className="row">
<div>
<button type="button" onClick={() => handleExportFile()}>
Export
</button>
</div>
<div>
<button type="button" onClick={() => handleImportFile()}>
Import
</button>
</div>
</div>
</div>
);
}
export default App;