From 9cc603c56c26b960079efdb7392343b280d6d062 Mon Sep 17 00:00:00 2001 From: talksik Date: Tue, 29 Sep 2026 09:36:52 -0700 Subject: [PATCH] clear out qt app --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 2 +- CMakeLists.txt | 76 ------- CMakeLists.txt.user | 462 ---------------------------------------- README.md | 30 ++- TODO.md | 52 +---- build-universal.sh | 141 ------------ createsessiondialog.cpp | 40 ---- createsessiondialog.h | 28 --- createsessiondialog.ui | 96 --------- endsessiondialog.cpp | 68 ------ endsessiondialog.h | 32 --- endsessiondialog.ui | 221 ------------------- focusoverlay.cpp | 100 --------- focusoverlay.h | 43 ---- focusoverlay.ui | 158 -------------- main.cpp | 16 -- mainwindow.cpp | 264 ----------------------- mainwindow.h | 56 ----- mainwindow.ui | 289 ------------------------- namegenerator.cpp | 5 - namegenerator.h | 8 - run.sh | 16 -- service.cpp | 349 ------------------------------ service.h | 104 --------- sessionitemdelegate.cpp | 139 ------------ sessionitemdelegate.h | 20 -- sessionslistmodel.cpp | 45 ---- sessionslistmodel.h | 24 --- src/main.c | 6 + 30 files changed, 28 insertions(+), 2862 deletions(-) delete mode 100644 .DS_Store delete mode 100644 CMakeLists.txt delete mode 100644 CMakeLists.txt.user delete mode 100755 build-universal.sh delete mode 100644 createsessiondialog.cpp delete mode 100644 createsessiondialog.h delete mode 100644 createsessiondialog.ui delete mode 100644 endsessiondialog.cpp delete mode 100644 endsessiondialog.h delete mode 100644 endsessiondialog.ui delete mode 100644 focusoverlay.cpp delete mode 100644 focusoverlay.h delete mode 100644 focusoverlay.ui delete mode 100644 main.cpp delete mode 100644 mainwindow.cpp delete mode 100644 mainwindow.h delete mode 100644 mainwindow.ui delete mode 100644 namegenerator.cpp delete mode 100644 namegenerator.h delete mode 100755 run.sh delete mode 100644 service.cpp delete mode 100644 service.h delete mode 100644 sessionitemdelegate.cpp delete mode 100644 sessionitemdelegate.h delete mode 100644 sessionslistmodel.cpp delete mode 100644 sessionslistmodel.h create mode 100644 src/main.c diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 6113fee8be489be940daf304188b897ab6ea3d03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKK~BR!474E?Fi|2DsW{_(TTKQ%K{fC^9nDnJGPt^(-UX6z&ngh8~0V;5=z-4R~*8lI|GxPsBi90Gl1^$%++H~t~ zg;%P*b@Fo7YZH6}|1{KkITmllKySs^SS!9csY`Z^e6BbKIvsJR1NkFhy3nY=Zz%8q D=DH_F diff --git a/.gitignore b/.gitignore index 9f9ca98..a8e562e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ build/ -build-universal/ +*~ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 9efc4b1..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(adhd VERSION 1.0.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Set minimum macOS version -# Qt 6.8.6 requires macOS 11.0 (Big Sur) minimum -if(APPLE) - set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum macOS version") -endif() - -find_package(Qt6 REQUIRED COMPONENTS - Core - Gui - Widgets -) - -qt_standard_project_setup() - -qt_add_executable(adhd - main.cpp - mainwindow.cpp - mainwindow.h - service.cpp - service.h - mainwindow.ui - sessionslistmodel.h - sessionslistmodel.cpp - sessionitemdelegate.h - sessionitemdelegate.cpp - createsessiondialog.h - createsessiondialog.cpp - createsessiondialog.ui - focusoverlay.h - focusoverlay.cpp - focusoverlay.ui - endsessiondialog.h - endsessiondialog.cpp - endsessiondialog.ui - namegenerator.h - namegenerator.cpp -) - -# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. -# If you are developing for iOS or macOS you should consider setting an -# explicit, fixed bundle identifier manually though. -set_target_properties(adhd PROPERTIES - # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.adhd - MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} - MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} - MACOSX_BUNDLE TRUE - WIN32_EXECUTABLE $> -) - -target_link_libraries(adhd - PRIVATE - Qt6::Core - Qt6::Gui - Qt6::Widgets -) - -include(GNUInstallDirs) -install(TARGETS adhd - BUNDLE DESTINATION . - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) - -qt_generate_deploy_app_script( - TARGET adhd - OUTPUT_SCRIPT deploy_script - NO_UNSUPPORTED_PLATFORM_ERROR -) -install(SCRIPT ${deploy_script}) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user deleted file mode 100644 index 12de3df..0000000 --- a/CMakeLists.txt.user +++ /dev/null @@ -1,462 +0,0 @@ - - - - - - EnvironmentId - {1354daad-1138-41d2-985c-27357b7ee48a} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - true - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 0 - 80 - true - true - 1 - 0 - false - true - false - 2 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - false - - - 0 - true - - true - true - Builtin.DefaultTidyAndClazy - 5 - true - - - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Qt 6.8.6 for macOS - Qt 6.8.6 for macOS - qt.qt6.686.clang_64_kit - 0 - 0 - 0 - - Debug - 2 - false - - -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_BUILD_TYPE:STRING=Debug --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} - 0 - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Debug - - - - - all - - false - - true - Build - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - Build - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - CMakeProjectManager.CMakeBuildConfiguration - - - Release - 2 - false - - -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_BUILD_TYPE:STRING=Release --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Release - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-RelWithDebInfo - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release with Debug Information - CMakeProjectManager.CMakeBuildConfiguration - - - RelWithDebInfo - 2 - false - - -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} - 0 - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Profile - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - CMakeProjectManager.CMakeBuildConfiguration - - - MinSizeRel - 2 - false - - -DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_BUILD_TYPE:STRING=MinSizeRel --DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-MinSizeRel - - - - - all - - false - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - false - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Minimum Size Release - CMakeProjectManager.CMakeBuildConfiguration - - 5 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - - - - - - - - false - - true - ApplicationManagerPlugin.Deploy.CMakePackageStep - - - install-package --acknowledge - true - Install Application Manager package - ApplicationManagerPlugin.Deploy.InstallPackageStep - - - - - - - - 2 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ApplicationManagerPlugin.Deploy.Configuration - - 2 - - true - true - 0 - true - - 2 - - false - -e cpu-cycles --call-graph dwarf,4096 -F 250 - adhd - CMakeProjectManager.CMakeRunConfiguration. - adhd - false - true - true - true - /Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Debug/adhd.app/Contents/MacOS - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/README.md b/README.md index 83df2ef..e4f74c8 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,29 @@ # Flowy.adhd -A macOS focus app that helps you stay on track by setting one intention per session. +We live in a noisy world. Unless you turn off your WiFi, millions of companies bid for your attention as you try to perform even the simplest tasks. + +This tool is a free, open-source application to help you stay on track. You set an intention before you work, and an overlay will remind you of your intention every x minutes. ![app](demo/app.png) ![desktop](demo/desktop.png) +## Install +At the moment, you must build and install the application yourself. There are minimum dependencies, so you essentially just need a C compiler. + ## How it works 1. Set your intention when you sit down at your computer -2. A persistent overlay keeps your focus visible while you work -3. End the session and mark it as a win or loss -4. Build a log of your sessions over time +2. A persistent overlay reminds you of your intention +3. Set whether today was a win (focused) or loss (distracted), and view your daily activity in a nice graph ## Philosophy -Stay aware of your intentions to avoid distractions. No todo manager needed—just focus on winning each session, one thing at a time. +In a world of fancy todo managers, for anyone with adhd, doing one thing at a time is the key. Win one intention at a time instead of planning, prioritizing, and juggling 100s of things. ## Features -- **No sign in required** - Start using immediately -- **Privacy first** - Sessions stored locally as markdown files +- **No sign in required** +- **Slick overlay to show current intention** +- **Lightweight** - Written in C with few dependencies, nothing bloated like electron +- **Privacy first** - No telemetry, works offline - **Session history** - Review your past wins and losses - -## Download - -Get the latest version from [releases](https://github.com/flowy-live/adhd/releases). - -## Roadmap - -- View past session notes -- Win/loss statistics visualizer -- Windows and Linux support diff --git a/TODO.md b/TODO.md index a442b66..4db2c59 100644 --- a/TODO.md +++ b/TODO.md @@ -1,45 +1,9 @@ -## Todo -- [ ] tab widget: one for settings, one for sessions, one for active session editing -- [ ] active session view would show timer, pause, end, and edit session details -- [ ] create new session button -- [ ] click on a session to set as active -- [ ] create separate overlay that the main app can listen to and notify of active session changes - -## Ideas -- Show me all sessions and the current session -- Sum up how many sessions I won/lost -- A session can simply be described by simple paragraph of what you'll do, maybe markdown -- Less rigidity in the sense of typing out thoughts and session goals...less due dates. Capture first, do later. -- Later: allow notes within a session, jot things down, all live in the same folder - - It's like a todo.md -- Every session is based on week # - year - session x -- Every session is an individual document that lives on disk -- See which week of the year that I'm in -- See progress bar of how much of the year is done or percentage -- Show stats on how many sessions total I've won/lost -- Display a separate overlay window that shows me my active working item in center bottom in a pill -- Can commit to github for "sync" and even include an input url to auto-upload the data directory to github - -- overlay can show the first line of the session doc (or separate input) -- review of session can be: `Win`, `Neutral`, or `Loss` - -## Flow -- select location to save all your session data in markdown files -- data in the app parses the markdown file and uses it as the database, including the frontmatter - -1. At the start of the day/session, set an intention by creating a session -2. Enter the top things to do this session in plain english (list or paragraph in markdown) -3. Click start session, and clock runs. Can pause, or stop. -4. When done for the session, select "Close session"...it will ask you to grade the session -5. View previous sessions in a list - -## marketing -- local-only -- access files and metadata -- simple video demo OR flowy research-site page that has simple visuals - -## Launch -- [ ] install via brew -- [ ] open source github -- [ ] hackernews "for developers with adhd"...purist site +- [ ] create a slick overlay mode +- [ ] create a simple window mode for adjusting the current intention +- [ ] remind me by flashing every x minutes (gradient orange) +- [ ] win / loss graph: set for each day with bit value in sqlite db +- [ ] adjust reminder interval +- [ ] install via homebrew +- [ ] create windows download +- [ ] launch on hackernews "for developers with adhd"...create an html page as well on flowylabs site diff --git a/build-universal.sh b/build-universal.sh deleted file mode 100755 index 9246a3f..0000000 --- a/build-universal.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash - -# Build script for universal macOS bundle (arm64 + x86_64) - -set -e # Exit on error - -echo "=========================================" -echo "Building Universal macOS Bundle for adhd" -echo "=========================================" - -# Configuration -APP_NAME="adhd" -BUILD_DIR="build-universal" -BUILD_TYPE="Release" -ARCHITECTURES="arm64;x86_64" -QT_PATH="$HOME/Qt/6.8.6/macos" -APPLE_DEVELOPMENT_IDENTITY="Developer ID Application: Arjun Patel (RK9WWM4Q99)" - -# Clean previous build (optional - comment out to keep incremental builds) -# rm -rf "$BUILD_DIR" - -# Configure CMake -echo "" -echo "Configuring CMake for universal binary..." -echo "Minimum macOS version: 11.0 (Big Sur)" -cmake -B "$BUILD_DIR" \ - -DCMAKE_OSX_ARCHITECTURES="$ARCHITECTURES" \ - -DCMAKE_OSX_DEPLOYMENT_TARGET="11.0" \ - -DCMAKE_PREFIX_PATH="$QT_PATH" \ - -DCMAKE_BUILD_TYPE="$BUILD_TYPE" - -# Build -echo "" -echo "Building..." -cmake --build "$BUILD_DIR" --config "$BUILD_TYPE" -j$(sysctl -n hw.ncpu) - -# Verify the binary is universal -echo "" -echo "Verifying binary architectures..." -if [ -f "$BUILD_DIR/$APP_NAME.app/Contents/MacOS/$APP_NAME" ]; then - lipo -info "$BUILD_DIR/$APP_NAME.app/Contents/MacOS/$APP_NAME" - echo "✓ Binary is universal" -else - echo "✗ Error: Binary not found at expected location" - exit 1 -fi - -# Deploy Qt dependencies -echo "" -echo "Deploying Qt dependencies..." -$QT_PATH/bin/macdeployqt "$BUILD_DIR/$APP_NAME.app" -always-overwrite -verbose=1 -echo "✓ Qt dependencies deployed" - -# Code signing -echo "" -echo "=========================================" -echo "Listing identities for code-signing" -echo "=========================================" -security find-identity -v -p codesigning - -echo "" -echo "=========================================" -echo "Code signing .app bundle" -echo "=========================================" -echo "Using: $APPLE_DEVELOPMENT_IDENTITY" - -cd "$BUILD_DIR" - -codesign --deep --force --timestamp --verify --verbose=1 \ - --sign "$APPLE_DEVELOPMENT_IDENTITY" \ - --options runtime "$APP_NAME.app" - -echo "" -echo "Verifying code signature..." -codesign --verify --deep --strict --verbose=1 "./$APP_NAME.app" -echo "✓ Code signing complete" - -# Create DMG -echo "" -echo "=========================================" -echo "Creating DMG" -echo "=========================================" -echo "NOTE: Install create-dmg if needed: https://github.com/sindresorhus/create-dmg" - -if ! command -v create-dmg &> /dev/null; then - echo "⚠ Warning: create-dmg not found. Install with: brew install create-dmg" - echo "Skipping DMG creation, notarization, and stapling." - cd .. - echo "" - echo "=========================================" - echo "Build completed (without DMG/notarization)" - echo "App bundle location: $BUILD_DIR/$APP_NAME.app" - echo "=========================================" - exit 0 -fi - -create-dmg "$APP_NAME.app" --identity="$APPLE_DEVELOPMENT_IDENTITY" --dmg-title="$APP_NAME" -# WORKAROUND: https://github.com/sindresorhus/create-dmg/issues/52 -mv *.dmg "$APP_NAME.dmg" 2>/dev/null || true - -echo "✓ DMG created: $APP_NAME.dmg" - -# Notarization -echo "" -echo "=========================================" -echo "Starting Notarization" -echo "=========================================" -echo "NOTE: Make sure you've run 'xcrun notarytool store-credentials' first" - -xcrun notarytool submit "$APP_NAME.dmg" \ - --keychain-profile "default" \ - --wait \ - --timeout "10m" - -echo "" -echo "=========================================" -echo "Stapling notarization ticket" -echo "=========================================" -xcrun stapler staple -v "$APP_NAME.dmg" -echo "✓ Notarization complete" - -# Optional: Create zip -echo "" -read -p "Create zip file? (y/N): " CREATE_ZIP -if [[ "$CREATE_ZIP" == "y" || "$CREATE_ZIP" == "Y" ]]; then - ZIP_NAME="$APP_NAME-universal.zip" - zip -9 "$ZIP_NAME" "$APP_NAME.dmg" - echo "✓ Created: $ZIP_NAME" -fi - -cd .. - -echo "" -echo "=========================================" -echo "Build completed successfully!" -echo "=========================================" -echo "App bundle: $BUILD_DIR/$APP_NAME.app" -echo "DMG: $BUILD_DIR/$APP_NAME.dmg" -echo "" -echo "To test: open $BUILD_DIR/$APP_NAME.dmg" -echo "=========================================" diff --git a/createsessiondialog.cpp b/createsessiondialog.cpp deleted file mode 100644 index db05854..0000000 --- a/createsessiondialog.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "createsessiondialog.h" -#include "ui_createsessiondialog.h" -#include - -CreateSessionDialog::CreateSessionDialog(QWidget *parent) - : QDialog(parent), - ui(new Ui::CreateSessionDialog) -{ - ui->setupUi(this); - - setWindowTitle("Create New Session"); - - // Disable OK button initially - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - - // Connect oneliner field to validation - connect(ui->onelinerEdit, &QLineEdit::textChanged, - this, &CreateSessionDialog::onOnelinerChanged); -} - -CreateSessionDialog::~CreateSessionDialog() -{ - delete ui; -} - -QString CreateSessionDialog::getOneliner() const -{ - return ui->onelinerEdit->text().trimmed(); -} - -QString CreateSessionDialog::getContent() const -{ - return ui->contentEdit->toPlainText().trimmed(); -} - -void CreateSessionDialog::onOnelinerChanged(const QString &text) -{ - bool isValid = !text.trimmed().isEmpty(); - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid); -} diff --git a/createsessiondialog.h b/createsessiondialog.h deleted file mode 100644 index fe07bf8..0000000 --- a/createsessiondialog.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CREATESESSIONDIALOG_H -#define CREATESESSIONDIALOG_H - -#include - -namespace Ui { -class CreateSessionDialog; -} - -class CreateSessionDialog : public QDialog -{ - Q_OBJECT - -public: - explicit CreateSessionDialog(QWidget *parent = nullptr); - ~CreateSessionDialog(); - - QString getOneliner() const; - QString getContent() const; - -private slots: - void onOnelinerChanged(const QString &text); - -private: - Ui::CreateSessionDialog *ui; -}; - -#endif // CREATESESSIONDIALOG_H diff --git a/createsessiondialog.ui b/createsessiondialog.ui deleted file mode 100644 index dea1ee9..0000000 --- a/createsessiondialog.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - CreateSessionDialog - - - - 0 - 0 - 500 - 300 - - - - Create Session - - - - - - - - Oneliner: - - - - - - - What will you focus on? - - - - - - - Initial Content: - - - - - - - Optional: Add initial notes or context... - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - CreateSessionDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - CreateSessionDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/endsessiondialog.cpp b/endsessiondialog.cpp deleted file mode 100644 index 8efc133..0000000 --- a/endsessiondialog.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "endsessiondialog.h" -#include "ui_endsessiondialog.h" - -EndSessionDialog::EndSessionDialog(const QString &oneliner, int elapsedMs, QWidget *parent) - : QDialog(parent), - ui(new Ui::EndSessionDialog), - m_selectedResult(Session::UNSPECIFIED) -{ - ui->setupUi(this); - - setWindowTitle("End Session"); - - // Set oneliner and elapsed time - ui->onelinerLabel->setText(oneliner); - - int seconds = elapsedMs / 1000; - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - int secs = seconds % 60; - - QString timeStr = QString("%1:%2:%3") - .arg(hours, 2, 10, QChar('0')) - .arg(minutes, 2, 10, QChar('0')) - .arg(secs, 2, 10, QChar('0')); - - ui->elapsedLabel->setText("Duration: " + timeStr); - - // Connect buttons - connect(ui->winButton, &QPushButton::clicked, - this, &EndSessionDialog::onWinClicked); - connect(ui->lossButton, &QPushButton::clicked, - this, &EndSessionDialog::onLossClicked); - connect(ui->neutralButton, &QPushButton::clicked, - this, &EndSessionDialog::onNeutralClicked); -} - -EndSessionDialog::~EndSessionDialog() -{ - delete ui; -} - -Session::Result EndSessionDialog::getResult() const -{ - return m_selectedResult; -} - -QString EndSessionDialog::getAdditionalNotes() const -{ - return ui->notesEdit->toPlainText().trimmed(); -} - -void EndSessionDialog::onWinClicked() -{ - m_selectedResult = Session::WIN; - accept(); -} - -void EndSessionDialog::onLossClicked() -{ - m_selectedResult = Session::LOSS; - accept(); -} - -void EndSessionDialog::onNeutralClicked() -{ - m_selectedResult = Session::NEUTRAL; - accept(); -} diff --git a/endsessiondialog.h b/endsessiondialog.h deleted file mode 100644 index 0f55c5e..0000000 --- a/endsessiondialog.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef ENDSESSIONDIALOG_H -#define ENDSESSIONDIALOG_H - -#include -#include "service.h" - -namespace Ui { -class EndSessionDialog; -} - -class EndSessionDialog : public QDialog -{ - Q_OBJECT - -public: - explicit EndSessionDialog(const QString &oneliner, int elapsedMs, QWidget *parent = nullptr); - ~EndSessionDialog(); - - Session::Result getResult() const; - QString getAdditionalNotes() const; - -private slots: - void onWinClicked(); - void onLossClicked(); - void onNeutralClicked(); - -private: - Ui::EndSessionDialog *ui; - Session::Result m_selectedResult; -}; - -#endif // ENDSESSIONDIALOG_H diff --git a/endsessiondialog.ui b/endsessiondialog.ui deleted file mode 100644 index bd84603..0000000 --- a/endsessiondialog.ui +++ /dev/null @@ -1,221 +0,0 @@ - - - EndSessionDialog - - - - 0 - 0 - 500 - 400 - - - - End Session - - - - - - - 16 - 75 - true - - - - How did your session go? - - - Qt::AlignCenter - - - - - - - - 14 - - - - Session Oneliner - - - Qt::AlignCenter - - - true - - - - - - - Duration: 00:00:00 - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - - - - 0 - 60 - - - - - 14 - 75 - true - - - - QPushButton { - background-color: #2ecc71; - color: white; - border-radius: 5px; -} -QPushButton:hover { - background-color: #27ae60; -} -QPushButton:pressed { - background-color: #229954; -} - - - WIN - - - - - - - - 0 - 60 - - - - - 14 - 75 - true - - - - QPushButton { - background-color: #e74c3c; - color: white; - border-radius: 5px; -} -QPushButton:hover { - background-color: #c0392b; -} -QPushButton:pressed { - background-color: #a93226; -} - - - LOSS - - - - - - - - 0 - 60 - - - - - 14 - 75 - true - - - - QPushButton { - background-color: #95a5a6; - color: white; - border-radius: 5px; -} -QPushButton:hover { - background-color: #7f8c8d; -} -QPushButton:pressed { - background-color: #707b7c; -} - - - NEUTRAL - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Optional: Add final notes - - - - - - - - 16777215 - 100 - - - - Any final thoughts or notes about this session... - - - - - - - - diff --git a/focusoverlay.cpp b/focusoverlay.cpp deleted file mode 100644 index 4527f9e..0000000 --- a/focusoverlay.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "focusoverlay.h" -#include "ui_focusoverlay.h" -#include -#include -#include - -FocusOverlay::FocusOverlay(QWidget *parent) - : QWidget(parent), - ui(new Ui::FocusOverlay), - m_dragging(false) -{ - ui->setupUi(this); - - // Set window flags for always-on-top frameless window - // Use Qt::Window instead of Qt::Tool so it stays visible when app loses focus - setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); - setAttribute(Qt::WA_TranslucentBackground); - setAttribute(Qt::WA_ShowWithoutActivating); // Don't steal focus when showing - - // Connect buttons - connect(ui->resetButton, &QPushButton::clicked, - this, &FocusOverlay::onResetButtonClicked); - connect(ui->endButton, &QPushButton::clicked, - this, &FocusOverlay::onEndButtonClicked); - - // Position window - positionAtBottomCenter(); -} - -FocusOverlay::~FocusOverlay() -{ - delete ui; -} - -void FocusOverlay::setOneliner(const QString &oneliner) -{ - ui->onelinerLabel->setText(oneliner); -} - -void FocusOverlay::setElapsedTime(int elapsedMs) -{ - int seconds = elapsedMs / 1000; - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - int secs = seconds % 60; - - QString timeStr = QString("%1:%2:%3") - .arg(hours, 2, 10, QChar('0')) - .arg(minutes, 2, 10, QChar('0')) - .arg(secs, 2, 10, QChar('0')); - - ui->elapsedLabel->setText("Elapsed: " + timeStr); -} - -void FocusOverlay::onResetButtonClicked() -{ - emit resetClicked(); -} - -void FocusOverlay::onEndButtonClicked() -{ - emit endSessionClicked(); -} - -void FocusOverlay::positionAtBottomCenter() -{ - QScreen *screen = QGuiApplication::primaryScreen(); - if (!screen) return; - - QRect screenGeometry = screen->geometry(); - int x = (screenGeometry.width() - width()) / 2; - int y = screenGeometry.height() - height(); - - move(x, y); -} - -void FocusOverlay::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - m_dragging = true; - m_dragStartPosition = event->globalPosition().toPoint() - frameGeometry().topLeft(); - event->accept(); - } -} - -void FocusOverlay::mouseMoveEvent(QMouseEvent *event) -{ - if (m_dragging && (event->buttons() & Qt::LeftButton)) { - move(event->globalPosition().toPoint() - m_dragStartPosition); - event->accept(); - } -} - -void FocusOverlay::mouseReleaseEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - m_dragging = false; - event->accept(); - } -} diff --git a/focusoverlay.h b/focusoverlay.h deleted file mode 100644 index ab02928..0000000 --- a/focusoverlay.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef FOCUSOVERLAY_H -#define FOCUSOVERLAY_H - -#include - -namespace Ui { -class FocusOverlay; -} - -class FocusOverlay : public QWidget -{ - Q_OBJECT - -public: - explicit FocusOverlay(QWidget *parent = nullptr); - ~FocusOverlay(); - - void setOneliner(const QString &oneliner); - void setElapsedTime(int elapsedMs); - -signals: - void resetClicked(); - void endSessionClicked(); - -private slots: - void onResetButtonClicked(); - void onEndButtonClicked(); - -protected: - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - -private: - Ui::FocusOverlay *ui; - void positionAtBottomCenter(); - - // For dragging - bool m_dragging; - QPoint m_dragStartPosition; -}; - -#endif // FOCUSOVERLAY_H diff --git a/focusoverlay.ui b/focusoverlay.ui deleted file mode 100644 index 7e3d7ce..0000000 --- a/focusoverlay.ui +++ /dev/null @@ -1,158 +0,0 @@ - - - FocusOverlay - - - - 0 - 0 - 350 - 102 - - - - - 0 - 0 - - - - - 350 - 80 - - - - - 350 - 102 - - - - Focus Session - - - QWidget#FocusOverlay { - background-color: rgba(50, 50, 50, 200); - border-radius: 10px; - border: 2px solid rgba(100, 100, 100, 255); -} - -QLabel { - color: white; -} - -QPushButton { - background-color: rgba(80, 80, 80, 255); - color: white; - border: 1px solid rgba(120, 120, 120, 255); - border-radius: 5px; - padding: 4px 8px; - min-width: 50px; -} - -QPushButton:hover { - background-color: rgba(100, 100, 100, 255); -} - -QPushButton:pressed { - background-color: rgba(60, 60, 60, 255); -} - - - - 8 - - - 10 - - - 8 - - - 10 - - - 8 - - - - - - 2 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 12 - true - - - - Session Oneliner - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - - - - - - - - 10 - - - - Elapsed: 00:00:00 - - - Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - - - - - - - - - - - - Reset - - - true - - - false - - - - - - - End Session - - - - - - - - - - diff --git a/main.cpp b/main.cpp deleted file mode 100644 index df55bee..0000000 --- a/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include "mainwindow.h" -#include "service.h" - -int main(int argc, char *argv[]) { - std::cout << "Starting adhd program" << std::endl; - - QApplication a(argc, argv); - a.setStyle("fusion"); - - MainWindow w; - w.show(); - - return a.exec(); -} diff --git a/mainwindow.cpp b/mainwindow.cpp deleted file mode 100644 index 924343f..0000000 --- a/mainwindow.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include "mainwindow.h" -#include "service.h" -#include "sessionslistmodel.h" -#include "sessionitemdelegate.h" -#include "createsessiondialog.h" -#include "focusoverlay.h" -#include "endsessiondialog.h" -#include -#include -#include -#include -#include -#include -#include "ui_mainwindow.h" - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), - m_service(new Service(this)), - m_focusOverlay(nullptr), - m_updatingActiveFields(false) -{ - ui = new Ui::MainWindow; - ui->setupUi(this); - setWindowTitle("flowy.adhd"); - - m_listModel = new SessionsListModel(m_service, this); - ui->listView->setModel(m_listModel); - ui->listView->setItemDelegate(new SessionItemDelegate(this)); - - // Connect Service signals - connect(m_service, &Service::activeSessionChanged, - this, &MainWindow::onActiveSessionChanged); - connect(m_service, &Service::sessionTimerTicked, - this, &MainWindow::onSessionTimerTicked); - - // Connect Active tab field changes - connect(ui->oneLineEdit, &QLineEdit::editingFinished, - this, &MainWindow::onActiveOnelinerChanged); - - // Debounce content text changes - QTimer *contentDebounce = new QTimer(this); - contentDebounce->setSingleShot(true); - contentDebounce->setInterval(500); - connect(ui->contentTextEdit, &QTextEdit::textChanged, - [contentDebounce]() { contentDebounce->start(); }); - connect(contentDebounce, &QTimer::timeout, - this, &MainWindow::onActiveContentChanged); - - // Set initial state: no active session - ui->activeStackedWidget->setCurrentIndex(0); - - // Load saved vault directory from settings - QSettings settings("flowy", "adhd"); - QString savedVaultPath = settings.value("vaultDirectory").toString(); - if (!savedVaultPath.isEmpty() && QDir(savedVaultPath).exists()) { - m_service->setVaultDirectory(savedVaultPath); - ui->vaultLabel->setText(savedVaultPath); - // Switch to Sessions tab if we have a valid vault - ui->tabWidget->setCurrentIndex(1); - } -} - -MainWindow::~MainWindow() {} - -void MainWindow::on_selectVaultButton_clicked() -{ - QString dir = QFileDialog::getExistingDirectory(this, - "Select Directory", - QDir::homePath(), - QFileDialog::ShowDirsOnly); - if (!dir.isEmpty()) { - m_service->setVaultDirectory(dir); - ui->tabWidget->setCurrentIndex(1); - ui->vaultLabel->setText(dir); - - // Save to settings for next launch - QSettings settings("flowy", "adhd"); - settings.setValue("vaultDirectory", dir); - } -} - -void MainWindow::on_newSessionButton_clicked() -{ - CreateSessionDialog dialog(this); - if (dialog.exec() == QDialog::Accepted) { - QString oneliner = dialog.getOneliner(); - QString content = dialog.getContent(); - - Session session = m_service->createSession(oneliner, content); - m_service->startSession(session); - } -} - -void MainWindow::on_startSessionButton_clicked() -{ - QModelIndex index = ui->listView->currentIndex(); - if (!index.isValid()) { - QMessageBox::warning(this, "No Selection", "Please select a session to start."); - return; - } - - Session session = m_listModel->getSessionByIndex(index); - m_service->startSession(session); -} - -void MainWindow::on_endSessionButton_clicked() -{ - auto activeSession = m_service->activeSession(); - if (!activeSession) { - return; - } - - EndSessionDialog dialog(activeSession->oneliner, m_service->getElapsedMs(), this); - if (dialog.exec() == QDialog::Accepted) { - Session::Result result = dialog.getResult(); - QString notes = dialog.getAdditionalNotes(); - - // Append notes to content if provided - if (!notes.isEmpty()) { - Session updated = *activeSession; - if (!updated.content.isEmpty()) { - updated.content += "\n\n"; - } - updated.content += notes; - m_service->updateSession(updated); - } - - m_service->endSession(result); - } -} - -void MainWindow::onActiveSessionChanged() -{ - auto activeSession = m_service->activeSession(); - - if (activeSession) { - // Session started - ui->activeStackedWidget->setCurrentIndex(1); - updateActiveTab(); - - // Create and show overlay - if (!m_focusOverlay) { - m_focusOverlay = new FocusOverlay(); - connect(m_focusOverlay, &FocusOverlay::resetClicked, - this, &MainWindow::onOverlayResetClicked); - connect(m_focusOverlay, &FocusOverlay::endSessionClicked, - this, &MainWindow::onOverlayEndSessionClicked); - } - - m_focusOverlay->setOneliner(activeSession->oneliner); - m_focusOverlay->setElapsedTime(0); - m_focusOverlay->show(); - - // Switch to Active tab - ui->tabWidget->setCurrentIndex(2); - } else { - // Session ended - ui->activeStackedWidget->setCurrentIndex(0); - - // Hide and delete overlay - if (m_focusOverlay) { - m_focusOverlay->hide(); - m_focusOverlay->deleteLater(); - m_focusOverlay = nullptr; - } - } -} - -void MainWindow::onSessionTimerTicked(int elapsedMs) -{ - ui->elapsedLabel->setText(formatDuration(elapsedMs)); - - if (m_focusOverlay) { - m_focusOverlay->setElapsedTime(elapsedMs); - } -} - -void MainWindow::onActiveOnelinerChanged() -{ - if (m_updatingActiveFields) return; - - auto activeSession = m_service->activeSession(); - if (!activeSession) return; - - Session updated = *activeSession; - updated.oneliner = ui->oneLineEdit->text(); - updated.lastModifiedAt = QDateTime::currentDateTime(); - - m_updatingActiveFields = true; - m_service->updateSession(updated); - m_service->updateActiveSession(updated); - - // Update overlay - if (m_focusOverlay) { - m_focusOverlay->setOneliner(updated.oneliner); - } - - m_updatingActiveFields = false; -} - -void MainWindow::onActiveContentChanged() -{ - if (m_updatingActiveFields) return; - - auto activeSession = m_service->activeSession(); - if (!activeSession) return; - - Session updated = *activeSession; - updated.content = ui->contentTextEdit->toPlainText(); - updated.lastModifiedAt = QDateTime::currentDateTime(); - - m_updatingActiveFields = true; - m_service->updateSession(updated); - m_service->updateActiveSession(updated); - m_updatingActiveFields = false; -} - -void MainWindow::onOverlayResetClicked() -{ - QMessageBox::StandardButton reply = QMessageBox::question( - this, - "Reset Timer", - "Are you sure you want to reset the timer to 00:00:00?", - QMessageBox::Yes | QMessageBox::No); - - if (reply == QMessageBox::Yes) { - m_service->resetSessionTimer(); - } -} - -void MainWindow::onOverlayEndSessionClicked() -{ - on_endSessionButton_clicked(); -} - -void MainWindow::updateActiveTab() -{ - auto activeSession = m_service->activeSession(); - if (!activeSession) return; - - m_updatingActiveFields = true; - - ui->oneLineEdit->setText(activeSession->oneliner); - ui->elapsedLabel->setText(formatDuration(m_service->getElapsedMs())); - - ui->createdLabel->setText(activeSession->createdAt.toString("yyyy-MM-dd hh:mm:ss")); - ui->modifiedLabel->setText(activeSession->lastModifiedAt.toString("yyyy-MM-dd hh:mm:ss")); - ui->contentTextEdit->setPlainText(activeSession->content); - - m_updatingActiveFields = false; -} - -QString MainWindow::formatDuration(int ms) const -{ - int seconds = ms / 1000; - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - int secs = seconds % 60; - - return QString("%1:%2:%3") - .arg(hours, 2, 10, QChar('0')) - .arg(minutes, 2, 10, QChar('0')) - .arg(secs, 2, 10, QChar('0')); -} diff --git a/mainwindow.h b/mainwindow.h deleted file mode 100644 index 9030128..0000000 --- a/mainwindow.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -class Service; -class SessionsListModel; -class FocusOverlay; -class QTimer; - -QT_BEGIN_NAMESPACE -QT_END_NAMESPACE - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow { - Q_OBJECT - -public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - -private slots: - void on_selectVaultButton_clicked(); - void on_newSessionButton_clicked(); - void on_startSessionButton_clicked(); - void on_endSessionButton_clicked(); - - // Service signal handlers - void onActiveSessionChanged(); - void onSessionTimerTicked(int elapsedMs); - - // Active tab field editing - void onActiveOnelinerChanged(); - void onActiveContentChanged(); - - // Overlay handlers - void onOverlayResetClicked(); - void onOverlayEndSessionClicked(); - -private: - Ui::MainWindow *ui; - Service *m_service; - SessionsListModel *m_listModel; - FocusOverlay *m_focusOverlay; - - bool m_updatingActiveFields; - - void updateActiveTab(); - QString formatDuration(int ms) const; -}; - -#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui deleted file mode 100644 index e2378cb..0000000 --- a/mainwindow.ui +++ /dev/null @@ -1,289 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 400 - 600 - - - - MainWindow - - - - - - - 0 - - - - Settings - - - - - 80 - 210 - 221 - 16 - - - - Select a folder - - - Qt::AlignmentFlag::AlignCenter - - - - - - 130 - 240 - 121 - 32 - - - - Select vault - - - - - - true - - - - - - Sessions - - - - - - - - New Session - - - - - - - Start Selected - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Active - - - - - - 0 - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - No session running. Start a session to begin. - - - Qt::AlignmentFlag::AlignCenter - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - - - - - true - - - - - 0 - 0 - 190 - 244 - - - - - - - - - Oneliner: - - - - - - - - - - Elapsed Time: - - - - - - - 00:00:00 - - - - - - - Created: - - - - - - - - - - - - - - - Modified: - - - - - - - - - - - - - - - Content: - - - - - - - Add notes, context, or anything related to this session... - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - End Session - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 400 - 30 - - - - - - - - diff --git a/namegenerator.cpp b/namegenerator.cpp deleted file mode 100644 index 93886d3..0000000 --- a/namegenerator.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "namegenerator.h" - -QString generate() { - return QString("generated-name-placeholder"); -} diff --git a/namegenerator.h b/namegenerator.h deleted file mode 100644 index 4aaa210..0000000 --- a/namegenerator.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NAMEGENERATOR_H -#define NAMEGENERATOR_H - -#include - -QString generate(); - -#endif //NAMEGENERATOR_H diff --git a/run.sh b/run.sh deleted file mode 100755 index df21b0b..0000000 --- a/run.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -e - -BUILD_DIR=build - -if [ ! -d "$BUILD_DIR" ]; then - cmake -B$BUILD_DIR -S. -GNinja \ - -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_CXX_FLAGS="-Wall -Wextra" \ - -DCMAKE_PREFIX_PATH="$HOME/Qt/6.8.6/macos" \ - -DCMAKE_COLOR_DIAGNOSTICS=ON \ - -DCMAKE_CXX_FLAGS_INIT="-DQT_QML_DEBUG" -fi - -cmake --build $BUILD_DIR --target all - -$BUILD_DIR/adhd.app/Contents/MacOS/adhd diff --git a/service.cpp b/service.cpp deleted file mode 100644 index 3dc364e..0000000 --- a/service.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "service.h" -#include -#include -#include -#include - -bool Session::isComplete() const { - return result != UNSPECIFIED; -} - -Service::Service(QObject *parent) - : QObject(parent), - m_tickTimer(new QTimer(this)) -{ - m_tickTimer->setInterval(1000); // Fire every second - connect(m_tickTimer, &QTimer::timeout, this, &Service::onTickTimerFired); -} - -Service::~Service() {} - -QString Service::vaultDirectory() const { - return m_vaultDirectory; -} - -int Service::sessionCount() const { - return m_sessions.size(); -} - -int Service::completedSessionCount() const { - int count = 0; - for (const Session &session : m_sessions) { - if (session.isComplete()) { - count++; - } - } - return count; -} - -int Service::totalWins() const { - int count = 0; - for (const Session &session : m_sessions) { - if (session.result == Session::WIN) { - count++; - } - } - return count; -} - -int Service::totalLosses() const { - int count = 0; - for (const Session &session : m_sessions) { - if (session.result == Session::LOSS) { - count++; - } - } - return count; -} - -int Service::totalNeutrals() const { - int count = 0; - for (const Session &session : m_sessions) { - if (session.result == Session::NEUTRAL) { - count++; - } - } - return count; -} - -QList Service::sessions() const { - return m_sessions; -} - -void Service::setVaultDirectory(const QString &path) { - m_sessions.clear(); - - qDebug() << "Setting vault directory to: " << path; - - QDir dir = QDir(path); - if (!dir.exists()) { - qWarning() << "Vault directory does not exist"; - return; - } - - m_vaultDirectory = path; - - dir.setFilter(QDir::Files); - dir.setSorting(QDir::Time); - - QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) { - QFileInfo fileInfo = list.at(i); - - if (fileInfo.completeSuffix() != QStringLiteral("md")) { - qWarning() << "Skipping invalid file format: " << fileInfo.completeSuffix(); - continue; - } - - qDebug() << "Parsing file: " << fileInfo.absoluteFilePath(); - std::optional session = parseFile(fileInfo); - if (session) { - m_sessions.append(*session); - } else { - qWarning() << "Failed to parse session file: " << fileInfo.absoluteFilePath(); - } - } - - emit sessionsChanged(); -} - -Session Service::createSession(const QString &oneliner, const QString &content) { - assert(!m_vaultDirectory.isEmpty() && "Vault directory must be set before creating sessions"); - - QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); - - Session session = {}; - session.id = uuid; - session.oneliner = oneliner; - session.durationMs = 0; - session.content = content; - session.result = Session::UNSPECIFIED; - session.createdAt = QDateTime::currentDateTime(); - session.lastModifiedAt = QDateTime::currentDateTime(); - - overwriteSessionFile(session); - - m_sessions.prepend(session); - emit sessionsChanged(); - - return session; -} - -void Service::updateSession(const Session &session) { - overwriteSessionFile(session); - for (int i = 0; i < m_sessions.size(); ++i) { - if (m_sessions[i].id == session.id) { - m_sessions[i] = session; - break; - } - } - emit sessionsChanged(); -} - -void Service::deleteSession(const QString &sessionId) { - QDir dir = QDir(m_vaultDirectory); - QString filePath = dir.filePath(sessionId + ".md"); - QFile file = QFile(filePath); - if (!file.remove()) { - qWarning() << "Failed to delete session file: " << filePath; - return; - } - - for (int i = 0; i < m_sessions.size(); ++i) { - if (m_sessions[i].id == sessionId) { - m_sessions.removeAt(i); - break; - } - } - emit sessionsChanged(); -} - -std::optional Service::parseFile(const QFileInfo &fileInfo) { - QString path = fileInfo.absoluteFilePath(); - QFile file = QFile(path); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return std::nullopt; - } - - Session session = {}; - session.id = fileInfo.baseName(); // Get filename without extension - session.content = ""; - session.oneliner = ""; - session.durationMs = 0; - session.result = Session::UNSPECIFIED; - session.createdAt = fileInfo.birthTime(); - session.lastModifiedAt = fileInfo.lastModified(); - - QTextStream in(&file); - int separatorCounts = 0; - while (!in.atEnd()) { - QString line = in.readLine(); - // qDebug() << "Reading line: " << line; - - if (separatorCounts >= 2) { - session.content += line + '\n'; - continue; - } - - switch (line[0].toLatin1()) { - case '-': - separatorCounts++; - continue; - break; - default: - break; - } - // parse each key value pair - QStringList parts = line.split(':'); - if (parts.size() != 2) { - continue; - } - QString key = parts[0].trimmed(); - QString value = parts[1].trimmed(); - if (key == "Oneliner") { - session.oneliner = value; - continue; - } else if (key == "DurationMs") { - session.durationMs = value.toInt(); - continue; - } else if (key == "Result") { - session.result = parseResult(value); - continue; - } - } - - qDebug() << "Parsed oneliner: " << session.oneliner; - qDebug() << "Parsed durationMs: " << session.durationMs; - qDebug() << "Parsed result: " << static_cast(session.result); - qDebug() << "Parsed content: " << session.content; - qDebug() << "Created at: " << session.createdAt; - qDebug() << "Last modified at: " << session.lastModifiedAt; - - file.close(); - - return session; -} - -Session::Result Service::parseResult(const QString &resultStr) { - if (resultStr == "Win") { - return Session::WIN; - } else if (resultStr == "Loss") { - return Session::LOSS; - } else if (resultStr == "Neutral") { - return Session::NEUTRAL; - } else { - return Session::UNSPECIFIED; - } -} - -void Service::overwriteSessionFile(const Session &session) -{ - // rewrites the entire file - QDir dir = QDir(m_vaultDirectory); - QString filePath = dir.filePath(session.id + ".md"); - QFile file = QFile(filePath); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Failed to update session file: " << filePath; - return; - } - - QTextStream out(&file); - out << "---\n"; - out << "Oneliner: " << session.oneliner << "\n"; - out << "DurationMs: " << session.durationMs << "\n"; - QString resultStr; - switch (session.result) { - case Session::WIN: - resultStr = "Win"; - break; - case Session::LOSS: - resultStr = "Loss"; - break; - case Session::NEUTRAL: - resultStr = "Neutral"; - break; - default: - resultStr = ""; - break; - } - if (!resultStr.isEmpty()) { - out << "Result: " << resultStr << "\n"; - } - out << "---\n"; - out << session.content << "\n"; - file.close(); -} - -// Session lifecycle methods - -void Service::startSession(const Session &session) { - if (m_activeSession.has_value()) { - qWarning() << "A session is already active. End it before starting a new one."; - return; - } - - m_activeSession = session; - m_sessionTimer.start(); - m_tickTimer->start(); - - emit activeSessionChanged(); - emit sessionTimerTicked(0); -} - -void Service::updateActiveSession(const Session &session) { - if (!m_activeSession.has_value()) { - qWarning() << "No active session to update."; - return; - } - - m_activeSession = session; - // Don't emit activeSessionChanged - just update the session data - // Timer keeps running -} - -int Service::getElapsedMs() const { - if (!m_activeSession) { - return 0; - } - return m_sessionTimer.elapsed(); -} - -void Service::resetSessionTimer() { - if (!m_activeSession) { - return; - } - - m_sessionTimer.restart(); - emit sessionTimerTicked(0); -} - -void Service::endSession(Session::Result result) { - if (!m_activeSession) { - return; - } - - // Update session with final values - Session updated = *m_activeSession; - updated.durationMs = getElapsedMs(); - updated.result = result; - updated.lastModifiedAt = QDateTime::currentDateTime(); - - // Save to file and update in list - updateSession(updated); - - // Clear active state - m_activeSession.reset(); - m_tickTimer->stop(); - - emit activeSessionChanged(); -} - -std::optional Service::activeSession() const { - return m_activeSession; -} - -void Service::onTickTimerFired() { - if (m_activeSession) { - emit sessionTimerTicked(getElapsedMs()); - } -} diff --git a/service.h b/service.h deleted file mode 100644 index 393eb55..0000000 --- a/service.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef SERVICE_H -#define SERVICE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct Session -{ - enum Result { - UNSPECIFIED = 0, - WIN, - LOSS, - NEUTRAL - }; - // Becomes the file name - QString id; - // Stored in the frontmatter under 'Oneliner' key - QString oneliner; - // Stored in the frontmatter - int durationMs; - // After the --- onwards, serves as general scratchpad - QString content; - // Stored in the frontmatter under 'Result' key - Result result; - - QDateTime lastModifiedAt; - QDateTime createdAt; - - bool isComplete() const; -}; - -class Service : public QObject { - Q_OBJECT - -public: - explicit Service(QObject *parent = nullptr); - ~Service(); - - QList sessions() const; - QString vaultDirectory() const; - - int sessionCount() const; - int completedSessionCount() const; - int totalWins() const; - int totalLosses() const; - int totalNeutrals() const; - -public slots: - /// @brief sets the directory from which to read/write sessions - /// Fails silently if not a valid path - /// Loads sessions from this path - void setVaultDirectory(const QString &path); - - /// @brief creates the session and stores in sessions list - /// @returns the newly created session - Session createSession(const QString &oneliner, const QString &content); - - /// @brief updates the session - /// Updates session in the sessions list, and the file associated - void updateSession(const Session &session); - - void deleteSession(const QString &sessionId); - - // Session lifecycle methods - void startSession(const Session &session); - void updateActiveSession(const Session &session); // Update without restarting timer - int getElapsedMs() const; - void resetSessionTimer(); - void endSession(Session::Result result); - std::optional activeSession() const; - -signals: - void sessionsChanged(); - void activeSessionChanged(); - void sessionTimerTicked(int elapsedMs); - -private: - QString m_vaultDirectory; - QList m_sessions; - - // Active session tracking - std::optional m_activeSession; - QElapsedTimer m_sessionTimer; - QTimer *m_tickTimer; - - /// @returns null Session if not a valid session markdown document - std::optional parseFile(const QFileInfo &fileInfo); - - Session::Result parseResult(const QString &resultStr); - void overwriteSessionFile(const Session &session); - -private slots: - void onTickTimerFired(); -}; - -Q_DECLARE_METATYPE(Session) - -#endif //SERVICE_H diff --git a/sessionitemdelegate.cpp b/sessionitemdelegate.cpp deleted file mode 100644 index 183f543..0000000 --- a/sessionitemdelegate.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "sessionitemdelegate.h" -#include "service.h" -#include -#include - -SessionItemDelegate::SessionItemDelegate(QObject *parent) - : QStyledItemDelegate(parent) -{ -} - -void SessionItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - if (!index.isValid()) { - QStyledItemDelegate::paint(painter, option, index); - return; - } - - painter->save(); - - // Get session data - Session session = index.data(Qt::UserRole).value(); - QString oneliner = session.oneliner; - - // Format duration - int seconds = session.durationMs / 1000; - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - int secs = seconds % 60; - QString durationStr = QString("%1:%2:%3") - .arg(hours, 2, 10, QChar('0')) - .arg(minutes, 2, 10, QChar('0')) - .arg(secs, 2, 10, QChar('0')); - - // Format result - QString resultStr; - switch (session.result) { - case Session::WIN: - resultStr = "WIN"; - break; - case Session::LOSS: - resultStr = "LOSS"; - break; - case Session::NEUTRAL: - resultStr = "NEUTRAL"; - break; - default: - resultStr = "UNSPECIFIED"; - break; - } - - // Format relative time - QDateTime now = QDateTime::currentDateTime(); - qint64 secsSinceModified = session.lastModifiedAt.secsTo(now); - QString relativeTime; - if (secsSinceModified < 60) { - relativeTime = "just now"; - } else if (secsSinceModified < 3600) { - relativeTime = QString("%1 min ago").arg(secsSinceModified / 60); - } else if (secsSinceModified < 86400) { - relativeTime = QString("%1 hr ago").arg(secsSinceModified / 3600); - } else { - relativeTime = QString("%1 days ago").arg(secsSinceModified / 86400); - } - - QString metadata = QString("Duration: %1 | Result: %2 | Modified: %3") - .arg(durationStr) - .arg(resultStr) - .arg(relativeTime); - - // Draw background - if (option.state & QStyle::State_Selected) { - painter->fillRect(option.rect, option.palette.highlight()); - } else { - painter->fillRect(option.rect, option.palette.base()); - } - - // Draw result indicator bar on the left - QColor indicatorColor; - switch (session.result) { - case Session::WIN: - indicatorColor = QColor(46, 204, 113); // Green - break; - case Session::LOSS: - indicatorColor = QColor(231, 76, 60); // Red - break; - case Session::NEUTRAL: - indicatorColor = QColor(149, 165, 166); // Gray - break; - default: - indicatorColor = QColor(0, 0, 0, 0); // Transparent - break; - } - - if (session.result != Session::UNSPECIFIED) { - QRect indicatorRect(option.rect.left(), option.rect.top(), 4, option.rect.height()); - painter->fillRect(indicatorRect, indicatorColor); - } - - // Set up text drawing - QRect textRect = option.rect.adjusted(10, 5, -5, -5); - QColor textColor = (option.state & QStyle::State_Selected) - ? option.palette.highlightedText().color() - : option.palette.text().color(); - - // Draw oneliner (bold, larger font) - painter->setPen(textColor); - QFont onelineFont = option.font; - onelineFont.setPointSize(14); - onelineFont.setBold(true); - painter->setFont(onelineFont); - - QRect onelineRect = textRect; - onelineRect.setHeight(24); - QString elidedOneliner = painter->fontMetrics().elidedText(oneliner, Qt::ElideRight, onelineRect.width()); - painter->drawText(onelineRect, Qt::AlignLeft | Qt::AlignVCenter, elidedOneliner); - - // Draw metadata (smaller font, lighter color) - QFont metadataFont = option.font; - metadataFont.setPointSize(11); - painter->setFont(metadataFont); - - QColor metadataColor = textColor; - metadataColor.setAlpha(180); // Make it slightly transparent - painter->setPen(metadataColor); - - QRect metadataRect = textRect; - metadataRect.setTop(onelineRect.bottom() + 2); - QString elidedMetadata = painter->fontMetrics().elidedText(metadata, Qt::ElideRight, metadataRect.width()); - painter->drawText(metadataRect, Qt::AlignLeft | Qt::AlignVCenter, elidedMetadata); - - painter->restore(); -} - -QSize SessionItemDelegate::sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - return QSize(option.rect.width(), 65); -} diff --git a/sessionitemdelegate.h b/sessionitemdelegate.h deleted file mode 100644 index e89b75e..0000000 --- a/sessionitemdelegate.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SESSIONITEMDELEGATE_H -#define SESSIONITEMDELEGATE_H - -#include - -class SessionItemDelegate : public QStyledItemDelegate -{ - Q_OBJECT - -public: - explicit SessionItemDelegate(QObject *parent = nullptr); - - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const override; - - QSize sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const override; -}; - -#endif // SESSIONITEMDELEGATE_H diff --git a/sessionslistmodel.cpp b/sessionslistmodel.cpp deleted file mode 100644 index cf13129..0000000 --- a/sessionslistmodel.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "sessionslistmodel.h" - -SessionsListModel::SessionsListModel(Service *service, QObject *parent) - : QAbstractListModel{parent}, m_service(service) -{ - connect(m_service, &Service::sessionsChanged, this, [this]() { - beginResetModel(); - endResetModel(); - }); -} - -int SessionsListModel::rowCount(const QModelIndex &parent) const { - return m_service->sessions().size(); -} - -int SessionsListModel::columnCount(const QModelIndex &parent) const { - return 1; -} - -QVariant SessionsListModel::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= rowCount()) { - return QVariant(); - } else if (!index.isValid()) { - return QVariant(); - } - - const Session session = m_service->sessions().at(index.row()); - switch (role) { - case Qt::DisplayRole: - // Simple display for fallback - delegate will handle rich rendering - return session.oneliner; - case Qt::UserRole: - // Store full session object for delegate access - return QVariant::fromValue(session); - default: - return QVariant(); - } -} - -Session SessionsListModel::getSessionByIndex(const QModelIndex &index) const { - if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) { - return Session(); // Return default-constructed session - } - return m_service->sessions().at(index.row()); -} diff --git a/sessionslistmodel.h b/sessionslistmodel.h deleted file mode 100644 index fb56763..0000000 --- a/sessionslistmodel.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef SESSIONSLISTMODEL_H -#define SESSIONSLISTMODEL_H - -#include -#include -#include "service.h" - -class SessionsListModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit SessionsListModel(Service *service, QObject *parent = nullptr); - - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - int columnCount(const QModelIndex& parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const override; - - Session getSessionByIndex(const QModelIndex &index) const; - -private: - Service *m_service; -}; - -#endif // SESSIONSLISTMODEL_H diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..8e59dd1 --- /dev/null +++ b/src/main.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char *argv[]) { + printf("Welcome to Flowy.adhd\n"); + +}