Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement tasks page with creation, deletion functionallity #19

Merged
merged 5 commits into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ run:
# Default: 1m
timeout: 3m


# This file contains only configs which differ from defaults.
# All possible optios can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
linters-settings:
Expand Down Expand Up @@ -166,7 +165,7 @@ linters-settings:
nolintlint:
# Exclude following linters from requiring an explanation.
# Default: []
allow-no-explanation: [ funlen, gocognit, lll ]
allow-no-explanation: [funlen, gocognit, lll]
# Enable to require an explanation of nonzero length after each nolint directive.
# Default: false
require-explanation: true
Expand Down Expand Up @@ -209,7 +208,6 @@ linters-settings:
# Default: false
all: true


linters:
disable-all: true
enable:
Expand All @@ -233,8 +231,8 @@ linters:
- durationcheck # checks for two durations multiplied together
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13
# - exhaustive # checks exhaustiveness of enum switch statements
# - exportloopref # checks for pointers to enclosing loop variables
# - exhaustive # checks exhaustiveness of enum switch statements
# - exportloopref # checks for pointers to enclosing loop variables
- fatcontext # detects nested contexts in loops
- forbidigo # forbids identifiers
- funlen # tool for detection of long functions
Expand Down Expand Up @@ -278,7 +276,7 @@ linters:
- spancheck # checks for mistakes with OpenTelemetry/Census spans
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
- stylecheck # is a replacement for golint
- tenv # detects using os.Setenv instead of t.Setenv since Go1.17
- usetesting
- testableexamples # checks if examples are testable (have an expected output)
- testifylint # checks usage of github.com/stretchr/testify
- testpackage # makes you use a separate _test package
Expand All @@ -288,13 +286,14 @@ linters:
- usestdlibvars # detects the possibility to use variables/constants from the Go standard library
- wastedassign # finds wasted assignment statements
- whitespace # detects leading and trailing whitespace
- testifylint

## you may want to enable
- decorder # checks declaration order and count of types, constants, variables and functions
- exhaustruct # [highly recommend to enable] checks if all structure fields are initialized
# - gci # controls golang package import order and makes it always deterministic
# - gci # controls golang package import order and makes it always deterministic
#- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using ginkgo and gomega
- godox # detects FIXME1, TODO1 and other comment keywords
#- godox # detects FIXME1, TODO1 and other comment keywords
- goheader # checks is file header matches to pattern
#- inamedparam # [great idea, but too strict, need to ignore a lot of cases by default] reports interfaces with unnamed method parameters
- interfacebloat # checks the number of methods inside an interface
Expand Down Expand Up @@ -328,7 +327,6 @@ linters:
#- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers
#- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines


issues:
# Maximum count of issues with the same text.
# Set to 0 to disable.
Expand All @@ -337,9 +335,9 @@ issues:

exclude-rules:
- source: "(noinspection|TODO)"
linters: [ godot ]
linters: [godot]
- source: "//noinspection"
linters: [ gocritic ]
linters: [gocritic]
- path: "_test\\.go"
linters:
- bodyclose
Expand Down
1 change: 1 addition & 0 deletions ToDo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add mode with key tips on left screen side
Binary file modified assets/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 26 additions & 11 deletions bottom_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,46 @@ import (
"github.com/rivo/tview"
)

func constructBottomPanel() *tview.TextView {
textPanel := hotKeysForPanel()
func constructBottomPanel(curPage PageName) *tview.TextView {
textPanel := hotKeysForPanel(curPage)
panel := tview.NewTextView().SetDynamicColors(true).SetTextAlign(tview.AlignCenter).
SetText(textPanel)

return panel
}

func hotKeysForPanel() string {
func hotKeysForPanel(pageName PageName) string {
type keyWithPage struct {
key string
page string
key string
prettyPageName string

insidePages []PageName
}

keys := []keyWithPage{
{"1", "Focus"},
{"2", "Break"},
{"3", "Tasks"},
{"4", "Summary"},
{"5", "Detail"},
{"1", "Focus", []PageName{pauseFocusPage, activeFocusPage}},
{"2", "Break", []PageName{pauseBreakPage, activeBreakPage}},
{"3", "Tasks", []PageName{allTasksPage, addNewTaskPage, deleteTaskPage}},
{"4", "Summary", []PageName{summaryStatsPage}},
{"5", "Detail", []PageName{detailStatsPage, insertStatsPage}},
}

strs := make([]string, 0, len(keys))
for _, k := range keys {
strs = append(strs, fmt.Sprintf("%s[:gray]%s[:-]", k.key, k.page))
str := fmt.Sprintf("%s[:gray]%s[:-]", k.key, k.prettyPageName)
if containPage(pageName, k.insidePages) {
str = fmt.Sprintf("%s[:brown]%s[:-]", k.key, k.prettyPageName)
}
strs = append(strs, str)
}
return strings.Join(strs, " ")
}

func containPage(target PageName, pages []PageName) bool {
for _, page := range pages {
if target == page {
return true
}
}
return false
}
48 changes: 45 additions & 3 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ package main
import (
"database/sql"
"embed"
"errors"
"fmt"
"log/slog"
"path/filepath"
"time"

"github.com/arevbond/PomoTrack/config"
"github.com/pressly/goose/v3"

_ "github.com/mattn/go-sqlite3"
Expand All @@ -33,7 +32,8 @@ type Storage struct {
}

func NewStorage(filename string, logger *slog.Logger) (*Storage, error) {
db, err := sql.Open("sqlite3", filepath.Join(config.GetConfigDir(), filename))
// db, err := sql.Open("sqlite3", filepath.Join(config.GetConfigDir(), filename))
db, err := sql.Open("sqlite3", filename)
if err != nil {
return nil, fmt.Errorf("can't connect to db: %w", err)
}
Expand Down Expand Up @@ -189,3 +189,45 @@ func (s *Storage) DeleteTask(id int) error {
}
return nil
}

func (s *Storage) UpdateTask(task *Task) error {
query := `UPDATE tasks
SET name = ?, pomodoros_required = ?, pomodoros_completed = ?, is_complete = ?, is_active = ?
WHERE id = ?;`
args := []any{task.Name, task.PomodorosRequired, task.PomodorosCompleted, task.IsComplete, task.IsActive, task.ID}
_, err := s.DB.Exec(query, args...)
if err != nil {
return fmt.Errorf("can't upate task: %w", err)
}
return nil
}

func (s *Storage) ActiveTask() (*Task, error) {
query := `SELECT id, name, pomodoros_required, pomodoros_completed, is_complete, is_active, created_at
FROM tasks
WHERE is_active = true;`
var task Task
err := s.DB.QueryRow(query).Scan(&task.ID, &task.Name, &task.PomodorosRequired, &task.PomodorosCompleted,
&task.IsComplete, &task.IsActive, &task.CreateAt)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
s.logger.Warn("query active task, when active task not exist")
return nil, fmt.Errorf("can't find active task: %w", err)
}
return nil, fmt.Errorf("can't find acitve task: %w", err)
}
return &task, nil
}

func (s *Storage) IncPomodoroActiveTask() error {
query := `UPDATE tasks
SET
pomodoros_completed = pomodoros_completed + 1,
is_complete = (pomodoros_completed + 1) >= pomodoros_required
WHERE is_active = true;`
_, err := s.DB.Exec(query)
if err != nil {
return fmt.Errorf("can't inc pomodoros in active task: %w", err)
}
return nil
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func initLogger(logFilePath string) (*slog.Logger, error) {

//nolint:exhaustruct // default logger
handler := slog.NewTextHandler(file, &slog.HandlerOptions{
Level: slog.LevelInfo,
Level: slog.LevelDebug,
})

logger := slog.New(handler)
Expand Down
2 changes: 1 addition & 1 deletion page_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func NewPageComponent(name PageName, resize bool, render func() tview.Primitive)
}

func (p *Page) WithBottomPanel() tview.Primitive {
hotKeysPanel := constructBottomPanel()
hotKeysPanel := constructBottomPanel(p.name)
grid := tview.NewGrid().
SetRows(0, 1).
SetColumns(0, 23, 23, 0).
Expand Down
8 changes: 4 additions & 4 deletions pages_statistics_detail.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ func (m *UIManager) NewInsertDetailPage(start, end int) *Page {
func (m *UIManager) renderDetailStatsPage(args ...any) func() tview.Primitive {
start, ok := args[0].(int)
if !ok {
m.logger.Error("can't extract argument for rendering detail stats page",
m.logger.Error("can't extract argument for rendering detail stats prettyPageName",
slog.String("func", "renderDetailStatsPage"))
return nil
}
end, ok := args[1].(int)
if !ok {
m.logger.Error("can't extract argument for rendering detail stats page",
m.logger.Error("can't extract argument for rendering detail stats prettyPageName",
slog.String("func", "renderDetailStatsPage"))
return nil
}
Expand Down Expand Up @@ -250,13 +250,13 @@ func (m *UIManager) totalDuration(pomodoros []*Pomodoro) string {
func (m *UIManager) renderInsertStatsPage(args ...any) func() tview.Primitive {
start, ok := args[0].(int)
if !ok {
m.logger.Error("can't extract argument for rendering insert detail page",
m.logger.Error("can't extract argument for rendering insert detail prettyPageName",
slog.String("func", "renderInsertStatsPage"))
return nil
}
end, ok := args[1].(int)
if !ok {
m.logger.Error("can't extract argument for rendering insert detail page",
m.logger.Error("can't extract argument for rendering insert detail prettyPageName",
slog.String("func", "renderInsertStatsPage"))
return nil
}
Expand Down
12 changes: 6 additions & 6 deletions pages_statistics_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ func (m *UIManager) NewSummaryPage() *Page {
func (m *UIManager) renderSummaryStatsPage(args ...any) func() tview.Primitive {
totalHours, ok := args[0].(float64)
if !ok {
m.logger.Error("can't extract argument for rendering summary stats page",
slog.String("func", "render summary stats page"))
m.logger.Error("can't extract argument for rendering summary stats prettyPageName",
slog.String("func", "render summary stats prettyPageName"))
return nil
}
totalDays, ok := args[1].(int)
if !ok {
m.logger.Error("can't extract argument for rendering summary stats page",
slog.String("func", "render summary stats page"))
m.logger.Error("can't extract argument for rendering summary stats prettyPageName",
slog.String("func", "render summary stats prettyPageName"))
return nil
}
weekdayHours, ok := args[2].([7]int)
if !ok {
m.logger.Error("can't extract argument for rendering summary stats page",
slog.String("func", "render summary stats page"))
m.logger.Error("can't extract argument for rendering summary stats prettyPageName",
slog.String("func", "render summary stats prettyPageName"))
return nil
}

Expand Down
17 changes: 13 additions & 4 deletions pages_switch_transitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const (
activeBreakPage PageName = "Active-Break"
pauseBreakPage PageName = "Stop-Break"

allTasksPage PageName = "All-Tasks-Pages"
allTasksPage PageName = "All-Tasks-Pages"
addNewTaskPage PageName = "Add-New-Task"
deleteTaskPage PageName = "Delete-Task-Page"

detailStatsPage PageName = "Detail-Statistics"
insertStatsPage PageName = "Insert-Statistics"
Expand Down Expand Up @@ -77,9 +79,16 @@ func (m *UIManager) keyboardEvents(event *tcell.EventKey) *tcell.EventKey {
return event
}

// need for reload new pomodoros
if targetPage.name == detailStatsPage {
targetPage = m.NewDetailStats(-1, -1)
// TODO: упростить эту хуйню
switch targetPage.name {
case detailStatsPage:
targetPage = m.NewDetailStats(-1, -1) // need for reload new pomodoros
case summaryStatsPage:
targetPage = m.NewSummaryPage() // need for reload summary time (include after insertion new time pertiod)
case allTasksPage:
targetPage = m.NewTasksPage()
case pauseBreakPage:
targetPage = m.NewPausePage(BreakTimer)
}

m.AddPageAndSwitch(targetPage)
Expand Down
Loading