Giter VIP home page Giter VIP logo

pamet's Introduction

Pamet

An infinite canvas for organizing information with text/images/links. Written using Qt for Python.

โš  Still in alpha โš  - you'll probably encounter GUI bugs, but the data storage/saving is stable. Development is transitioning to web technologies for the front end currently. You can check out the progress here

Installation

Via desktop version via pip

Requires Python >3.10. If it's not available for your package manager(/app store) - you can use pyenv.

pip install pamet , start with pamet

From source

Will update the instructions soon. The app is transitioning to web technologies. The legacy desktop vesrsion is under minimal maintenence mode and will not be developed further.

Usage

  • Ctrl+shift+P for the command palette
  • Double click to create a new note
  • L to craete an arrow
  • Click to select
  • Long-press and drag to move selected notes/arrows
  • Ctrl or shift to select multiple notes
  • Ctrl+Shift to drag-select multiple notes
  • Drag the lower right corner of a note to resize it
  • Buttons 1,2,3,4 change the note color. 5 removes the background
  • Selected notes get moved together and resized to the same size
  • No manual saving is required
  • Copy/paste/cut work as you'd expect
  • Paste special with ctrl+shift+V (imports links and multiple notes) - will be improved

screenshot

pamet_demo.mp4

Testing

There are unit tests for some of the functionality and testing for the actions(=controller) which are not precise but are quite useful for visual verification (+are easy to generate).

screenshot

Development state and future

Check some notes on the development so far

Currently the code documentation isn't updated, and typing annotations have to be completed in places.

Next goals in terms of features:

  • Server for page sharing
  • A minimal web app for viewing pages
  • A minimal android app for viewing and limited input

pamet's People

Contributors

v-ko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

pamet's Issues

Implement touchpad navigation

  • Two-finger pan
    • Touchpad/mouse mode auto-switch service...done
      • Switch to left-mouse nav...done
        • Fix click selection...done
      • Apply scroll to pan in touchpad mode...done
  • Switch navigation to right-mouse-nav and left-mouse-select

Acceptance criteria:

  • Using the touchpad switches to the respective navigation mode (interpret scrolling as panning)
  • Using the mouse scroll or right-mouse pan switches to mouse mode
  • Page zoom shortcuts (ctrl+plus/minus and ctrl+scroll) are intercepted and interpreted as zoom

Story tonnage:
5 / M

Improve the initial help note

The initial help note could contain a real help information like - "Pres right mouse button to create another note, page etc."

Implement note and arrow selection

  • Alter PageViewState...done

  • Integrate paper.js for intersection calculations and canvas rendering...done

    • Local state for the note rects and arrow paths (for selection calculations)...done
  • Implement click selection...done

    • selectedChildren changes don't trigger a canvas update...done
    • note selection...done
    • arrow selection...done
      • Circle intersection testing...done
  • Implement drag selection

    • PageViewState add props...done
    • Start, update, finish actions...done
    • View rendering of the selection rect...done
    • View user action handling to trigger drag select...done
  • Test

    • Bug: Windows resize breaks canvas coordinate system....done
    • Fix drag select rendering issues...done
    • Stress test...done

AC:

  • Click on an item selects it, deselects all else
  • Click on item with ctrl toggles selection
  • Click on item with shift adds the item to selection
  • Click on canvas clears selection
  • Mouse drag with ctrl+shift pressed, shows a selection rect and selects items under it on release
  • Stress test

Story points:
8 / L

Plan for the local persistence and device sync machinery (that would be compatible with sharing and real-time collab services)

  • Use cases relevant to the problem
    • Offline work and device sync
    • Inter-tab sync, desktop server sync
    • Sharing
    • Real-time collab
    • Undo/redo - not really, will be handled on the change-set level
    • Backups - not really, could use commits, but should be handled in a separate on-device (non-synced) service
    • Full change history retention - not really, should be on-device, non-synced. Again - possibly a separate service or part of the backup
    • Media sync
      • The fetch source can be swapped by intercepting the requests in a service worker. So the browser cache will be used naturally, while the source of the media can be swapped.
  • Constraints/requirements
    • Possibly without accurate time sync for every node
    • Able to tollerate long offline periods and multiple changes (offline work)
    • Multi device multi-user state syncing with automatic conflict resolution. Data loss on conflict is acceptable and resolved on a node seniority principle
    • Worst case scenario merkle-tree hashing tests (200 changed hashes for 750char content leafs + 15000 unchanged content leafs to be recalculated into node-hashes) on "low-end mobile hardware" (chrome dev-tools throttling) take ~160ms. Therefore commit creation cannot be in the main-thread, but can be done on every commit

Story points:
XL / 13 (were expected to be M to L)

Project icon

It will be nice if you can ask Mila to make some simple icon for the project that will be seen in GitHub, Taskbar, Desktop etc.
She will be able to add "Works on several open source projects." to her CV then ;)

Local persistence service

  • Implement Repository functionality - changesets created by the user/services via Actions should trigger commit creation in the Local repo service (rename?). This will happen by pushing changesets from the top-level-action (TLA) channel to the repo service. The latter will create commits and push them to the appliedCommits (rename?) channel. There will be a store Resync (?) service, that receives the local changesets, and also the commits from appliedCommits, and keeps the local store synchronized to the commit stream. E.g. if a different tab makes changes - the repo service will produce a commit. The latter should be applied to the first tab.

Image

  • Delete selected elements action implement, add shortcut. Use for testing
  • Test

Optional:

  • Broadcast changes among tabs

Story points:
L / 8

Remove mobx domain stores and reintroduce the InMemoryStore

  • Fix the domain store related code - it will be used for propagating the changes to the in-mem storage or other (persistence) adapters.. also services like search/undo-redo. Let's leave the mobx store to be used only for views. That's what it's for. Other stuff will be handled by the custom store and channels. Ok, so if i'll pass evereything through the pametCRUD anyway - I might as well make the .note accessor methods return a note copy to be modified in the actions (e.g. refactor the .note to note(), which under the hood calls the computed _note mobx property or whatever). then the updated note/arrow/element gets passed to pametCRUD via the facade methods. I'm taking ownage of the domain store management, so only add a mapping function to update view states on note changes (synchronously, in-action, in the facade, right after the inMemStore update).
    • setCurrentPage action to directly create (or reuse) the PVS , instead of just chanigng the currentPageId...done
    • Reintroduce the InMemoryStore (move methods from facade?)...done
    • Fix facade methods to use the InMemRepo...done
      • Load duplicate errors...done
      • Decide on PametInMemRepo implementation - compose, rather than inherit...not needed. The facade does that. In other words: done
    • applyChangesToViewStates(app_state, changes) reducer-like function will go through all the ViewStates in the app state and swap the data objects on update (fcit no diffing needed. It's only for actual entity changes).
    • add/remove/update EVS methods in the page view state...done
    • Implement applyChangesToViewStates...done
    • Call it after pushing the changes (synchronously) to the inMemStore (so that that mapping happens in-action, and without increased complexity, side-effects etc)...done
    • Test with note creation...done
      • Image note update after loading is broken...resolved in meantime
      • New note change is not reflected...done
    • refactor NVS.note to note() + get _note():computed
    • Rename sync repo to store if it still seems appropriate...not for now

Acceptance criteria:

  • No regressions

Story points:
5 / M

Implement edit window and related functionality

Note editing, at least for the core note types, will happen via a single note edit component. Any interactive integrations will open in a separate modal window.

  • Design the window...done, mostly reusing the desktop design

    • Consider integrations (e.g. script note, audio, video) settings - as a separate panel?...no, as a modal window
    • Consider the mobile interface...done
  • Implement note text editing

    • Implement a minimal component/window...done

    • Add the edit window state as part of the page view state...done

      • Structure the component hierarchy app-mid?-page...done
    • Implement an action to show the edit window and call it on the N button press...done

      • Should be a command, so setup the commands lib...done
        • Mouse position is needed, so setup tracking in the page view state...done
    • Fix the basic layout...done

      • Implement window dragging...done
        • Implement restrictions on drag/resize positions and sizes. Hopefully in css...done, not in css but accetably easy
      • add close button, title and move handle icon...done
    • Text edit related

      • Add text area and fix main content layout...done
      • Pass the note data and populate the text area...done
    • Fix react image element duplicates...done

    • Actions to save/cancel editing...done

      • Add a note() method to the editWindowState...done
      • Implement the saveEditedNote action
        • Add default method to TextNote...done
          • Refactor own/page id storage logic...done
        • Autosize function translate to ts...done
          • Implement Size class...done
      • Note does not update on size change...will be fixed in another issue
      • Add autosize command and shortcut (also a large size shortcut for testing)...done
    • Add E edit window shortcut in page...done

    • Add Esc shortcut for edit window close...done

    • Shortcuts interfere with text typing in the edit window...done

    • Scroll events should also probably be stopped to not bubble...done

    • Double click to edit/new note...done

Acceptance criteria:

  • Edited notes get updated as expected
  • Edit window opens on double-click and N shortcut
  • Closes on Esc

Story tonnage:
3 / S -> 5 / M

Implement card, script, external link note rendering

  • Card note rendering:

    • Computed layout methods in the view state
  • Script note rendering - reuse text note and decorate

  • External link note - add

Acceptance criteria:

  • Correct rendering in all shapes and sizes
  • Correct text eliding where present
  • Error reporting (for missing script file, etc)

Story tonnage:
3 / S

Test navigation rendering optimization options

Navigation lag noticeable in large note files. In theory pure translate/scale transformations should be efficient, so the lag may be alleviated via restricting state-tree diffing operations for the page.

  • Test if pure css var changes reduce the lag...yes, but on low-end devices and large pages that's not enough

Will have to implement canvas/webgl rendering instead of react components for notes/arrows

Remove CRA and fix tests for symlinked folders

  • Testing is broken (craco preserve symlink config stopped working at some point). CRA is a lot of trouble.
    • Migrate to Vite...done
    • Refactor to monorepo...done
      • Vite config problems...done, probably
      • multi-root error. remove node_modules from subfolders?...done
      • Python refactoring problems - cannot import fusion on debug (works from terminal)...done

Acceptance criteria:

  • Running InMemoryRepository tests

Story tonnage:
5 / M

Implement canvas rendering

  • PixiJS research...no, doesn't include path intersection API, and is heavier

  • Optimize rendering...done

    • Drawing cache service...done
    • Urgent rendering logic...done
    • Testing...done
      • Draw cache rect and add sanity check logging in the untested functions. It's probably the projection matrix...done
      • Test arrow disappearance - probably bad ctx management...done
      • Fix dpr rendering issues...done
        • Fix viewport projection calculation - makes no sense to keep the 0,0 real coords in the viewport center...done
          • Project to topleft in Viewport...done
          • Init vieportCenter in PVS to the element center...done
          • Fix realTopLeft argument in calls...done
      • Fix denovo updates on translate (bad cache rect I guess)...done
      • No patterns appear ever....done
      • Cache rects are variable on DPR!=1 (notes wiggle on panning)...done
        • Add DPR to the Viewport ...done
      • Don't cache on closeup...done
      • There's still rendering artefacts on some scales. Translation invariant...done , fixed by increasing the cache rect padding
      • Initial render update not happening...done
      • Remove PaperJS (and pixi), replace bezier intersection functionality...no, there's no alternative and I fixed performance issues and memory leaks...done
      • Skip redundant queued renders...done
  • Note rendering

    • TextLayout remove empty lines...done

    • Fix notes with new lines...done

    • Call next render if unfinished items...done

    • Plan image rendering...done

      • Take advantage of browser cache

      • Add a lazy image loading service - notes will query it when rendering and will provide fallback container size. The service will either return the image or a placeholder depiction

        • The lazy image service keeps its state in the appState (queued downloads)
        • Well the whole service has to be a queue with cache. I.e. keep most frequently accessed in memory (that is optional actually, but preferable) and regardless if retrieved from cache or abroad - deliver each item to be "consumed" by the renderer. This may be implicitly achieved through the image access method. This means the image disappears on scaling tho.. But only if there's too many images (>cache), which is ok. Which means I don't need a strict consumption mechanism/queue, neither the implicit freeing. Just a cache, and an on-screen warning for "too many images. Will not render all".
        • Alternatively: Since I'll have a boundary on the acceptable image count (for full rendering) - I can implement that in react and not deal with the service. I only need to synchronize react rendering with the canvas rendering to avoid artefacts
        • Final? a lazy image service that queues images for download (+/- in a service worker) upon calling the access method. The service has a view-state: on each finished download a counter is incremented to trigger page rerender, a flag indicates if the queue is empty (shows a spinner otherwise?)

        Final:

        • Upon further consideration - the max note size is 1920x1920. That will be the max image preview size too, which with adequate compression means acceptable memory requirements. The server will provide images with the size of the note (on each note resize - the backend updates its cache). On the cloud/desktop backend the original file is kept (subject to size restrictions). On the PWA backend - files are resized on upload (to 1920x1920, lossy) and kept in the indexDB. On page render - the notes with images will be added as hidden elements (with a placeholder fallback) and their references will be mapped to their NVS/url in the canvas-renderer. The canvasDraw will accept not ctx, but the renderer as a parameter (and will access images by retrieving its ref via some method)
          • since we'll be keeping references (i.e. note view react state) - we can go ahead and add all notes for SEO (invisible) and call the canvasDraw in the component... NO, the two renderers (react, and my canvas-renderer) are separate concerns
            *On the PWA backend - files are resized on upload (to 1920x1920, lossy) and kept in the indexDB... NO , i don't want to deal with caring for the image life cycle
          • Write down the plan in a structured manner...done
    • Render the img tags for the media components with react

      • Will just create the elements hidden with react and query them at render time via the document API...done
      • parseMediaUrl error (mutable data mistake?)...done
    • Implement add/get/clear image element reference...no

    • Put note rendering logic in CanvasElementView components - functional (the simpler option) + leave only NoteViewState (no note-type-specific states). The mapping will be on the View level

      • Add ElementView registration...done
      • Rename the page renderer...done
    • Implement ImageView...done

      • Remove card notes?...yes
    • InternalLinkNote...done

    • Test...done

    • Implement CardView...no

    • Draw link borders when appropriate...done

  • Arrow rendering...done

    • Draw arrow head...done

Acceptance criteria:

  • Correct rendering for all types of notes and for arrows
  • Low latency when stress testing

Story points:
13 / XL

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.