Merge pull request #13 from SuperChamp234/dev

Version 0.9.15
This commit is contained in:
Zain 2021-11-16 19:11:00 +05:30 committed by GitHub
commit d29bfd9995
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 264 additions and 170 deletions

View file

@ -1,7 +1,7 @@
{ {
"id": "obsidian-habitica-integration", "id": "obsidian-habitica-integration",
"name": "Habitica Sync", "name": "Habitica Sync",
"version": "0.9.7", "version": "0.9.15",
"minAppVersion": "0.9.12", "minAppVersion": "0.9.12",
"description": "This plugin helps integrate Habitica user tasks and stats into Obsidian", "description": "This plugin helps integrate Habitica user tasks and stats into Obsidian",
"author": "Leoh and Ran", "author": "Leoh and Ran",

View file

@ -31,6 +31,7 @@
"node-fetch": "^3.0.0", "node-fetch": "^3.0.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-emoji-render": "^1.2.4",
"react-tabs": "^3.2.2" "react-tabs": "^3.2.2"
} }
} }

View file

@ -1,17 +1,30 @@
import * as React from "react"; import * as React from "react";
import { Notice } from "obsidian"; import { Notice } from "obsidian";
import { getStats, scoreTask } from "./habiticaAPI" import { getStats, scoreTask, makeCronReq } from "./habiticaAPI"
import Statsview from "./Components/Statsview" import Statsview from "./Components/Statsview"
import Taskview from "./Components/Taskview" import Taskview from "./Components/Taskview"
class App extends React.Component<any,any> { class App extends React.Component<any,any> {
username = "" private _username = "";
credentials = "" public get username() {
return this._username;
}
public set username(value) {
this._username = value;
}
private _credentials = "";
public get credentials() {
return this._credentials;
}
public set credentials(value) {
this._credentials = value;
}
constructor(props: any) { constructor(props: any) {
super(props) super(props)
this.username = this.props.plugin.settings.userID this.username = this.props.plugin.settings.userID
this.credentials = this.props.plugin.settings.apiToken this.credentials = this.props.plugin.settings.apiToken
this.state = { this.state = {
needCron: false,
isLoaded: false, isLoaded: false,
user_data: { user_data: {
profile: { profile: {
@ -20,18 +33,48 @@ class App extends React.Component<any,any> {
stats: { stats: {
hp: 0, hp: 0,
lvl: 0, lvl: 0,
} },
lastCron: "",
}, },
todos: [], todos: [],
dailys: [], dailys: [],
habits: [], habits: [],
} }
this.handleChangeTodos = this.handleChangeTodos.bind(this) this.handleChangeTodos = this.handleChangeTodos.bind(this);
this.handleChangeDailys = this.handleChangeDailys.bind(this) this.handleChangeDailys = this.handleChangeDailys.bind(this);
this.handleChangeHabits = this.handleChangeHabits.bind(this) this.handleChangeHabits = this.handleChangeHabits.bind(this);
this.runCron = this.runCron.bind(this);
} }
CheckCron(lastCron: string) {
let cronDate = new Date(lastCron);
let now = new Date();
if (cronDate.getDate() != now.getDate() || (cronDate.getMonth() != now.getMonth() || cronDate.getFullYear() != now.getFullYear())) {
return(
<div className="cron">
<div id="cronMessage"> Welcome back! Please check your tasks for the last day and hit continue to get your daily rewards. </div>
<button onClick={this.runCron}>Continue</button>
</div>
);
}
else {
console.log("Cron is up to date");
return null
};
}
async runCron() {
console.log("running cron");
try {
let response = await makeCronReq(this.username, this.credentials);
this.setState({
needCron: false,
})
} catch (error) {
console.log(error);
new Notice("There was an error running the cron. Please try again later.");
}
this.reloadData();
}
async reloadData() { async reloadData() {
try { try {
let response = await getStats(this.username, this.credentials); let response = await getStats(this.username, this.credentials);
@ -40,6 +83,7 @@ class App extends React.Component<any,any> {
new Notice('Login Failed, Please check credentials and try again!'); new Notice('Login Failed, Please check credentials and try again!');
} }
else { else {
console.log(result);
this.setState({ this.setState({
isLoaded: true, isLoaded: true,
user_data: result, user_data: result,
@ -115,6 +159,7 @@ class App extends React.Component<any,any> {
} }
render(){ render(){
let content = this.CheckCron(this.state.user_data.lastCron);
if(this.state.error) if(this.state.error)
return(<div className="loading">Loading....</div>) return(<div className="loading">Loading....</div>)
else if(!this.state.isLoaded) else if(!this.state.isLoaded)
@ -124,6 +169,7 @@ class App extends React.Component<any,any> {
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<Statsview user_data={this.state.user_data} /> <Statsview user_data={this.state.user_data} />
<Taskview data={this.state.tasks} handleChangeTodos={this.handleChangeTodos} handleChangeDailys={this.handleChangeDailys} handleChangeHabits={this.handleChangeHabits}/> <Taskview data={this.state.tasks} handleChangeTodos={this.handleChangeTodos} handleChangeDailys={this.handleChangeDailys} handleChangeHabits={this.handleChangeHabits}/>
{content}
</div> </div>
); );
} }

View file

@ -1,10 +1,11 @@
import * as React from "react"; import Emoji from "react-emoji-render";
import * as React from "react";
function DailyItem(props: any) { function DailyItem(props: any) {
return ( return (
<div className="todo-item" id={props.id}> <div className="todo-item" id={props.id}>
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/> <input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
<p>{props.daily_text}</p> <p><Emoji text={props.daily_text}></Emoji></p>
</div> </div>
) )
} }

View file

@ -1,4 +1,5 @@
import * as React from "react"; import Emoji from "react-emoji-render";
import * as React from "react";
function HabitItem(props: any) { function HabitItem(props: any) {
return ( return (
@ -6,7 +7,7 @@ function HabitItem(props: any) {
<button className="habit-plus" id={"plus"+props.id} onClick={props.onChange}> <button className="habit-plus" id={"plus"+props.id} onClick={props.onChange}>
+{props.upCount} +{props.upCount}
</button> </button>
<p className="habit-text">{props.habit_text}</p> <p className="habit-text"><Emoji text = {props.habit_text}></Emoji></p>
<button className="habit-minus" id={"mins"+props.id} onClick={props.onChange}> <button className="habit-minus" id={"mins"+props.id} onClick={props.onChange}>
-{props.downCount} -{props.downCount}
</button> </button>

View file

@ -1,10 +1,11 @@
import * as React from "react"; import { Emoji } from 'react-emoji-render';
import * as React from "react";
function TodoItem(props: any) { function TodoItem(props: any) {
return ( return (
<div className="todo-item" id={props.id}> <div className="todo-item" id={props.id}>
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/> <input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
<p>{props.todo_text}</p> <Emoji text = {props.todo_text}></Emoji>
</div> </div>
) )
} }

View file

@ -1,10 +1,11 @@
import * as React from "react"; import Emoji from "react-emoji-render";
import * as React from "react";
function TodoItem(props: any) { function TodoItem(props: any) {
return ( return (
<div className="todo-item" id={props.id}> <div className="todo-item" id={props.id}>
<input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/> <input type="checkbox" className="checkbox" id={props.id} onChange={props.onChange} checked={props.completed}/>
<p>{props.todo_text}</p> <p><Emoji text ={props.todo_text}></Emoji></p>
</div> </div>
) )
} }

View file

@ -6,7 +6,7 @@ export async function getStats(username: string, credentials: string){
method: 'GET', method: 'GET',
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"x-client": username.concat("-testAPI"), "x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
"x-api-user": username, "x-api-user": username,
"x-api-key": credentials, "x-api-key": credentials,
}, },
@ -20,7 +20,20 @@ export async function scoreTask(username: string, credentials: string, taskID: s
method: 'POST', method: 'POST',
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"x-client": username.concat("-testAPI"), "x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
"x-api-user": username,
"x-api-key": credentials,
}
})
return(response)
}
export async function makeCronReq(username: string, credentials: string){
const url = "https://habitica.com/api/v3/cron";
const response = fetch(url, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"x-client": "278e719e-5f9c-43b1-9dba-8b73343dc062-HabiticaSync",
"x-api-user": username, "x-api-user": username,
"x-api-key": credentials, "x-api-key": credentials,
} }

View file

@ -1,151 +1,181 @@
#profile-name { #profile-name {
font-size: x-large; font-size: x-large;
font-weight: bold; font-weight: bold;
padding-bottom: 3%; padding-bottom: 3%;
} }
.stats { .stats {
padding-bottom: 6px; padding-bottom: 6px;
} }
.todo-item { .todo-item {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 0px 0px 0; padding: 0px 0px 0;
width: 80%; width: 80%;
border-bottom: 1px solid #cecece; border-bottom: 1px solid #cecece;
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;
font-weight: normal; font-weight: normal;
font-size: 16px; font-size: 16px;
} }
.habit-text { .habit-text {
text-align: center !important; text-align: center !important;
padding: 0px; padding: 0px;
width: 80px; width: 50%;
margin-right: 20px; margin-right: 20px;
} }
.habit-plus { .habit-plus {
/* background-color: #fff; */ /* background-color: #fff; */
border: none; border: none;
color: white; color: white;
padding: 7px 10px; padding: 7px 10px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
font-size: 16px; font-size: 16px;
} }
.habit-minus { .habit-minus {
/* background-color: #fff; */ /* background-color: #fff; */
/* border-radius: 50%; */ /* border-radius: 50%; */
border: none; border: none;
color: white; color: white;
padding: 7px 10px; padding: 7px 10px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
font-size: 16px; font-size: 16px;
} }
.habit-item { .habit-item {
display: flex; display: flex;
/* justify-content: center; */ /* justify-content: center; */
align-content: space-between; align-content: space-between;
align-items: center; align-items: center;
padding: 0px 0px 0; padding: 0px 0px 0;
width: 100%; width: 100%;
border-bottom: 1px solid #cecece; border-bottom: 1px solid #cecece;
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;
font-weight: 50%; font-weight: 50%;
font-size: 16px; font-size: 16px;
} }
input[type=checkbox] { input[type=checkbox] {
margin-right: 10px; margin-right: 10px;
} }
input[type=checkbox]:focus { input[type=checkbox]:focus {
outline: 0; outline: 0;
} }
.plugin-root { .plugin-root {
min-width: 260px; min-width: 260px;
} }
.substats { .substats {
font-size: medium; font-size: medium;
} }
/* react-tabs internal file :wink: */ /* react-tabs internal file :wink: */
.material-icons { .material-icons {
font-size: 12px !important; font-size: 12px !important;
padding-top: 1px; padding-top: 1px;
padding-right: 2px; padding-right: 2px;
} }
.material-icons.md-18 { font-size: 18px !important; } .material-icons.md-18 { font-size: 18px !important; }
.material-icons.md-24 { font-size: 24px !important; } .material-icons.md-24 { font-size: 24px !important; }
.material-icons.md-32 { font-size: 32px !important; } .material-icons.md-32 { font-size: 32px !important; }
.material-icons.md-48 { font-size: 48px !important; } .material-icons.md-48 { font-size: 48px !important; }
.react-tabs { .react-tabs {
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
.react-tabs__tab-list { .react-tabs__tab-list {
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
margin: 0 0 10px; margin: 0 0 10px;
padding: 0; padding: 0;
} }
.react-tabs__tab { .react-tabs__tab {
display: inline-block; display: inline-block;
border: 1px solid transparent; border: 1px solid transparent;
border-bottom: none; border-bottom: none;
bottom: -1px; bottom: -1px;
position: relative; position: relative;
list-style: none; list-style: none;
padding: 1% 2%; padding: 1% 2%;
cursor: pointer; cursor: pointer;
font-size: medium; font-size: medium;
} }
.react-tabs__tab--selected { .react-tabs__tab--selected {
background: var(--interactive-accent); background: var(--interactive-accent);
color: white; color: white;
border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0;
} }
.react-tabs__tab--disabled { .react-tabs__tab--disabled {
color: GrayText; color: GrayText;
cursor: default; cursor: default;
} }
.react-tabs__tab:focus { .react-tabs__tab:focus {
box-shadow: 0 0 5px hsl(208, 99%, 50%); box-shadow: 0 0 5px hsl(208, 99%, 50%);
border-color: hsl(208, 99%, 50%); border-color: hsl(208, 99%, 50%);
outline: none; outline: none;
} }
.react-tabs__tab:focus:after { .react-tabs__tab:focus:after {
content: ""; content: "";
position: absolute; position: absolute;
height: 5px; height: 5px;
left: -4px; left: -4px;
right: -4px; right: -4px;
bottom: -5px; bottom: -5px;
background: #fff; background: #fff;
} }
.react-tabs__tab-panel { .react-tabs__tab-panel {
display: none; display: none;
} }
.react-tabs__tab-panel--selected { .react-tabs__tab-panel--selected {
display: block; display: block;
} }
ul li:not(.task-list-item)::before {
content: "•";
color: transparent;
display: inline-block;
width: 1em;
margin-left: -1em;
padding: 0;
font-weight: bold;
text-shadow: 0 0 0.5em transparent;
}
body > div.app-container.is-left-sidedock-collapsed.is-right-sidedock-collapsed > div.horizontal-main-container > div > div.workspace-split.mod-horizontal.mod-right-split > div.workspace-tabs > div.workspace-leaf > div > div.view-content > div > div.cron > button {
margin: auto;
margin-bottom: 5px;
}
.cron {
display: inline-grid;
justify-content: center;
text-align: center;;
margin-top: 5px;
margin-left: 10%;
margin-right: 10%;
margin-bottom: 10px;
background-color: var(--background-secondary-alt);
border-radius: 10px;
}
#cronMessage {
margin: 20px;
margin-bottom: 10px;
color: var(--text-normal)
}