Initial commit: EventTracker desktop app + Android companion
Desktop: GTK3 + matplotlib app tracking arbitrary events (button -> timestamp -> CSV), with per-event stats, trend charts, settings (rename/add events, relocate data file), and a reset-with-backup flow. Portable desktop launcher via a .desktop.in template + install script, no machine-specific paths baked in. Android: minimal Kivy v1 companion reading/writing the same CSV format, plus buildozer build tooling isolated in a venv and a local p4a recipe override for kivy (see CLAUDE.md for why). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
cd9f9456e9
17 changed files with 1722 additions and 0 deletions
110
android/p4a-recipes/kivy/__init__.py
Normal file
110
android/p4a-recipes/kivy/__init__.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# Local override of p4a's built-in kivy recipe — identical except
|
||||
# python_depends is emptied. See buildozer.spec for why: upstream's
|
||||
# ['certifi', 'chardet', 'idna', 'requests', 'urllib3', 'filetype'] pulls
|
||||
# in requests -> charset-normalizer, whose newest release ships an
|
||||
# Android-tagged wheel that p4a's own install step can't actually install
|
||||
# (see comment in buildozer.spec). We never call kivy.network.UrlRequest,
|
||||
# so dropping the whole chain is correct, not just a workaround.
|
||||
from os.path import join
|
||||
import sys
|
||||
import packaging.version
|
||||
|
||||
import sh
|
||||
from pythonforandroid.recipe import PyProjectRecipe
|
||||
from pythonforandroid.toolchain import current_directory, shprint
|
||||
|
||||
|
||||
def get_kivy_version(recipe, arch):
|
||||
with current_directory(join(recipe.get_build_dir(arch.arch), "kivy")):
|
||||
return shprint(
|
||||
sh.Command(sys.executable),
|
||||
"-c",
|
||||
"import _version; print(_version.__version__)",
|
||||
)
|
||||
|
||||
|
||||
def is_kivy_affected_by_deadlock_issue(recipe=None, arch=None):
|
||||
return packaging.version.parse(
|
||||
str(get_kivy_version(recipe, arch))
|
||||
) < packaging.version.Version("2.2.0.dev0")
|
||||
|
||||
|
||||
def is_kivy_less_than_3(recipe=None, arch=None):
|
||||
return packaging.version.parse(
|
||||
str(get_kivy_version(recipe, arch))
|
||||
) < packaging.version.Version("3.0.0.dev0")
|
||||
|
||||
|
||||
class KivyRecipe(PyProjectRecipe):
|
||||
version = '2.3.1'
|
||||
url = 'https://github.com/kivy/kivy/archive/{version}.zip'
|
||||
name = 'kivy'
|
||||
|
||||
depends = [('sdl2', 'sdl3'), 'pyjnius', 'setuptools', 'android']
|
||||
python_depends = [] # upstream: ['certifi', 'chardet', 'idna', 'requests', 'urllib3', 'filetype'] — unused, see buildozer.spec
|
||||
hostpython_prerequisites = ["cython>=0.29.1,<=3.0.12"]
|
||||
|
||||
# sdl-gl-swapwindow-nogil.patch is needed to avoid a deadlock.
|
||||
# See: https://github.com/kivy/kivy/pull/8025
|
||||
# WARNING: Remove this patch when a new Kivy version is released.
|
||||
patches = [
|
||||
("sdl-gl-swapwindow-nogil.patch", is_kivy_affected_by_deadlock_issue),
|
||||
("use_cython.patch", is_kivy_less_than_3),
|
||||
"no-ast-str.patch"
|
||||
]
|
||||
|
||||
@property
|
||||
def need_stl_shared(self):
|
||||
if "sdl3" in self.ctx.recipe_build_order:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_recipe_env(self, arch, **kwargs):
|
||||
env = super().get_recipe_env(arch, **kwargs)
|
||||
|
||||
# Taken from CythonRecipe
|
||||
env['LDFLAGS'] = env['LDFLAGS'] + ' -L{} '.format(
|
||||
self.ctx.get_libs_dir(arch.arch) +
|
||||
' -L{} '.format(self.ctx.libs_dir) +
|
||||
' -L{}'.format(join(self.ctx.bootstrap.build_dir, 'obj', 'local',
|
||||
arch.arch)))
|
||||
env['LDSHARED'] = env['CC'] + ' -shared'
|
||||
env['LIBLINK'] = 'NOTNONE'
|
||||
|
||||
# NDKPLATFORM is our switch for detecting Android platform, so can't be None
|
||||
env['NDKPLATFORM'] = "NOTNONE"
|
||||
if not is_kivy_less_than_3(self, arch):
|
||||
env['KIVY_CROSS_PLATFORM'] = 'android'
|
||||
|
||||
if 'sdl2' in self.ctx.recipe_build_order:
|
||||
env['USE_SDL2'] = '1'
|
||||
env['KIVY_SPLIT_EXAMPLES'] = '1'
|
||||
sdl2_mixer_recipe = self.get_recipe('sdl2_mixer', self.ctx)
|
||||
sdl2_image_recipe = self.get_recipe('sdl2_image', self.ctx)
|
||||
env['KIVY_SDL2_PATH'] = ':'.join([
|
||||
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL', 'include'),
|
||||
*sdl2_image_recipe.get_include_dirs(arch),
|
||||
*sdl2_mixer_recipe.get_include_dirs(arch),
|
||||
join(self.ctx.bootstrap.build_dir, 'jni', 'SDL2_ttf'),
|
||||
])
|
||||
if "sdl3" in self.ctx.recipe_build_order:
|
||||
sdl3_mixer_recipe = self.get_recipe("sdl3_mixer", self.ctx)
|
||||
sdl3_image_recipe = self.get_recipe("sdl3_image", self.ctx)
|
||||
sdl3_ttf_recipe = self.get_recipe("sdl3_ttf", self.ctx)
|
||||
sdl3_recipe = self.get_recipe("sdl3", self.ctx)
|
||||
env["USE_SDL3"] = "1"
|
||||
env["KIVY_SPLIT_EXAMPLES"] = "1"
|
||||
env["KIVY_SDL3_PATH"] = ":".join(
|
||||
[
|
||||
*sdl3_mixer_recipe.get_include_dirs(arch),
|
||||
*sdl3_image_recipe.get_include_dirs(arch),
|
||||
*sdl3_ttf_recipe.get_include_dirs(arch),
|
||||
*sdl3_recipe.get_include_dirs(arch),
|
||||
]
|
||||
)
|
||||
|
||||
return env
|
||||
|
||||
|
||||
recipe = KivyRecipe()
|
||||
Loading…
Reference in a new issue