Content
View differences
Updated by Marc Alcobé about 1 month ago
### **Original feedback**
_When recording time, there is no keyword search for "Activity". You can only scroll through the list. This is unmanageable when there are a large number of activities, as is the case with us._
### User Story
**As a** As a mobile app user
**I
I want to** to select an activity for time logging using search and a recent list
**so that**
so that I can find the right activity faster with fewer taps
### Acceptance Criteria
* The time logging flow includes an **Activity** selector that triggers a bottom sheet modal
* The Activity bottom sheet shows a **tabs** with two options: **All** and **Recent**
* The **All** tab is selected by default when the bottom sheet opens
* In the **All** tab, the list displays all activities available to the user for the selected work package (or for the time entry context currently being logged)
* In the **Recent** tab, the list displays only the most recently used activities by the user, ordered by most recent first
* The bottom sheet includes a **search input** at the top that can be focused immediately and accepts text input
* When the search query is non-empty, the list shows only matching activities within the currently selected tab (All or Recent)
* When the user types in the search input, the activity list is filtered in real time based on a case-insensitive “contains” match against the activity name
* If there are **no matches**, the list shows an explicit empty state message (use the existing blank slate for results: “**No matching results** - No results match your search term”) and shows no selectable rows
* Clearing the search input restores the unfiltered list for the selected tab
* Selecting an activity in either tab sets the activity on the time entry draft and closes the bottom sheet
* After an activity is selected (and the time entry is saved or confirmed according to current app behavior), that activity becomes the most recent activity for the user and appears at the top of the Recent tab
* The Recent tab does not contain duplicates. If an activity is selected again, it moves to the top of the Recent list
* The Recent list has a fixed maximum size (assumption: 15 items). When exceeded, the oldest item is removed
* If the user has no recent activities, the Recent tab is hidden
* The Activity list supports scrolling, and the search input and tab control remain visible while scrolling (sticky header behavior)
* If activities cannot be loaded due to connectivity or API errors, the UI shows a failure state, without crashing or blocking the entire time logging flow
### 3\. Technical Notes
* **Assumptions**
* “Activities” correspond to OpenProject time entry activities configured per project (or globally), and are selectable when creating/editing a time entry.
* The mobile app already fetches the available activity list for the time logging screen.
* **Data model (local)**
* Store a per-user “recent activities” list locally on-device.
* Data fields to store per recent item:
* Activity identifier (immutable ID)
* Activity name (cached for display)
* Last used timestamp
* Storage approach:
* iOS: UserDefaults or local persistence layer used by the app
* Android: SharedPreferences or local persistence layer used by the app
* Cache the activities on the first display load
* **API dependencies / contracts**
* Use existing API calls for fetching available activities (no new server API required for recents if stored locally).
* Search is client-side filtering of the already fetched activity list (avoid new “search activities” endpoint).
* If the activity list is context-dependent (project/work package), the All tab must reflect that same scope.
* **Frontend vs backend responsibilities**
* Frontend:
* Render bottom sheet, tabs, search input, list, empty states
* Apply filtering and ordering
* Persist and update recent activities locally after selection
* Backend:
* No change required unless activities are not currently available in the mobile time logging API
* **Performance and state**
* We could store the activities as cache when they are loaded and displayed on the first time already to have them available fast
* Handle activity lists up to a reasonable size (assumption: up to a few hundred) with performant list virtualization
* Ensure state is preserved during quick open/close cycles of the bottom sheet and device rotation (where applicable)
### Permissions and Visibility Considerations
* Only authenticated users can access time logging and the Activity selector
* The All tab only lists activities the user is permitted to use for time entries in the current context (project/work package)
* If the user lacks permission to log time, the Activity selector is not accessible (or the time logging UI is disabled) following existing app behavior
* The Recent list must never show activities that are no longer available in the All list for the current context
* If a recent activity is not currently available, it is hidden in Recent
### Translation Considerations
* Localize:
* Tab labels “All” and “Recent”
* Retry and error messages
### 6\. Out of Scope
* Server-side synchronization of recent activities across devices
* Favorites or pinned activities (separate from recents)
* Changes to the underlying set of activities available in OpenProject (configuration remains as-is)
_When recording time, there is no keyword search for "Activity". You can only scroll through the list. This is unmanageable when there are a large number of activities, as is the case with us._
### User Story
**As a**
**I
I
**so that**
so that
### Acceptance Criteria
* The time logging flow includes an **Activity** selector that triggers a bottom sheet modal
* The Activity bottom sheet shows a **tabs** with two options: **All** and **Recent**
* The **All** tab is selected by default when the bottom sheet opens
* In the **All** tab, the list displays all activities available to the user for the selected work package (or for the time entry context currently being logged)
* In the **Recent** tab, the list displays only the most recently used activities by the user, ordered by most recent first
* The bottom sheet includes a **search input** at the top that can be focused immediately and accepts text input
* When the search query is non-empty, the list shows only matching activities within the currently selected tab (All or Recent)
* When the user types in the search input, the activity list is filtered in real time based on a case-insensitive “contains” match against the activity name
* If there are **no matches**, the list shows an explicit empty state message (use the existing blank slate for results: “**No matching results** - No results match your search term”) and shows no selectable rows
* Clearing the search input restores the unfiltered list for the selected tab
* Selecting an activity in either tab sets the activity on the time entry draft and closes the bottom sheet
* After an activity is selected (and the time entry is saved or confirmed according to current app behavior), that activity becomes the most recent activity for the user and appears at the top of the Recent tab
* The Recent tab does not contain duplicates. If an activity is selected again, it moves to the top of the Recent list
* The Recent list has a fixed maximum size (assumption: 15 items). When exceeded, the oldest item is removed
* If the user has no recent activities, the Recent tab is hidden
* The Activity list supports scrolling, and the search input and tab control remain visible while scrolling (sticky header behavior)
* If activities cannot be loaded due to connectivity or API errors, the UI shows a failure state, without crashing or blocking the entire time logging flow
###
* **Assumptions**
* “Activities” correspond to OpenProject time entry activities configured per project (or globally), and are selectable when creating/editing a time entry.
* The mobile app already fetches the available activity list for the time logging screen.
* **Data model (local)**
* Store a per-user “recent activities” list locally on-device.
* Data fields to store per recent item:
* Activity identifier (immutable ID)
* Activity name
* Last used timestamp
* Storage approach:
* iOS: UserDefaults or local persistence layer used by the app
* Android: SharedPreferences or local persistence layer used by the app
* **API dependencies / contracts**
* Use existing API calls for fetching available activities (no new server API required for recents if stored locally).
* Search is client-side filtering of the already fetched activity list (avoid new “search activities” endpoint).
* If the activity list is context-dependent (project/work package), the All tab must reflect that same scope.
* **Frontend vs backend responsibilities**
* Frontend:
* Render bottom sheet, tabs, search input, list, empty states
* Apply filtering and ordering
* Persist and update recent activities locally after selection
* Backend:
* No change required unless activities are not currently available in the mobile time logging API
* **Performance and state**
* We could store the activities as cache when they are loaded and displayed on the first time already to have them available fast
* Handle activity lists up to a reasonable size (assumption: up to a few hundred) with performant list virtualization
* Ensure state is preserved during quick open/close cycles of the bottom sheet and device rotation (where applicable)
### Permissions and Visibility Considerations
* Only authenticated users can access time logging and the Activity selector
* The All tab only lists activities the user is permitted to use for time entries in the current context (project/work package)
* If the user lacks permission to log time, the Activity selector is not accessible (or the time logging UI is disabled) following existing app behavior
* The Recent list must never show activities that are no longer available in the All list for the current context
* If a recent activity is not currently available, it is hidden in Recent
### Translation Considerations
* Localize:
* Tab labels “All” and “Recent”
* Retry and error messages
###
* Server-side synchronization of recent activities across devices
* Favorites or pinned activities (separate from recents)
* Changes to the underlying set of activities available in OpenProject (configuration remains as-is)