-
Notifications
You must be signed in to change notification settings - Fork 187
Discussion: Custom Fields
There have been a few requests for new fields:
- Date loaned
- Date to return
- Language
- Date purchased
- Maxi series (edit 31/1/2011) I think we should just allow multiple series per book as per LibraryThing
- No of copies
Some of these really foreshadowed improved features eg. Loan and return stuff could be enhanced and # of copies presupposes a solution to duplicate management.
But I wonder if there is any value in considering allowing the user to add fields at runtime. They would need to be limited to certain types etc...but is it worth pursuing as an idea?
I definitely think it is a good idea. However it is a major change. It has implications on the database as well as the interface. We would need to consider data types, entry methods, placements on screen and tabs, visibility controls, etc. Your thoughts?
We may need a forum or something for design discussions, but in the mean time, I'd suggest something along the lines of:
- . Define some limited data types we can support in the first version: integer, real, date, isbn and string, possibly with some basic validation on some of them (like a range for numbers). Maybe even just start with strings. Store these in a table called attribute_types (say). Handling of these types will be hard-coded somewhere.
- . Allow the user to create a new field for books. They provide:
- display name (eg. 'Date Eaten').
- unique id (string name that is less pretty) eg. 'date_eaten'
- the basic type (ed. 'Date' as above).
- limits (length for string, min/max for numbers)
- sort position
- (Store these in a table called book_attribute_definitions (say)).
- Alter the 'Comments' tab (or edit tab) to include the custom fields at the end. These will be appended accoring to the provided sort position followed by the name.
- Store the values in a table called book_attribute_values (say) when a book is edited.
- Consider adding an 'attribute_group' field on attributes. Then, when displaying attributes always put the same group on one line. This would handle fields like 'series' and 'series #' which look best on one line.
- (Maybe, perhaps in later version) Build a search/sort tool that allows queries to be constructed based on these attributes.
- Consider which, if any, existing attributes should become custom attributes.
- Consider, adding all existing attributes as 'intrinsic' types so that the search tool in 6 might be useable...
- Bear in mind that sorting and searching on these attributes will be slower. We may in fact want to build a real table using the unique attribute IDs then issue the relevant 'ALTER TABLE' commands when a new attribute is defined. In this case, I would start with a table book_attributes(id foregn key ref book) and just append/delete columns as necessary. We would still need book_attribute_definitions to define the type and rules for each attribute.
- In the first version, just start with strings and float. Do two types to reduce the temptation to make too many shortcuts. Ultimately define some other limited data types we can support: integer, date, isbn and string, possibly with some basic validation on some of them (like a range for numbers or a list for strings). Store these in a table called attribute_types (say). Handling of these types will be hard-coded somewhere.
- Version 5.0 introduced a BookData object, which is a layer on top of a Bundle and provides a load-from-cursor option; this would need to be extended to also load user-defined-fields from another cursor. Currently it loads a book from a cursor then gets series and authors. This would be easy to add.
- Many of our fields are pretty standard now: they have simple data entry, date-picker or a list-based button picker or editor. We can probably load the basic item from XML files, or build them manually.
- Add a new table 'field_specifications' (say) that includes a unique field ID for each of these fields as well as their position on the screen. Some will be fixed, eg. author, title & cover image always at top in position 1, 2, 3 in the 'Details' section. After that allow the users to edit position AND visibility of all fields (user-defined and intrinsic). This will replace the 'Manage Field Visibility' activity, and become 'Manage Fields'...with an 'Add' button.
- 'field_specifications' table will be something like (field_id (R.id value), group_id (details, notes), data_type (int), position (sort order in chosen group)) ).
- Simplify the XML files for the read-only view and for 'Details' and 'Notes' to load fields according to the order specified by the user. Keep the same-logic in the read-only code for auto-hiding empty fields. May need to split special intrinsic fields (like author, series, format, anthology , all dates, and cover thumbnail into special XML files to capture their special handling.
- For 'String' fields we may want to allow the user to specify 'edit in situ' (like comments) or 'edit-via-dialog' (like description).
- To make all this work we will need to dynamically set the ID on the new fields. These can only be IDs generated via resources. So we need to add generic 'R.id.custom_field_1' through (say) 'R.id.custom_field_20'.
- When a custom field is added, find the next unused R.id field, and use that as the global ID. Assign it a default position at the end of the 'Notes' tab. In the read-only view this is basically just above the 'Description' field.
- Handle 'intrinsic' fields based on static data structures in the app, load a full list from the database and sort/hide accordingly.
- Each user-defined field must have:
- Display name (the little grey headings we use). eg. 'Date Eaten'
- unique name (string name that is less pretty) eg. 'date_eaten' and will be used in CSV export & archiving
- sort position
- the basic type (eg. 'String' in the first instance. or 'Date' or maybe 'intrinsic' for app-defined ones).
- Later: limits (length for string, min/max for numbers)
- (Store these in a table called book_attribute_definitions (say)).
- Alter the 'Comments' tab (or edit tab) to include the custom fields at the end. These will be appended accoring to the provided sort position followed by the name.
- Store the values in a table called book_attribute_values (say) when a book is edited. They key would be the R.id value and the value would be the text/whatever representation.
- (Maybe, perhaps in later version) Build a search/sort tool that allows queries to be constructed based on these attributes. PEOPLE WILL ASK FOR THIS. I the short term, perhaps just add a 'Index this field' checkbox or dropdown.
- In the first instance, load the user-defined fields at display time as necessary. Do not display them in book lists.
- CSV Exports would need to dump custom fields with column names based on the 'unique_name' field. Imports would need to ignore data from custom fields that were not defined. Archives would need to restore custom fields before restoring the book data.
- Probably the very first step in doing this is to turn the edit and read-only views into dynamically generated layouts...it's also probably the hardest part.
Bear in mind that the design above seems to be the best end position. What we need are simple small steps to get there.
- Assume all fields Strings.
- Always add custom fields at end of 'Notes' tab, or above 'Description' in read-only mode.
- Add the 'R.id.custom_field_1' through (say) 'R.id.custom_field_20'.
- Add a 'field_specifications' table; something like (rowid long, field_id (R.id value), data_type (int, 0 = String?), display_name text, unique_name text).
- Dynamically add fields in onCreateView()
- Populate as above in BookData
- Add to Fields collection as appropriate
- Update CSV Import/Export to use the 'unique_name'. Ignore fields not defined in the database already.
This will probably get 90% of the user requirements without any of the fancy stuff. What we are missing is:
- Ability to show/hide
- Ability to set position
- Ability to validate
- Ability to set data types
If we're going to create R.id.custom_field_1 - R.id.custom_field_20, why not create custom_field_1 VARCHAR(255) - custom_field_20 VARCHAR(255) in the database. Piggybacks on all the existing code and we only need to write a rename wrapper around fields (which users could apply to any field).
Food for thought?