clear out qt app
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
build/
|
||||
build-universal/
|
||||
*~
|
||||
@@ -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 $<NOT:$<CONFIG:Debug>>
|
||||
)
|
||||
|
||||
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})
|
||||
@@ -1,462 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 16.0.2, 2026-02-01T13:41:28. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{1354daad-1138-41d2-985c-27357b7ee48a}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="qlonglong">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">5</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 6.8.6 for macOS</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Qt 6.8.6 for macOS</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt6.686.clang_64_kit</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-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}</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="CMake.Build.Type">Release</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-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}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-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}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-RelWithDebInfo</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
|
||||
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-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}</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.4">
|
||||
<value type="QString" key="CMake.Build.Type">MinSizeRel</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-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}</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-MinSizeRel</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">5</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">adhd</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">adhd</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/Users/talksik/Documents/code/adhd/build/Qt_6_8_6_for_macOS-Debug/adhd.app/Contents/MacOS</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="qlonglong">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
## 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "========================================="
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "createsessiondialog.h"
|
||||
#include "ui_createsessiondialog.h"
|
||||
#include <QPushButton>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef CREATESESSIONDIALOG_H
|
||||
#define CREATESESSIONDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
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
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CreateSessionDialog</class>
|
||||
<widget class="QDialog" name="CreateSessionDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Session</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="onelinerLabel">
|
||||
<property name="text">
|
||||
<string>Oneliner:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="onelinerEdit">
|
||||
<property name="placeholderText">
|
||||
<string>What will you focus on?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="contentLabel">
|
||||
<property name="text">
|
||||
<string>Initial Content:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QTextEdit" name="contentEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Optional: Add initial notes or context...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CreateSessionDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CreateSessionDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -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();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef ENDSESSIONDIALOG_H
|
||||
#define ENDSESSIONDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#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
|
||||
@@ -1,221 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EndSessionDialog</class>
|
||||
<widget class="QDialog" name="EndSessionDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>End Session</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>How did your session go?</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="onelinerLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Session Oneliner</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="elapsedLabel">
|
||||
<property name="text">
|
||||
<string>Duration: 00:00:00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="winButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton {
|
||||
background-color: #2ecc71;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #27ae60;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #229954;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>WIN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="lossButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #a93226;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LOSS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="neutralButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton {
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #7f8c8d;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #707b7c;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NEUTRAL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Optional: Add final notes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="notesEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Any final thoughts or notes about this session...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,100 +0,0 @@
|
||||
#include "focusoverlay.h"
|
||||
#include "ui_focusoverlay.h"
|
||||
#include <QScreen>
|
||||
#include <QGuiApplication>
|
||||
#include <QMouseEvent>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#ifndef FOCUSOVERLAY_H
|
||||
#define FOCUSOVERLAY_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
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
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FocusOverlay</class>
|
||||
<widget class="QWidget" name="FocusOverlay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>102</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>102</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Focus Session</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">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);
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="onelinerLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Session Oneliner</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="elapsedLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Elapsed: 00:00:00</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetButton">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="endButton">
|
||||
<property name="text">
|
||||
<string>End Session</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,16 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <QApplication>
|
||||
#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();
|
||||
}
|
||||
-264
@@ -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 <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#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'));
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMainWindow>
|
||||
|
||||
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
|
||||
-289
@@ -1,289 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Settings</string>
|
||||
</attribute>
|
||||
<widget class="QLabel" name="vaultLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>80</x>
|
||||
<y>210</y>
|
||||
<width>221</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select a folder</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="selectVaultButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>130</x>
|
||||
<y>240</y>
|
||||
<width>121</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select vault</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Sessions</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="newSessionButton">
|
||||
<property name="text">
|
||||
<string>New Session</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="startSessionButton">
|
||||
<property name="text">
|
||||
<string>Start Selected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="listView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Active</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="activeStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="noSessionPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="noSessionLabel">
|
||||
<property name="text">
|
||||
<string>No session running. Start a session to begin.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="activeSessionPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>190</width>
|
||||
<height>244</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Oneliner:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="oneLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Elapsed Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="elapsedLabel">
|
||||
<property name="text">
|
||||
<string>00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Created:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="createdLabel">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Modified:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="modifiedLabel">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Content:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QTextEdit" name="contentTextEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Add notes, context, or anything related to this session...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="endSessionButton">
|
||||
<property name="text">
|
||||
<string>End Session</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,5 +0,0 @@
|
||||
#include "namegenerator.h"
|
||||
|
||||
QString generate() {
|
||||
return QString("generated-name-placeholder");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef NAMEGENERATOR_H
|
||||
#define NAMEGENERATOR_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
QString generate();
|
||||
|
||||
#endif //NAMEGENERATOR_H
|
||||
@@ -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
|
||||
-349
@@ -1,349 +0,0 @@
|
||||
#include "service.h"
|
||||
#include <QDir>
|
||||
#include <QFileInfoList>
|
||||
#include <QUuid>
|
||||
#include <QFile>
|
||||
|
||||
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<Session> 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> 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<Session> 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<int>(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<Session> Service::activeSession() const {
|
||||
return m_activeSession;
|
||||
}
|
||||
|
||||
void Service::onTickTimerFired() {
|
||||
if (m_activeSession) {
|
||||
emit sessionTimerTicked(getElapsedMs());
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
#ifndef SERVICE_H
|
||||
#define SERVICE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QFileInfo>
|
||||
#include <QElapsedTimer>
|
||||
#include <QTimer>
|
||||
#include <optional>
|
||||
|
||||
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<Session> 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<Session> activeSession() const;
|
||||
|
||||
signals:
|
||||
void sessionsChanged();
|
||||
void activeSessionChanged();
|
||||
void sessionTimerTicked(int elapsedMs);
|
||||
|
||||
private:
|
||||
QString m_vaultDirectory;
|
||||
QList<Session> m_sessions;
|
||||
|
||||
// Active session tracking
|
||||
std::optional<Session> m_activeSession;
|
||||
QElapsedTimer m_sessionTimer;
|
||||
QTimer *m_tickTimer;
|
||||
|
||||
/// @returns null Session if not a valid session markdown document
|
||||
std::optional<Session> 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
|
||||
@@ -1,139 +0,0 @@
|
||||
#include "sessionitemdelegate.h"
|
||||
#include "service.h"
|
||||
#include <QPainter>
|
||||
#include <QDateTime>
|
||||
|
||||
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<Session>();
|
||||
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);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef SESSIONITEMDELEGATE_H
|
||||
#define SESSIONITEMDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
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
|
||||
@@ -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());
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef SESSIONSLISTMODEL_H
|
||||
#define SESSIONSLISTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#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
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("Welcome to Flowy.adhd\n");
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user