-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IMAP Keywords #2668
IMAP Keywords #2668
Conversation
…x to allow all flags to be retrieved by valueOfByRealName() just in case.
Changes: * Current codebase has a new "FORWARDED" flag * Since Flag is no longer an enum, use another container (HashSet instead of EnumSet) * Direct (dumb) translation of ImapStore.search(). Don't quite like it right now. * Remove MessagingController.SYNC_FLAGS so that all flags are sync'd (not entirely sure this works the way I think it does, though).
Also, fix wrong translation of switch statement (must not break when encountering default flags).
Adds a label+field after "Cc:" listing all user-defined imap keywords in the message.
per artbristol's recommendation in issue 558
This maps name->Flag, to avoid duplication of objects, and adds a "tag name" attribute to the Flag class. The UI now uses this field instead of the name. The memory mapping is updated at every call to MessagingController.checkMailForAccount(). Probably not the right place.
This creates a very simple activity (shamelessly copying from FolderList) to present a listing of imap keywords and their corresponding tags from the memory map. Read-only, for now. To access the activity, click the Tags label (or any of the items) in the message header. Also, change Flag.REMEMBERED_KEYWORDS to LinkedHashMap to maintain iteration order.
User can edit the tag names for imap keywords that k-9 picks up when reading/syncing local messages. Usability still sucks and the UI has too many quirks (lost focus, cursor not updated, saving to memory only when leaving the activity...)
Tag names survive resets. Still barely usable: need somebody with actual android UI skills.
Features: * Message list: background shading using color of first tag * Message view: list of colored tag names; tap for tag choice dialog * Tag choice dialog: de-/select tags for message; changes are written to the IMAP sever; tap preferences icon for keyword editor * Keyword editor: change visibility, display name, color, order; add/remove keyword keywords: Drop TagDialog. keywords: Add new tag choice dialog. keywords: Add new keyword editor activity. keywords: Factor class Keyword out of Flag. keywords: Rename 'tag' to 'keyword' where is it not attached to a mail. keywords: Move keyword storage from account-specific LocalStore to k9-global Preferences. keywords: Move background color shading into Keyword and make it also work for the dark theme. keywords: Pick a random color for a new Keyword. keywords: Save newly created Keywords to preferences. keywords: Factor out parsing of comma-separated list of Flag codes. keywords: Drop tags label from MessageHeader. keywords: Separate font size of tags from cc in MessageHeader. keywords: Clean up MessagingController.syncFlags().
Thanks a lot for carrying the torch! I used to test this with a separate Application ID alongside my 'official' k-9 install, I'll see if I can dig up the patch I used for that and take a look at what's new. I'd just like to comment on (6), as a user.
I like AntennaPod's drag-and-drop reordering in the Queue activity, which is only triggered when you use the |
The empahsis has been on reducing k9mail-library's dependency on Android. So put the functionality in k9, possibly by implementing an interface exposed by the library. |
/** | ||
* Flags that can be applied to Messages. | ||
* | ||
* Terminology: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather see this go on the website's developer documentation than in the source, but I'm a clean-code-ist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me! For example, I could add a basic "Flags" or "Flags and Keywords" page to the Development section on https://k9mail.github.io/ or to the Wiki. What do you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you could make a PR for the website we can merge that in at the same time we do a release :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we go: See #55 for k9mail.github.io.
|
||
// Code for use in external storage, e.g. "\\Deleted" | ||
// For IMAP: A 'system flag' or a 'keyword' in terms of RFC 3501, 2.3.2. | ||
private final String externalCode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should think about WebDAV and EWS/EAS here a bit. Ideally we want the same flags in multiple stores.
} | ||
|
||
|
||
public static Keyword getKeywordByExternalCode(String externalCode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of static methods where you're storing and loading data, they are hard to test. I'd rather these move to a FlagsManager
class which is an application singleton.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have now created a FlagManager
that manages lookup of flags and keywords, as well as dynamic creation, deletion, and order of keywords. I left the creation (and the HashMap
s) of flags in the class Flag
, since the flags are all hard-coded, and I did not want to make their constructor public. There are still lookup methods in Flag
, but they no longer access Keyword
.
On the downside, the constructor of Keyword
and some other methods are now public, so that FlagManager
can access them. I could have made the manager a nested class of Keyword
, but since it manages not just keywords, but all kinds of flags, that appeared to be wrong. Also, some do-it-yourself friend construct seems to be over-the-top.
Oh, and I slightly preferred FlagManager
over FlagsManager
, but will happily change it, if you like. :-)
} else if (flag == Flag.FORWARDED | ||
&& (canCreateKeywords || store.getPermanentFlagsIndex().contains(Flag.FORWARDED))) { | ||
flagNames.add("$Forwarded"); | ||
// client's can't add the RECENT flag! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'clients'
@Override | ||
public View getView( | ||
final int position, View convertView, ViewGroup parent) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is way too long. It's a method for a class in a class that and contains multiple anonymous classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Now I refactored it and added a holder class to avoid repetition of one-time tasks. Still, the nested class KeywordEditorListAdapter has ~200 lines, which is almost half of the whole file. If desired, I can move the nested class into its own file.
|
||
Keyword tag = getItem(position); | ||
TextView tv = (TextView) convertView.findViewById( | ||
android.R.id.text1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
android.R.id.text1
Change this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
android.R.id.text1
comes from the built-in layout android.R.layout.simple_list_item_multiple_choice
. So, to change the former (for example to something like keyword_name
), I would need to add a local layout for the list item. I will happily change it! Could you please confirm that this approach is preferred over using the built-in layout?
} | ||
|
||
Keyword tag = getItem(position); | ||
TextView tv = (TextView) convertView.findViewById( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tv
Call this something more informative.
tv.setTextColor(tag.getTextColor()); | ||
} | ||
|
||
ListView lv = (ListView) parent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this something more informative.
Keyword.getVisibleKeywords(mMessage.getFlags())); | ||
fragment.show(getFragmentManager(), "tag_choice"); | ||
} catch (Exception e) { | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use logging instead of this.
@@ -340,6 +356,32 @@ public void populate(final Message message, final Account account) { | |||
mForwardedIcon.setVisibility(message.isSet(Flag.FORWARDED) ? View.VISIBLE : View.GONE); | |||
mFlagged.setChecked(message.isSet(Flag.FLAGGED)); | |||
|
|||
SpannableStringBuilder sb = new SpannableStringBuilder(); | |||
List<Keyword> tags = Keyword.getVisibleKeywords(msgFlags); | |||
if (tags.size() != 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create a helper method for this code.
…m setBackgroundColor()
Done with 5f89a65. |
Oh, I hope I did not make things unnecessarily complicated by merging the 'master' into the 'keywords'. I am still new to git and GitHub, and the big "Resolve Conflicts" button was quite tempting... If desired, I'll try to revert. :-/ @philipwhiuk Except for that, I think I have worked on almost all issues you raised. Thinking about keywords in WebDAV and EWS/EAS remains open. I hope I find some time in the next days. Any additional input on this issue is welcome. Please let me know, if I have missed anything else from your feedback! In addition, I still want to add some options to the global settings to enable/disable tag-based shading in the message list and tag names in the message view. But probably not today. |
I rebased this on current master, see https://github.com/k9mail/k-9/tree/Trogel-keywords. I noticed halfway through that you might have wanted to do this yourself, sorry if I've been hasty here :) |
Unfortunately 'invalid' currently includes keywords with a comma that are valid according to RFC 3501, 2.3.2, but that k-9 cannot handle.
@Valodim Fine with me! I hope it is okay that I still add a few changes here. You might want to merge them into Trogel-keywords. Except for my new commit eb25b31, the diff between Trogel-keywords and my branch is currently rather small. I just found two lines that you could drop from Trogel-keywords:
|
It probably makes sense to keep focus on this PR. I'd suggest you just |
@Valodim Did I get it right: Your idea is to, let's say, replace my merge with your rebase? So, the result would be as if I had rebased my branch and the PR. I'll happily do that, if desired, but I remember all these warnings like "Do not rebase commits that exist outside your repository" (from the Git Book) and "BadThingsWillHappen" (from k-9's GitGuide). Could you please confirm that rebasing the PR is the right thing do now? I already tried it in a local branch, and it seems I'd better |
Supporting three modes: always, never, if tags are assigned (default).
Options for tags added to global settings. Enjoy! :-) |
@Trogel, it's nice to see that someone is working on this. Thank you. I'm sorry for not chiming in earlier. After looking at the issues and previous attempts I feel like this is a feature that needs more consideration before attempting an implementation. The functionality spans a lot of areas and it's not obvious what the user experience should look like. After writing down where we want to go it should be easier to come up with the right abstractions for the code. Otherwise this will be just another instance where a feature is tightly coupled to code that shouldn't have to care about what the app does with the data. I've added my thought on this feature to issue #769. I'm tempted to close this PR because I believe it'll be easier to start over than to refactor this. |
Closing the pull request as suggested by @cketti. |
This is my attempt at issue #769. It started as a rebase of pull request #558. Many thanks to @igoralmeida and all other contributors! However, to avoid surprises: I assume I have turned almost everything upside down.
As of now I'd call this a working prototype. So I don't expect this go into k-9 without further changes. However, now would be a good time for me to get some feedback and guidance for further development.
Implemented features
New keywords found on emails are automatically added to the database, but by default they are hidden. To make them visible open an email, tap the tag list, tap the preferences icon, tap the visibility icon, and then tap the back button.
Some more things I'd like to add
Well, the list is getting long. It probably makes more sense to focus just on the fundamental functionality for now and leave additional fancy features for further pull requests.
Major design changes compared to #558
Open issues
Now for the open issues, where I am hoping for feedback and possibly some guidance:
https://github.com/JayH5/drag-sort-listview
https://github.com/justasm/DragLinearLayout