Skip to content

Commit

Permalink
Merge branch 'main' into mv2
Browse files Browse the repository at this point in the history
  • Loading branch information
sheepzh committed Sep 5, 2023
2 parents c26be73 + 2872ee4 commit 3fc1fa9
Show file tree
Hide file tree
Showing 19 changed files with 160 additions and 305 deletions.
20 changes: 15 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@

All notable changes to Time Tracker will be documented in this file.

Release time refers to the time when the installation package is submitted to the webstore. It is about one week for Edge to moderate packages, while only 1-2 days for Chrome and Firefox.
It is worth mentioning that the release time of each change refers to the time when the installation package is submitted to the webstore. It is about one week for Edge to moderate packages, while only 1-2 days for Chrome and Firefox.

## [v1.9.5] - 2023-09-05

- Fixed an issue where the restriction did not take effect in full screen mode (#234).
- Fixed the style error when setting restriction rules. (#233)

## [v1.9.4] - 2023-08-08

- Supported syncing data with [Local REST API for Obsibian](https://github.com/coddingtonbear/obsidian-local-rest-api).
- Display change log on the guide page and the context menu.

## [v1.9.3] - 2023-08-02

Expand All @@ -17,22 +27,22 @@ Release time refers to the time when the installation package is submitted to th
- Supported importing data exported from Webtime Tracker.
- Supported importing data exported from Web Activity Time Tracker.

## [1.9.0] - 2023-06-27
## [v1.9.0] - 2023-06-27

- Supported password and verification to unlock daily limit.
- Fixed known bugs.

## [1.8.2] - 2023-05-20
## [v1.8.2] - 2023-05-20

- Added contributor list of translation.
- Added Portuguese localization.
- Fixed known bugs.

## [1.8.1] - 2023-04-12
## [v1.8.1] - 2023-04-12

- Renamed from Timer to Time Tracker.

## [1.8.0] - 2023-04-04
## [v1.8.0] - 2023-04-04

- Refactored the guide page.
- Fixed the background color of sidebar.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "timer",
"version": "1.9.4",
"version": "1.9.5",
"description": "Web timer",
"homepage": "https://github.com/sheepzh/timer",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/api/chrome/common.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export function handleError(scene: string) {
try {
const lastError = chrome.runtime.lastError
lastError && console.log(`Errord when ${scene}: ${lastError.message}`)
lastError && console.log(`Errored when ${scene}: ${lastError.message}`)
} catch (e) {
console.info("Can't execute here")
}
Expand Down
48 changes: 46 additions & 2 deletions src/app/components/limit/table/column/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { t, tN } from "@app/locale"
import { locale } from "@i18n"
import { VerificationPair } from "@service/limit-service/verification/common"
import verificationProcessor from "@service/limit-service/verification/processor"
import { getCssVariable } from "@util/style"
import { ElMessageBox, ElMessage } from "element-plus"
import { h, VNode } from "vue"
import { defineComponent, h, onMounted, ref, VNode } from "vue"

/**
* Judge wether verification is required
Expand All @@ -19,6 +20,46 @@ const PROMT_TXT_CSS: Partial<CSSStyleDeclaration> = {
userSelect: 'none',
}

const ANSWER_CANVAS_FONT_SIZE = 24

const CANVAS_WRAPPER_CSS: Partial<CSSStyleDeclaration> = {
fontSize: `${ANSWER_CANVAS_FONT_SIZE}px`,
textAlign: 'center',
}

const AnswerCanvas = defineComponent({
props: {
text: String
},
setup: (props => {
const dom = ref<HTMLCanvasElement>()
const wrapper = ref<HTMLDivElement>()
const { text } = props

onMounted(() => {
const ele = dom.value
const ctx = ele.getContext("2d")
const height = Math.floor(ANSWER_CANVAS_FONT_SIZE * 1.3)
ele.height = height
const font = getComputedStyle(wrapper.value).font
// Set font to measure width
ctx.font = font
const { width } = ctx.measureText(text)
ele.width = width
// Need set font again after width changed
ctx.font = font
const color = getCssVariable("--el-text-color-primary")
ctx.fillStyle = color
ctx.fillText(text, 0, ANSWER_CANVAS_FONT_SIZE)
})

return () => h('div', {
style: CANVAS_WRAPPER_CSS,
ref: wrapper,
}, h('canvas', { ref: dom }))
})
})

/**
* @returns null if verification not required,
* or promise with resolve invocked only if verification code or password correct
Expand All @@ -43,7 +84,10 @@ export async function processVerification(option: timer.option.DailyLimitOption)
: prompt
messageNodes = tN(msg => msg.limit.verification.inputTip, { prompt: h('b', promptTxt) })
} else {
messageNodes = tN(msg => msg.limit.verification.inputTip2, { answer: h('b', answerValue) })
const answer: VNode = limitVerifyDifficulty === 'disgusting'
? h(AnswerCanvas, { text: answerValue })
: h('b', answerValue)
messageNodes = tN(msg => msg.limit.verification.inputTip2, { answer })
}
}
return messageNodes?.length && answerValue
Expand Down
12 changes: 0 additions & 12 deletions src/app/components/option/components/backup/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ const typeOptions = () => ALL_TYPES.map(type => h(ElOption, {
label: TYPE_NAMES[type],
}))

const typeSelect = (type: Ref<timer.backup.Type>, handleChange?: Function) => h(ElSelect,
{
modelValue: type.value,
size: 'small',
async onChange(newType: timer.backup.Type) {
type.value = newType
handleChange?.()
}
},
() => typeOptions()
)

const clientNameInput = (clientName: Ref<string>, handleInput?: Function) => h(ElInput, {
modelValue: clientName.value,
size: 'small',
Expand Down
3 changes: 0 additions & 3 deletions src/app/components/option/components/backup/style.sass
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
height: 20px
margin-right: 0
margin-left: 6px

.sop-dialog-container
margin-right: 16px
.el-dialog
text-align: center
.step-container
width: 400px
margin: auto
Expand Down
2 changes: 2 additions & 0 deletions src/app/styles/compatible.sass
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
font-size: 10px
.el-divider__text
background-color: transparent
.el-dialog.is-align-center
text-align: center
\:root
--el-input-height: 40px
--el-input-inner-height: 38px
3 changes: 1 addition & 2 deletions src/background/content-script-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* https://opensource.org/licenses/MIT
*/

import TimeLimitItem from "@entity/time-limit-item"
import limitService from "@service/limit-service"
import optionService from "@service/option-service"
import statService from "@service/stat-service"
Expand Down Expand Up @@ -42,5 +41,5 @@ export default function init(dispatcher: MessageDispatcher) {
// More minutes
.register<string, timer.limit.Item[]>('cs.moreMinutes', url => limitService.moreMinutes(url))
// cs.getLimitedRules
.register<string, TimeLimitItem[]>('cs.getLimitedRules', url => limitService.getLimited(url))
.register<string, timer.limit.Item[]>('cs.getLimitedRules', url => limitService.getLimited(url))
}
8 changes: 4 additions & 4 deletions src/background/limit-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import { createTab, listTabs, sendMsg2Tab } from "@api/chrome/tab"
import { LIMIT_ROUTE } from "@app/router/constants"
import TimeLimitItem from "@entity/time-limit-item"
import { getAppPageUrl } from "@util/constant/url"
import MessageDispatcher from "./message-dispatcher"
import { matches } from "@util/limit"

function processLimitWaking(rules: TimeLimitItem[], tab: ChromeTab) {
function processLimitWaking(rules: timer.limit.Item[], tab: ChromeTab) {
const { url } = tab
const anyMatch = rules.map(rule => rule.matches(url)).reduce((a, b) => a || b, false)
const anyMatch = rules.map(rule => matches(rule, url)).reduce((a, b) => a || b, false)
if (!anyMatch) {
return
}
Expand All @@ -31,7 +31,7 @@ export default function init(dispatcher: MessageDispatcher) {
.register<timer.limit.Item[]>(
'limitWaking',
async data => {
const rules = data?.map(like => TimeLimitItem.of(like)) || []
const rules = data || []
const tabs = await listTabs({ status: 'complete' })
tabs.forEach(tab => processLimitWaking(rules, tab))
}
Expand Down
2 changes: 1 addition & 1 deletion src/background/timer/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async function sendLimitedMessage(item: timer.limit.Item[]) {
const tabs = await listTabs({ status: 'complete' })
tabs.forEach(tab => sendMsg2Tab(tab.id, 'limitTimeMeet', item)
.then(() => console.log(`Processed limit rules: rule=${JSON.stringify(item)}`))
.catch(err => console.error(`Failed to execute limit rule: rule=${JSON.stringify(item)}, msg=${err.msg}`))
.catch(() => {/*Ignored*/ })
)
}

Expand Down
9 changes: 5 additions & 4 deletions src/content-script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import printInfo from "./printer"
const host = document?.location?.host
const url = document?.location?.href

const FLAG_ID = '__TIMER_INJECTION_FLAG__' + chrome.runtime.id

function getOrSetFlag(): boolean {
const flagId = '__TIMER_INJECTION_FLAG__'
const pre = document?.getElementById(flagId)
const pre = document?.getElementById(FLAG_ID)
if (!pre) {
const flag = document?.createElement('a')
flag.style.visibility = 'hidden'
flag && (flag.id = flagId)
flag.style && (flag.style.visibility = 'hidden')
flag && (flag.id = FLAG_ID)
document?.body?.appendChild(flag)
}
return !!pre
Expand Down
54 changes: 35 additions & 19 deletions src/content-script/limit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* https://opensource.org/licenses/MIT
*/

import TimeLimitItem from "@entity/time-limit-item"
import { hasLimited, matches } from "@util/limit"
import optionService from "@service/option-service"
import { t2Chrome } from "@i18n/chrome/t"
import { t } from "./locale"
Expand All @@ -30,13 +30,18 @@ class _Modal {
...maskStyle,
...filterStyle[filterType || 'translucent']
}
Object.assign(this.mask.style, realMaskStyle)
Object.assign(this.mask.style || {}, realMaskStyle)
}

showModal(showDelay: boolean) {
if (!document.body) {
return
}
// Exist full screen at first
exitScreen().then(() => this.showModalInner(showDelay))
}

private showModalInner(showDelay: boolean) {
const _thisUrl = this.url
if (showDelay && this.mask.childElementCount === 1) {
this.delayContainer = document.createElement('p')
Expand All @@ -45,15 +50,13 @@ class _Modal {
// Only delay-allowed rules exist, can delay
// @since 0.4.0
const link = document.createElement('a')
Object.assign(link.style, linkStyle)
Object.assign(link.style || {}, linkStyle)
link.setAttribute('href', 'javascript:void(0)')
const text = t(msg => msg.more5Minutes)
link.innerText = text
link.onclick = async () => {
const delayRules: timer.limit.Item[] = await sendMsg2Runtime('cs.moreMinutes', _thisUrl)
const wakingRules = delayRules
.map(like => TimeLimitItem.of(like))
.filter(rule => !rule.hasLimited())
const wakingRules = delayRules.filter(rule => !hasLimited(rule))
sendMsg2Runtime('limitWaking', wakingRules)
this.hideModal()
}
Expand All @@ -79,10 +82,10 @@ class _Modal {
this.visible = false
}

process(data: TimeLimitItem[]) {
const anyMatch = data.map(item => item.matches(this.url)).reduce((a, b) => a || b)
process(data: timer.limit.Item[]) {
const anyMatch = data.map(item => matches(item, this.url)).reduce((a, b) => a || b)
if (anyMatch) {
const anyDelay = data.map(item => item.matches(this.url) && item.allowDelay).reduce((a, b) => a || b)
const anyDelay = data.map(item => matches(item, this.url) && item.allowDelay).reduce((a, b) => a || b)
this.showModal(anyDelay)
}
}
Expand Down Expand Up @@ -122,9 +125,25 @@ const linkStyle: Partial<CSSStyleDeclaration> = {
fontSize: '16px !important'
}

function exitScreen(): Promise<void> {
const ele = document.fullscreenElement
if (!ele) {
return Promise.resolve()
}
return new Promise<void>(resolve => {
if (document.exitFullscreen) {
document.exitFullscreen()
.then(resolve)
.catch(e => console.warn("Failed to exit fullscreen", e))
} else {
resolve()
}
})
}

function link2Setup(url: string): HTMLParagraphElement {
const link = document.createElement('a')
Object.assign(link.style, linkStyle)
Object.assign(link.style || {}, linkStyle)
link.setAttribute('href', 'javascript:void(0)')
const text = t(msg => msg.timeLimitMsg)
.replace('{appName}', t2Chrome(msg => msg.meta.name))
Expand All @@ -139,11 +158,10 @@ async function handleLimitTimeMeet(msg: timer.mq.Request<timer.limit.Item[]>, mo
if (msg.code !== "limitTimeMeet") {
return { code: "ignore" }
}
const itemLikes: timer.limit.Item[] = msg.data
if (!itemLikes) {
const items: timer.limit.Item[] = msg.data
if (!items?.length) {
return { code: "fail", msg: "Empty time limit item" }
}
const items = itemLikes.map(itemLike => TimeLimitItem.of(itemLike))
modal.process(items)
return { code: "success" }
}
Expand All @@ -155,14 +173,13 @@ async function handleLimitWaking(msg: timer.mq.Request<timer.limit.Item[]>, moda
if (!modal.isVisible()) {
return { code: "ignore" }
}
const itemLikes: timer.limit.Item[] = msg.data
if (!itemLikes || !itemLikes.length) {
const items: timer.limit.Item[] = msg.data
if (!items?.length) {
return { code: "success", msg: "Empty time limit item" }
}
const items = itemLikes.map(itemLike => TimeLimitItem.of(itemLike))
for (let index in items) {
const item = items[index]
if (item.matches(modal.url) && !item.hasLimited()) {
if (matches(item, modal.url) && !hasLimited(item)) {
modal.hideModal()
break
}
Expand All @@ -172,8 +189,7 @@ async function handleLimitWaking(msg: timer.mq.Request<timer.limit.Item[]>, moda

async function handleLimitChanged(msg: timer.mq.Request<timer.limit.Item[]>, modal: _Modal): Promise<timer.mq.Response> {
if (msg.code === 'limitChanged') {
const data: timer.limit.Item[] = msg.data
const items = data.map(TimeLimitItem.of)
const items: timer.limit.Item[] = msg.data || []
items?.length ? modal.process(items) : modal.hideModal()
return { code: 'success' }
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/database/limit-database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { REMAIN_WORD_PREFIX } from "./common/constant"

const KEY = REMAIN_WORD_PREFIX + 'LIMIT'

declare type ItemValue = {
type ItemValue = {
/**
* Limited time, second
*/
Expand All @@ -34,7 +34,7 @@ declare type ItemValue = {
ad: boolean
}

declare type Item = {
type Item = {
[cond: string]: ItemValue
}

Expand Down
Loading

0 comments on commit 3fc1fa9

Please sign in to comment.