PROJECT: ɯeme


Overview

ɯeme is a meme manager app for those who prefer to use a desktop app for managing memes. More importantly, ɯeme is optimized for those who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). Users can view, tag, search, import and export a collection of meme. They can also create their own memes from meme templates.

Summary of contributions

  • Major enhancement: added the ability to undo/redo previous commands

    • What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.

    • Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.

    • Highlights: This enhancement affects existing and future commands, as well as the design of the model of the application. The inclusion of files, as we are handling meme images, complicates a lot of logic with the existing commands. Commands that were easy to implement such as add were not trivial to undo when local files are being manipulated. As a result, many alternatives had to be considered before arriving to a well-planned conclusion. A thorough understanding of how the entire application functioned was necessary to ensure that the undo/redo implementation syncs well with existing and future commands, making the design of the feature much more complicated.

    • Credits: Basic idea from AB4 implementation.

  • Minor enhancement:

    • Added logic for tabs [#40]

    • Added archive-related commands with tests for Memes and Templates [#133] [#209]

  • Code contributed: [RepoSense Code]

  • Other contributions:

    • Project management:

      • Extensively reviewed most of peer’s pull requests before merging into master [Reviews]

      • Managed issues and milestones on GitHub for weekly deadlines.

      • Renamed AB3 to Weme as part of morphing [#10]

    • Enhancements to existing features:

      • Fixed SampleDataUtil for file support [#67]

      • Fixed GUI to support larger range of resolutions [#247]

    • Documentation:

      • Assisted with update of documentation from addressbook3 to Weme [#75]

    • Community:

      • Reported bugs and suggestions for other teams [PED]

    • Tools:

      • Added support for Travis-CI, AppVeyor, Coveralls and Netlify [#1]

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Undoing previous commands : undo

Undoes commands and tells you the command you just undid.
Format: undo
Example: undo

Redoing previously undone commands: redo

Redoes previously undone commands and tells you the command you just redid.
Format: redo
Example: redo

Commands such as list, find that only change the user interface, commands such as export and load that are related to external files, as well as commands such as edit and delete in the import tab that modifies the import list are not supported.

These are the list of commands that support undo / redo operations:

  • Memes Tab: add, edit, delete, clear, archive, unarchive, like, dislike, stage

  • Templates Tab: add, edit, delete, clear, archive, unarchive, use

  • Create Tab: add, edit, delete, move, abort, create

  • Export Tab: unstage, clear

  • Import Tab: import

undo and redo works between tabs. This means that if you make a change in the Memes tab, by editing a meme, and then you switch to the Templates tab, when you execute undo, it reverts the change in the Memes tab as well. However, undo/redo is not usable while viewing a meme.

Listing archived memes: archives

Lists all memes that are archived in the memes tab.
Format: archives

  • To view unarchived memes again, just execute the list command!

Archiving a meme: archive

Archives the meme at the specified index. Hides the meme from the default view.
Format: archive INDEX

  • You can only archive unarchived memes. Execute list to see the unarchived memes.

Unarchiving a meme: unarchive

Unarchives the meme at the specified index. Shows the meme in the default view.
Format: unarchive INDEX

  • You can only unarchive archived memes. Execute archives to see the archived memes.

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Besides the section below, I have also written the Archives Feature section.

Undo/Redo feature

The Undo and Redo commands are necessary to give users the flexibility of undoing or redoing a wrongly executed command. Especially in Weme where we deal with image files, it is possible to key in the wrong file when adding a meme. Hence, simply entering the command undo allows the user to revert this mistake and add the correct file accordingly.

Current implementation

The undo/redo mechanism is facilitated by VersionedWeme. VersionedWeme extends Weme with an undo/redo history, stored internally as a versionedWemeStates, stateIndex and a feedbackList. Additionally, it implements the following operations:

  • VersionedWeme#commit() — Saves the current Weme state in its history.

  • VersionedWeme#undo() — Restores the previous Weme state from its history and returns the feedback message of the undone command.

  • VersionedWeme#redo() — Restores a previously undone Weme state from its history and returns the feedback message of the redone command.

These operations are exposed in the Model interface as Model#commitWeme(), Model#undoWeme() and Model#redoWeme() respectively.

Only state changes on the internal structure of Weme are undoable.

Commands such as list, find that only change the user interface, commands such as export and load that are related to external files, as well as commands such as edit and delete in the import tab that modifies the import list are not supported.

These are the list of commands that support undo / redo operations:

  • Memes Tab: add, edit, delete, clear, archive, unarchive, like, dislike, stage

  • Templates Tab: add, edit, delete, clear, archive, unarchive, use

  • Create Tab: add, edit, delete, move, abort, create

  • Export Tab: unstage, clear

  • Import Tab: import

undo and redo works between tabs. This means that if you make a change in the Memes tab, by editing a meme, and then you switch to the Templates tab, when you execute undo, it reverts the change in the Memes tab as well. However, undo/redo is not usable while viewing a meme.

Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.

Step 1. The user launches the application for the first time. The VersionedWeme will be initialized with the initial Weme state, and the stateIndex pointing to that single Weme state.

UndoRedoState0

Step 2. The user executes delete 5 command to delete the 5th meme in the meme list. The delete command calls Model#commitWeme() with the success feedback message as a parameter, causing the modified state of the Weme after the delete 5 command executes to be saved in the versionedWemeStates, the stateIndex is shifted to the newly inserted Weme state, and finally the delete command’s feedback message is inserted into the feedbackList.

UndoRedoState1

Step 3. The user executes edit 2 d/surprised pikachu to edit a meme’s description. The edit command also calls Model#commitWeme(), causing another modified Weme state to be saved into the versionedWemeStates.

UndoRedoState2
If a command fails its execution, it will not call Model#commitWeme(), so the Weme state will not be saved into the versionedWemeStates.

Step 4. The user now decides that editing the meme was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoWeme(), which will shift the stateIndex once to the left, pointing it to the previous Weme state, and restores the Weme to that state. The feedback message is then returned to pass into and construct the CommandResult.

UndoRedoState3
If the stateIndex is at index 0, pointing to the initial Weme state, then there are no previous Weme states to restore. The undo command uses Model#canUndoWeme() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoSequenceDiagram
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

The redo command does the opposite — it calls Model#redoWeme(), which shifts the stateIndex once to the right, pointing to the previously undone state, and restores the Weme to that state.

If the stateIndex is at index versionedWemeStates.size() - 1, pointing to the latest Weme state, then there are no undone Weme states to restore. The redo command uses Model#canRedoWeme() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command list. Commands that do not modify the Weme, such as list, will usually not call Model#commitWeme(), Model#undoWeme() or Model#redoWeme(). Thus, the versionedWemeStates remains unchanged.

UndoRedoState4

Step 6. The user executes clear, which calls Model#commitWeme(). Since the stateIndex is not pointing at the end of the versionedWemeStates, all Weme states after the stateIndex will be purged. We designed it this way because it no longer makes sense to redo the edit 2 d/surprised pikachu command. This is the behavior that most modern desktop applications follow.

UndoRedoState5

The following activity diagram summarizes what happens when a user executes a new command:

CommitActivityDiagram

The addition of undo redo complicates certain commands. An example of this complication is when undoing add or delete commands. Originally, deleting a Meme will delete the corresponding image file on the disk. However, this means it is not possible to retrieve the file afterwards when attempting to undo. Hence, the current implementation is to delete the Meme entry in the json, but keep the original image file until Weme is closed. When Weme is closed, a thread will clean up all unreferenced image files in the image folder. This is part of the reason why certain commands such as load are not supported.

The following sequence diagram shows how the clean up works:

CleanUpSequenceDiagram

When the handleExit command is called, MainWindow will create a Thread to call logic.cleanUp() to prevent the GUI from slowing down. The thread then further spawns other threads to clean up the files in the data folder, deleting those images that are not found in the memes and templates list stored on Weme. The cleanTemplateStorage() part of the UML diagram has been truncated as it is similar to cleanMemeStorage().

Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire state.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for delete, just save the meme being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct. This gets complicated when dealing with files.

Aspect: Types of commands to undo
  • Alternative 1 (current choice): Includes only commands that modify the underlying data. (Add, Edit, Clear, Delete)

    • Pros: Only changes that permanently affect the application are reverted.

    • Cons: Might be less intuitive as a user calling tab templates then undo might expect to revert the Tab command instead.

  • Alternative 2: Includes all commands

    • Pros: Intuitive

    • Cons: Might be very troublesome for a user if they want to revert the state instead of the view. More unexpected behaviours as certain commands such as load depends on files outside Weme’s data folder. If there is an error on redoing a command, there is no easy way to find out.

Aspect: Context for commands to be undoable
  • Alternative 1 (current choice): Allow undoing throughout the application regardless of context.

    • Pros: User in a different context is able to easily undo the state.

    • Cons: User might expect to undo only when they are in the same context. i.e. Undo Meme commands in Meme context.

  • Alternative 2: Restrict undoing to its own context

    • Pros: More user intuitive. Commands will only affect their own context.

    • Cons: Heavily complicates the model. Model will then need to keep track of a versioning of every single context. Does not allow for commands such as create which affects the Creation tab and Memes tab without many modifications to the existing structure.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of past states.

    • Pros: Easy to understand and adjust according to needs. Undo and redo simply moves along the list to change the state.

    • Cons: Clutters up the Weme class.

  • Alternative 2: Use a wrapper class

    • Pros: Everything will be handled within a single UndoRedoManager class.

    • Cons: Might introduce complications as managing states now needs to go through another class instead of just the model.

Aspect: Handling file changes
  • Alternative 1 (current choice): Remove files only on exit.

    • Pros: No need to deal with files when managing commands. Easy to execute add and delete commands without an issue without worrying whether a file is present.

    • Cons: Might take a while to delete if we had a lot of images. (Resolved with threads)

  • Alternative 2: Implement a recycle bin to move files to/from on command.

    • Pros: Commands do what they are fully expected to do (Delete deletes the image as well).

    • Cons: Heavily complicates the logic with a need to copy and paste when undoing and redoing. Very difficult to understand and error-prone. Still needs to eventually clear the recycle bin on exit. Repeated work.

  • Alternative 3: Make file-related commands undoable.

    • Pros: No need to deal with file manipulation.

    • Cons: Makes undo redo feature a lot more useless as it loses support for certain key commands.