diff --git a/.gitignore b/.gitignore index 2a38550a..a3619ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ -# Python -__pycache__/ *.py[cod] -*$py.class -*.so +__pycache__/ +.pytest_cache/ +.coverage +htmlcov/ + +# Distribution / packaging .Python build/ develop-eggs/ @@ -20,7 +22,12 @@ wheels/ .installed.cfg *.egg -# Virtual Environment +# Installer artifacts +installer/build/ +installer/dist/ +rw.*.dmg # Temporary disk images + +# Virtual environments .env .venv env/ @@ -30,15 +37,8 @@ ENV/ # IDE .idea/ .vscode/ +*.swp +*.swo -# Project specific -projects/*.db -projects/*.db-journal -/.coverage - -**/.DS_Store - -*.log -/.coverage.* - -installer/build/ \ No newline at end of file +# macOS +.DS_Store diff --git a/pyproject.toml b/pyproject.toml index 23aef801..ecd76c96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ "watchfiles>=1.0.4", "fastapi[standard]>=0.115.8", "alembic>=1.14.1", + "rumps>=0.4.0", ] [project.urls] diff --git a/src/basic_memory/ui/menubar/__init__.py b/src/basic_memory/ui/menubar/__init__.py new file mode 100644 index 00000000..d16b6be1 --- /dev/null +++ b/src/basic_memory/ui/menubar/__init__.py @@ -0,0 +1,4 @@ +"""Basic Memory menubar application package.""" +from .app import BasicMemoryApp, main + +__all__ = ["BasicMemoryApp", "main"] diff --git a/src/basic_memory/ui/menubar/app.py b/src/basic_memory/ui/menubar/app.py new file mode 100644 index 00000000..0466740b --- /dev/null +++ b/src/basic_memory/ui/menubar/app.py @@ -0,0 +1,47 @@ +"""Basic Memory menubar app using rumps.""" +import rumps +from loguru import logger + +class BasicMemoryApp(rumps.App): + def __init__(self): + super().__init__("Basic Memory", "✓") + + # Initialize menu structure + self.menu = [ + rumps.MenuItem("Status: Idle"), + None, # separator + rumps.MenuItem("Recent Events"), + None, + ["Settings", + "Choose Home Directory...", + "Start at Login" + ], + None, + "Start Sync", + ] + + @rumps.clicked("Start Sync") + def toggle_sync(self, _): + """Toggle sync on/off.""" + sender = self.menu["Start Sync"] + if sender.title == "Start Sync": + sender.title = "Stop Sync" + self.icon = "↻" + # TODO: Start sync process + else: + sender.title = "Start Sync" + self.icon = "✓" + # TODO: Stop sync process + + @rumps.clicked("Settings", "Choose Home Directory...") + def choose_home_dir(self, _): + """Open dialog to choose home directory.""" + # TODO: Implement directory chooser + logger.info("Choose home directory clicked") + +def main(): + """Run the menubar app.""" + BasicMemoryApp().run() + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index b70047c0..4c407134 100644 --- a/uv.lock +++ b/uv.lock @@ -88,6 +88,7 @@ dependencies = [ { name = "python-frontmatter" }, { name = "pyyaml" }, { name = "rich" }, + { name = "rumps" }, { name = "sqlalchemy" }, { name = "typer" }, { name = "unidecode" }, @@ -123,6 +124,7 @@ requires-dist = [ { name = "python-frontmatter", specifier = ">=1.1.0" }, { name = "pyyaml", specifier = ">=6.0.1" }, { name = "rich", specifier = ">=13.9.4" }, + { name = "rumps", specifier = ">=0.4.0" }, { name = "sqlalchemy", specifier = ">=2.0.0" }, { name = "typer", specifier = ">=0.9.0" }, { name = "unidecode", specifier = ">=1.3.8" }, @@ -761,6 +763,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] +[[package]] +name = "pyobjc-core" +version = "11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/94/a111239b98260869780a5767e5d74bfd3a8c13a40457f479c28dcd91f89d/pyobjc_core-11.0.tar.gz", hash = "sha256:63bced211cb8a8fb5c8ff46473603da30e51112861bd02c438fbbbc8578d9a70", size = 994931 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/ce/bf3ff9a9347721a398c3dfb83e29b43fb166b7ef590f3f7b7ddcd283df39/pyobjc_core-11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a03061d4955c62ddd7754224a80cdadfdf17b6b5f60df1d9169a3b1b02923f0b", size = 739750 }, + { url = "https://files.pythonhosted.org/packages/72/16/0c468e73dbecb821e3da8819236fe832dfc53eb5f66a11775b055a7589ea/pyobjc_core-11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c338c1deb7ab2e9436d4175d1127da2eeed4a1b564b3d83b9f3ae4844ba97e86", size = 743900 }, + { url = "https://files.pythonhosted.org/packages/f3/88/cecec88fd51f62a6cd7775cc4fb6bfde16652f97df88d28c84fb77ca0c18/pyobjc_core-11.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b4e9dc4296110f251a4033ff3f40320b35873ea7f876bd29a1c9705bb5e08c59", size = 791905 }, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/32/53809096ad5fc3e7a2c5ddea642590a5f2cb5b81d0ad6ea67fdb2263d9f9/pyobjc_framework_cocoa-11.0.tar.gz", hash = "sha256:00346a8cb81ad7b017b32ff7bf596000f9faa905807b1bd234644ebd47f692c5", size = 6173848 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/8d/0e2558447c26b3ba64f7c9776a5a6c9d2ae8abf9d34308b174ae0934402e/pyobjc_framework_Cocoa-11.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:280a577b83c68175a28b2b7138d1d2d3111f2b2b66c30e86f81a19c2b02eae71", size = 385811 }, + { url = "https://files.pythonhosted.org/packages/1d/a5/609281a7e89efefbef9db1d8fe66bc0458c3b4e74e2227c644f9c18926fa/pyobjc_framework_Cocoa-11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:15b2bd977ed340074f930f1330f03d42912d5882b697d78bd06f8ebe263ef92e", size = 385889 }, + { url = "https://files.pythonhosted.org/packages/93/f6/2d5a863673ef7b85a3cba875c43e6c495fb1307427a6801001ae94bb5e54/pyobjc_framework_Cocoa-11.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5750001db544e67f2b66f02067d8f0da96bb2ef71732bde104f01b8628f9d7ea", size = 389831 }, +] + [[package]] name = "pyqt6" version = "6.8.1" @@ -1041,6 +1068,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/4e/33df635528292bd2d18404e4daabcd74ca8a9853b2e1df85ed3d32d24362/ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6", size = 10001738 }, ] +[[package]] +name = "rumps" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyobjc-framework-cocoa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/e2/2e6a47951290bd1a2831dcc50aec4b25d104c0cf00e8b7868cbd29cf3bfe/rumps-0.4.0.tar.gz", hash = "sha256:17fb33c21b54b1e25db0d71d1d793dc19dc3c0b7d8c79dc6d833d0cffc8b1596", size = 39257 } + [[package]] name = "setuptools" version = "75.8.0"