Loading app/core/src/main/java/com/fsck/k9/search/LocalSearch.java +22 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Parcelable; public class LocalSearch implements SearchSpecification { private String id; private String mName; private boolean mPredefined; private boolean mManualSearch = false; Loading Loading @@ -103,6 +104,16 @@ public class LocalSearch implements SearchSpecification { this.mName = name; } /** * Set the ID of the search. This is used to identify a unified inbox * search * * @param id ID to set */ public void setId(String id) { this.id = id; } /** * Add a new account to the search. When no accounts are * added manually we search all accounts on the device. Loading Loading @@ -301,6 +312,15 @@ public class LocalSearch implements SearchSpecification { return (mName == null) ? "" : mName; } /** * Returns the ID of the search * * @return The ID of the search */ public String getId() { return (id == null) ? "" : id; } /** * Checks if this search was hard coded and shipped with K-9 * Loading Loading @@ -364,6 +384,7 @@ public class LocalSearch implements SearchSpecification { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(id); dest.writeString(mName); dest.writeByte((byte) (mPredefined ? 1 : 0)); dest.writeByte((byte) (mManualSearch ? 1 : 0)); Loading @@ -386,6 +407,7 @@ public class LocalSearch implements SearchSpecification { }; public LocalSearch(Parcel in) { id = in.readString(); mName = in.readString(); mPredefined = (in.readByte() == 1); mManualSearch = (in.readByte() == 1); Loading app/core/src/main/java/com/fsck/k9/search/SearchAccount.java +1 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ public class SearchAccount implements BaseAccount { CoreResourceProvider resourceProvider = DI.get(CoreResourceProvider.class); String name = resourceProvider.searchUnifiedInboxTitle(); LocalSearch tmpSearch = new LocalSearch(name); tmpSearch.setId(UNIFIED_INBOX); tmpSearch.and(SearchField.INTEGRATE, "1", Attribute.EQUALS); return new SearchAccount(UNIFIED_INBOX, tmpSearch, name, resourceProvider.searchUnifiedInboxDetail()); } Loading app/ui/src/main/java/com/fsck/k9/activity/MessageList.java +31 −125 Original line number Diff line number Diff line package com.fsck.k9.activity; import java.util.ArrayList; import java.util.Collection; import java.util.List; Loading @@ -19,7 +18,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager.OnBackStackChangedListener; Loading @@ -27,7 +25,6 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; Loading @@ -46,13 +43,12 @@ import com.fsck.k9.DI; import com.fsck.k9.K9; import com.fsck.k9.K9.SplitViewMode; import com.fsck.k9.Preferences; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.helper.Contacts; import com.fsck.k9.ui.R; import com.fsck.k9.activity.compose.MessageActions; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.fragment.MessageListFragment; import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener; import com.fsck.k9.helper.Contacts; import com.fsck.k9.helper.ParcelableUtil; import com.fsck.k9.mailstore.Folder; import com.fsck.k9.mailstore.SearchStatusManager; Loading @@ -64,7 +60,8 @@ import com.fsck.k9.search.SearchSpecification; import com.fsck.k9.search.SearchSpecification.Attribute; import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.SearchField; import com.fsck.k9.ui.folders.FolderNameFormatter; import com.fsck.k9.ui.K9Drawer; import com.fsck.k9.ui.R; import com.fsck.k9.ui.messagelist.MessageListViewModel; import com.fsck.k9.ui.messagelist.MessageListViewModelFactory; import com.fsck.k9.ui.messageview.MessageViewFragment; Loading @@ -74,11 +71,7 @@ import com.fsck.k9.view.MessageHeader; import com.fsck.k9.view.MessageTitleView; import com.fsck.k9.view.ViewSwitcher; import com.fsck.k9.view.ViewSwitcher.OnSwitchCompleteListener; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.Drawer.OnDrawerListener; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import de.cketti.library.changelog.ChangeLog; import timber.log.Timber; Loading Loading @@ -169,12 +162,11 @@ public class MessageList extends K9Activity implements MessageListFragmentListen protected final SearchStatusManager searchStatusManager = DI.get(SearchStatusManager.class); private StorageManager.StorageListener mStorageListener = new StorageListenerImplementation(); private final FolderNameFormatter folderNameFormatter = DI.get(FolderNameFormatter.class); private final Preferences preferences = DI.get(Preferences.class); private ActionBar actionBar; private ActionBarDrawerToggle drawerToggle; private Drawer drawer; private K9Drawer drawer; private FragmentTransaction openFolderTransaction; private View actionBarMessageList; private View actionBarMessageView; Loading @@ -183,15 +175,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen private TextView actionBarSubTitle; private Menu menu; private int iconFolderInboxResId; private int iconFolderOutbotResId; private int iconFolderSentResId; private int iconFolderTrashResId; private int iconFolderDraftsResId; private int iconFolderArchiveResId; private int iconFolderSpamResId; private int iconFolderResId; private ViewGroup messageViewContainer; private View messageViewPlaceHolder; Loading @@ -202,7 +185,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen private Account account; private LocalSearch search; private boolean singleFolderMode; private String openedFolder; private boolean singleAccountMode; private ProgressBar actionBarProgress; Loading Loading @@ -252,7 +234,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen initializeActionBar(); initializeDrawer(savedInstanceState); initializeFolderIcons(); // Enable gesture detection for MessageLists setupGestureDetector(this); Loading @@ -268,7 +249,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen viewModel.getFolders(account).observe(this, new Observer<List<Folder>>() { @Override public void onChanged(@Nullable List<Folder> folders) { populateDrawerWithFolders(folders); drawer.setUserFolders(folders); } }); } Loading Loading @@ -494,7 +475,8 @@ public class MessageList extends K9Activity implements MessageListFragmentListen if (messageReference != null) { search = new LocalSearch(); search.addAccountUuid(messageReference.getAccountUuid()); search.addAllowedFolder(messageReference.getFolderServerId()); String folderServerId = messageReference.getFolderServerId(); search.addAllowedFolder(folderServerId); } if (search == null) { Loading Loading @@ -590,18 +572,9 @@ public class MessageList extends K9Activity implements MessageListFragmentListen return; } drawer = new DrawerBuilder() .withActivity(this) .withDisplayBelowStatusBar(false) .withTranslucentStatusBar(false) .withDrawerLayout(R.layout.material_drawer_fits_not) .withActionBarDrawerToggle(true) .withOnDrawerItemClickListener(createDrawerItemClickListener()) .withOnDrawerListener(createOnDrawerListener()) .withSavedInstance(savedInstanceState) .build(); drawer = new K9Drawer(this, savedInstanceState); DrawerLayout drawerLayout = drawer.getDrawerLayout(); DrawerLayout drawerLayout = drawer.getLayout(); drawerToggle = new ActionBarDrawerToggle( this, drawerLayout, null, R.string.navigation_drawer_open, R.string.navigation_drawer_close Loading @@ -610,19 +583,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen drawerToggle.syncState(); } @NonNull private Drawer.OnDrawerItemClickListener createDrawerItemClickListener() { return new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { Folder folder = (Folder) drawerItem.getTag(); openFolderTransaction = openFolder(folder.getServerId()); return false; } }; } private OnDrawerListener createOnDrawerListener() { public OnDrawerListener createOnDrawerListener() { return new OnDrawerListener() { @Override public void onDrawerClosed(View drawerView) { Loading @@ -644,83 +605,26 @@ public class MessageList extends K9Activity implements MessageListFragmentListen }; } private void populateDrawerWithFolders(@Nullable List<Folder> folders) { if (folders != null) { List<IDrawerItem> drawerItems = new ArrayList<>(folders.size()); long openedFolderId = -1; for (Folder folder : folders) { PrimaryDrawerItem item = new PrimaryDrawerItem() .withIcon(getFolderIcon(folder)) .withIdentifier(folder.getId()) .withTag(folder) .withName(getFolderDisplayName(folder)); drawerItems.add(item); if (folder.getServerId().equals(openedFolder)) { openedFolderId = folder.getId(); } } drawer.setItems(drawerItems); if (openedFolderId != -1) { drawer.setSelection(openedFolderId, false); } } else { drawer.removeAllItems(); } } private void initializeFolderIcons() { iconFolderInboxResId = getResId(R.attr.iconFolderInbox); iconFolderOutbotResId = getResId(R.attr.iconFolderOutbox); iconFolderSentResId = getResId(R.attr.iconFolderSent); iconFolderTrashResId = getResId(R.attr.iconFolderTrash); iconFolderDraftsResId = getResId(R.attr.iconFolderDrafts); iconFolderArchiveResId = getResId(R.attr.iconFolderArchive); iconFolderSpamResId = getResId(R.attr.iconFolderSpam); iconFolderResId = getResId(R.attr.iconFolder); } private int getResId(int resAttribute) { TypedValue typedValue = new TypedValue(); boolean found = getTheme().resolveAttribute(resAttribute, typedValue, true); if (!found) { throw new AssertionError("Couldn't find resource with attribute " + resAttribute); } return typedValue.resourceId; } public void openFolder(String folderName) { LocalSearch search = new LocalSearch(folderName); search.addAccountUuid(account.getUuid()); search.addAllowedFolder(folderName); private int getFolderIcon(Folder folder) { switch (folder.getType()) { case INBOX: return iconFolderInboxResId; case OUTBOX: return iconFolderOutbotResId; case SENT: return iconFolderSentResId; case TRASH: return iconFolderTrashResId; case DRAFTS: return iconFolderDraftsResId; case ARCHIVE: return iconFolderArchiveResId; case SPAM: return iconFolderSpamResId; default: return iconFolderResId; } performSearch(search); } private String getFolderDisplayName(Folder folder) { return folderNameFormatter.displayName(folder); public void openUnifiedInbox() { drawer.selectUnifiedInbox(); performSearch(SearchAccount.createUnifiedInboxAccount().getRelatedSearch()); } private FragmentTransaction openFolder(String folderName) { LocalSearch search = new LocalSearch(folderName); search.addAccountUuid(account.getUuid()); search.addAllowedFolder(folderName); private void performSearch(LocalSearch search) { initializeFromLocalSearch(search); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); openFolderTransaction = fragmentManager.beginTransaction(); messageListFragment = MessageListFragment.newInstance(search, false, K9.isThreadedViewEnabled()); ft.replace(R.id.message_list_container, messageListFragment); return ft; openFolderTransaction.replace(R.id.message_list_container, messageListFragment); } protected boolean isDrawerEnabled() { Loading Loading @@ -969,10 +873,10 @@ public class MessageList extends K9Activity implements MessageListFragmentListen if (id == android.R.id.home) { if (displayMode != DisplayMode.MESSAGE_VIEW && !isAdditionalMessageListDisplayed()) { if (isDrawerEnabled()) { if (drawer.isDrawerOpen()) { drawer.closeDrawer(); if (drawer.isOpen()) { drawer.close(); } else { drawer.openDrawer(); drawer.open(); } } else { finish(); Loading Loading @@ -1762,12 +1666,12 @@ public class MessageList extends K9Activity implements MessageListFragmentListen } private void lockDrawer() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); drawer.lock(); drawerToggle.setDrawerIndicatorEnabled(false); } private void unlockDrawer() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); drawer.unlock(); drawerToggle.setDrawerIndicatorEnabled(true); } Loading @@ -1791,9 +1695,11 @@ public class MessageList extends K9Activity implements MessageListFragmentListen List<String> folderServerIds = search.getFolderServerIds(); singleFolderMode = singleAccountMode && folderServerIds.size() == 1; if (singleFolderMode) { openedFolder = folderServerIds.get(0); drawer.selectFolder(folderServerIds.get(0)); } else if (search.getId().equals(SearchAccount.UNIFIED_INBOX)) { drawer.selectUnifiedInbox(); } else { openedFolder = null; drawer.selectFolder(null); } // now we know if we are in single account mode and need a subtitle Loading app/ui/src/main/java/com/fsck/k9/ui/K9Drawer.java 0 → 100644 +233 −0 Original line number Diff line number Diff line package com.fsck.k9.ui; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.widget.DrawerLayout; import android.util.TypedValue; import android.view.View; import com.fsck.k9.DI; import com.fsck.k9.K9; import com.fsck.k9.activity.MessageList; import com.fsck.k9.mailstore.Folder; import com.fsck.k9.ui.folders.FolderNameFormatter; import com.fsck.k9.ui.settings.SettingsActivity; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.Drawer.OnDrawerItemClickListener; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; public class K9Drawer { // Bit shift for identifiers of user folders items, to leave space for other items private static final short DRAWER_FOLDER_SHIFT = 2; private static final long DRAWER_ID_UNIFIED_INBOX = 0; private static final long DRAWER_ID_PREFERENCES = 1; private final FolderNameFormatter folderNameFormatter = DI.get(FolderNameFormatter.class); private final Drawer drawer; private final MessageList parent; private int headerItemCount = 0; private int iconFolderInboxResId; private int iconFolderOutboxResId; private int iconFolderSentResId; private int iconFolderTrashResId; private int iconFolderDraftsResId; private int iconFolderArchiveResId; private int iconFolderSpamResId; private int iconFolderResId; private final List<Long> userFolderDrawerIds = new ArrayList<>(); private boolean unifiedInboxSelected; private String openedFolderServerId; public K9Drawer(MessageList parent, Bundle savedInstanceState) { this.parent = parent; drawer = new DrawerBuilder() .withActivity(parent) .withDisplayBelowStatusBar(false) .withTranslucentStatusBar(false) .withDrawerLayout(R.layout.material_drawer_fits_not) .withActionBarDrawerToggle(true) .withOnDrawerItemClickListener(createItemClickListener()) .withOnDrawerListener(parent.createOnDrawerListener()) .withSavedInstance(savedInstanceState) .build(); addHeaderItems(); addFooterItems(); initializeFolderIcons(); } private void addHeaderItems() { if (!K9.isHideSpecialAccounts()) { drawer.addItems(new PrimaryDrawerItem() .withName(R.string.integrated_inbox_title) .withIcon(getResId(R.attr.iconUnifiedInbox)) .withIdentifier(DRAWER_ID_UNIFIED_INBOX), new DividerDrawerItem()); headerItemCount += 2; } } private void addFooterItems() { drawer.addItems(new DividerDrawerItem(), new PrimaryDrawerItem() .withName(R.string.preferences_action) .withIcon(getResId(R.attr.iconActionSettings)) .withIdentifier(DRAWER_ID_PREFERENCES) .withSelectable(false)); } private void initializeFolderIcons() { iconFolderInboxResId = getResId(R.attr.iconFolderInbox); iconFolderOutboxResId = getResId(R.attr.iconFolderOutbox); iconFolderSentResId = getResId(R.attr.iconFolderSent); iconFolderTrashResId = getResId(R.attr.iconFolderTrash); iconFolderDraftsResId = getResId(R.attr.iconFolderDrafts); iconFolderArchiveResId = getResId(R.attr.iconFolderArchive); iconFolderSpamResId = getResId(R.attr.iconFolderSpam); iconFolderResId = getResId(R.attr.iconFolder); } private int getResId(int resAttribute) { TypedValue typedValue = new TypedValue(); boolean found = parent.getTheme().resolveAttribute(resAttribute, typedValue, true); if (!found) { throw new AssertionError("Couldn't find resource with attribute " + resAttribute); } return typedValue.resourceId; } private int getFolderIcon(Folder folder) { switch (folder.getType()) { case INBOX: return iconFolderInboxResId; case OUTBOX: return iconFolderOutboxResId; case SENT: return iconFolderSentResId; case TRASH: return iconFolderTrashResId; case DRAFTS: return iconFolderDraftsResId; case ARCHIVE: return iconFolderArchiveResId; case SPAM: return iconFolderSpamResId; default: return iconFolderResId; } } private String getFolderDisplayName(Folder folder) { return folderNameFormatter.displayName(folder); } private OnDrawerItemClickListener createItemClickListener() { return new OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { long id = drawerItem.getIdentifier(); if (id == DRAWER_ID_UNIFIED_INBOX) { parent.openUnifiedInbox(); return false; } else if (id == DRAWER_ID_PREFERENCES) { SettingsActivity.launch(parent); return false; } Folder folder = (Folder) drawerItem.getTag(); parent.openFolder(folder.getServerId()); return false; } }; } public void setUserFolders(@Nullable List<Folder> folders) { clearUserFolders(); if (folders == null) { return; } long openedFolderDrawerId = -1; for (int i = folders.size() - 1; i >= 0; i--) { Folder folder = folders.get(i); long drawerId = folder.getId() << DRAWER_FOLDER_SHIFT; drawer.addItemAtPosition(new PrimaryDrawerItem() .withIcon(getFolderIcon(folder)) .withIdentifier(drawerId) .withTag(folder) .withName(getFolderDisplayName(folder)), headerItemCount); userFolderDrawerIds.add(drawerId); if (folder.getServerId().equals(openedFolderServerId)) { openedFolderDrawerId = drawerId; } } if (openedFolderDrawerId != -1) { drawer.setSelection(openedFolderDrawerId, false); } else if (unifiedInboxSelected) { selectUnifiedInbox(); } } private void clearUserFolders() { for (long drawerId : userFolderDrawerIds) { drawer.removeItem(drawerId); } userFolderDrawerIds.clear(); } public void selectFolder(String folderServerId) { unifiedInboxSelected = false; openedFolderServerId = folderServerId; for (long drawerId : userFolderDrawerIds) { Folder folder = (Folder) drawer.getDrawerItem(drawerId).getTag(); if (folder.getServerId().equals(folderServerId)) { drawer.setSelection(drawerId, false); return; } } } public void selectUnifiedInbox() { unifiedInboxSelected = true; openedFolderServerId = null; drawer.setSelection(DRAWER_ID_UNIFIED_INBOX, false); } public DrawerLayout getLayout() { return drawer.getDrawerLayout(); } public boolean isOpen() { return drawer.isDrawerOpen(); } public void open() { drawer.openDrawer(); } public void close() { drawer.closeDrawer(); } public void lock() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } public void unlock() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } } app/ui/src/main/res/drawable-anydpi/ic_inbox_multiple_dark.xml 0 → 100644 +7 −0 Original line number Diff line number Diff line <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> <path android:fillColor="#fff" android:pathData="M19 3H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 6h-4c0 1.62-1.38 3-3 3s-3-1.38-3-3H5V5h14v4zm-4 7h6v3c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2v-3h6c0 1.66 1.34 3 3 3s3-1.34 3-3z" /> </vector> Loading
app/core/src/main/java/com/fsck/k9/search/LocalSearch.java +22 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Parcelable; public class LocalSearch implements SearchSpecification { private String id; private String mName; private boolean mPredefined; private boolean mManualSearch = false; Loading Loading @@ -103,6 +104,16 @@ public class LocalSearch implements SearchSpecification { this.mName = name; } /** * Set the ID of the search. This is used to identify a unified inbox * search * * @param id ID to set */ public void setId(String id) { this.id = id; } /** * Add a new account to the search. When no accounts are * added manually we search all accounts on the device. Loading Loading @@ -301,6 +312,15 @@ public class LocalSearch implements SearchSpecification { return (mName == null) ? "" : mName; } /** * Returns the ID of the search * * @return The ID of the search */ public String getId() { return (id == null) ? "" : id; } /** * Checks if this search was hard coded and shipped with K-9 * Loading Loading @@ -364,6 +384,7 @@ public class LocalSearch implements SearchSpecification { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(id); dest.writeString(mName); dest.writeByte((byte) (mPredefined ? 1 : 0)); dest.writeByte((byte) (mManualSearch ? 1 : 0)); Loading @@ -386,6 +407,7 @@ public class LocalSearch implements SearchSpecification { }; public LocalSearch(Parcel in) { id = in.readString(); mName = in.readString(); mPredefined = (in.readByte() == 1); mManualSearch = (in.readByte() == 1); Loading
app/core/src/main/java/com/fsck/k9/search/SearchAccount.java +1 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ public class SearchAccount implements BaseAccount { CoreResourceProvider resourceProvider = DI.get(CoreResourceProvider.class); String name = resourceProvider.searchUnifiedInboxTitle(); LocalSearch tmpSearch = new LocalSearch(name); tmpSearch.setId(UNIFIED_INBOX); tmpSearch.and(SearchField.INTEGRATE, "1", Attribute.EQUALS); return new SearchAccount(UNIFIED_INBOX, tmpSearch, name, resourceProvider.searchUnifiedInboxDetail()); } Loading
app/ui/src/main/java/com/fsck/k9/activity/MessageList.java +31 −125 Original line number Diff line number Diff line package com.fsck.k9.activity; import java.util.ArrayList; import java.util.Collection; import java.util.List; Loading @@ -19,7 +18,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager.OnBackStackChangedListener; Loading @@ -27,7 +25,6 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; Loading @@ -46,13 +43,12 @@ import com.fsck.k9.DI; import com.fsck.k9.K9; import com.fsck.k9.K9.SplitViewMode; import com.fsck.k9.Preferences; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.helper.Contacts; import com.fsck.k9.ui.R; import com.fsck.k9.activity.compose.MessageActions; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.fragment.MessageListFragment; import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener; import com.fsck.k9.helper.Contacts; import com.fsck.k9.helper.ParcelableUtil; import com.fsck.k9.mailstore.Folder; import com.fsck.k9.mailstore.SearchStatusManager; Loading @@ -64,7 +60,8 @@ import com.fsck.k9.search.SearchSpecification; import com.fsck.k9.search.SearchSpecification.Attribute; import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.SearchField; import com.fsck.k9.ui.folders.FolderNameFormatter; import com.fsck.k9.ui.K9Drawer; import com.fsck.k9.ui.R; import com.fsck.k9.ui.messagelist.MessageListViewModel; import com.fsck.k9.ui.messagelist.MessageListViewModelFactory; import com.fsck.k9.ui.messageview.MessageViewFragment; Loading @@ -74,11 +71,7 @@ import com.fsck.k9.view.MessageHeader; import com.fsck.k9.view.MessageTitleView; import com.fsck.k9.view.ViewSwitcher; import com.fsck.k9.view.ViewSwitcher.OnSwitchCompleteListener; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.Drawer.OnDrawerListener; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import de.cketti.library.changelog.ChangeLog; import timber.log.Timber; Loading Loading @@ -169,12 +162,11 @@ public class MessageList extends K9Activity implements MessageListFragmentListen protected final SearchStatusManager searchStatusManager = DI.get(SearchStatusManager.class); private StorageManager.StorageListener mStorageListener = new StorageListenerImplementation(); private final FolderNameFormatter folderNameFormatter = DI.get(FolderNameFormatter.class); private final Preferences preferences = DI.get(Preferences.class); private ActionBar actionBar; private ActionBarDrawerToggle drawerToggle; private Drawer drawer; private K9Drawer drawer; private FragmentTransaction openFolderTransaction; private View actionBarMessageList; private View actionBarMessageView; Loading @@ -183,15 +175,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen private TextView actionBarSubTitle; private Menu menu; private int iconFolderInboxResId; private int iconFolderOutbotResId; private int iconFolderSentResId; private int iconFolderTrashResId; private int iconFolderDraftsResId; private int iconFolderArchiveResId; private int iconFolderSpamResId; private int iconFolderResId; private ViewGroup messageViewContainer; private View messageViewPlaceHolder; Loading @@ -202,7 +185,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen private Account account; private LocalSearch search; private boolean singleFolderMode; private String openedFolder; private boolean singleAccountMode; private ProgressBar actionBarProgress; Loading Loading @@ -252,7 +234,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen initializeActionBar(); initializeDrawer(savedInstanceState); initializeFolderIcons(); // Enable gesture detection for MessageLists setupGestureDetector(this); Loading @@ -268,7 +249,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen viewModel.getFolders(account).observe(this, new Observer<List<Folder>>() { @Override public void onChanged(@Nullable List<Folder> folders) { populateDrawerWithFolders(folders); drawer.setUserFolders(folders); } }); } Loading Loading @@ -494,7 +475,8 @@ public class MessageList extends K9Activity implements MessageListFragmentListen if (messageReference != null) { search = new LocalSearch(); search.addAccountUuid(messageReference.getAccountUuid()); search.addAllowedFolder(messageReference.getFolderServerId()); String folderServerId = messageReference.getFolderServerId(); search.addAllowedFolder(folderServerId); } if (search == null) { Loading Loading @@ -590,18 +572,9 @@ public class MessageList extends K9Activity implements MessageListFragmentListen return; } drawer = new DrawerBuilder() .withActivity(this) .withDisplayBelowStatusBar(false) .withTranslucentStatusBar(false) .withDrawerLayout(R.layout.material_drawer_fits_not) .withActionBarDrawerToggle(true) .withOnDrawerItemClickListener(createDrawerItemClickListener()) .withOnDrawerListener(createOnDrawerListener()) .withSavedInstance(savedInstanceState) .build(); drawer = new K9Drawer(this, savedInstanceState); DrawerLayout drawerLayout = drawer.getDrawerLayout(); DrawerLayout drawerLayout = drawer.getLayout(); drawerToggle = new ActionBarDrawerToggle( this, drawerLayout, null, R.string.navigation_drawer_open, R.string.navigation_drawer_close Loading @@ -610,19 +583,7 @@ public class MessageList extends K9Activity implements MessageListFragmentListen drawerToggle.syncState(); } @NonNull private Drawer.OnDrawerItemClickListener createDrawerItemClickListener() { return new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { Folder folder = (Folder) drawerItem.getTag(); openFolderTransaction = openFolder(folder.getServerId()); return false; } }; } private OnDrawerListener createOnDrawerListener() { public OnDrawerListener createOnDrawerListener() { return new OnDrawerListener() { @Override public void onDrawerClosed(View drawerView) { Loading @@ -644,83 +605,26 @@ public class MessageList extends K9Activity implements MessageListFragmentListen }; } private void populateDrawerWithFolders(@Nullable List<Folder> folders) { if (folders != null) { List<IDrawerItem> drawerItems = new ArrayList<>(folders.size()); long openedFolderId = -1; for (Folder folder : folders) { PrimaryDrawerItem item = new PrimaryDrawerItem() .withIcon(getFolderIcon(folder)) .withIdentifier(folder.getId()) .withTag(folder) .withName(getFolderDisplayName(folder)); drawerItems.add(item); if (folder.getServerId().equals(openedFolder)) { openedFolderId = folder.getId(); } } drawer.setItems(drawerItems); if (openedFolderId != -1) { drawer.setSelection(openedFolderId, false); } } else { drawer.removeAllItems(); } } private void initializeFolderIcons() { iconFolderInboxResId = getResId(R.attr.iconFolderInbox); iconFolderOutbotResId = getResId(R.attr.iconFolderOutbox); iconFolderSentResId = getResId(R.attr.iconFolderSent); iconFolderTrashResId = getResId(R.attr.iconFolderTrash); iconFolderDraftsResId = getResId(R.attr.iconFolderDrafts); iconFolderArchiveResId = getResId(R.attr.iconFolderArchive); iconFolderSpamResId = getResId(R.attr.iconFolderSpam); iconFolderResId = getResId(R.attr.iconFolder); } private int getResId(int resAttribute) { TypedValue typedValue = new TypedValue(); boolean found = getTheme().resolveAttribute(resAttribute, typedValue, true); if (!found) { throw new AssertionError("Couldn't find resource with attribute " + resAttribute); } return typedValue.resourceId; } public void openFolder(String folderName) { LocalSearch search = new LocalSearch(folderName); search.addAccountUuid(account.getUuid()); search.addAllowedFolder(folderName); private int getFolderIcon(Folder folder) { switch (folder.getType()) { case INBOX: return iconFolderInboxResId; case OUTBOX: return iconFolderOutbotResId; case SENT: return iconFolderSentResId; case TRASH: return iconFolderTrashResId; case DRAFTS: return iconFolderDraftsResId; case ARCHIVE: return iconFolderArchiveResId; case SPAM: return iconFolderSpamResId; default: return iconFolderResId; } performSearch(search); } private String getFolderDisplayName(Folder folder) { return folderNameFormatter.displayName(folder); public void openUnifiedInbox() { drawer.selectUnifiedInbox(); performSearch(SearchAccount.createUnifiedInboxAccount().getRelatedSearch()); } private FragmentTransaction openFolder(String folderName) { LocalSearch search = new LocalSearch(folderName); search.addAccountUuid(account.getUuid()); search.addAllowedFolder(folderName); private void performSearch(LocalSearch search) { initializeFromLocalSearch(search); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); openFolderTransaction = fragmentManager.beginTransaction(); messageListFragment = MessageListFragment.newInstance(search, false, K9.isThreadedViewEnabled()); ft.replace(R.id.message_list_container, messageListFragment); return ft; openFolderTransaction.replace(R.id.message_list_container, messageListFragment); } protected boolean isDrawerEnabled() { Loading Loading @@ -969,10 +873,10 @@ public class MessageList extends K9Activity implements MessageListFragmentListen if (id == android.R.id.home) { if (displayMode != DisplayMode.MESSAGE_VIEW && !isAdditionalMessageListDisplayed()) { if (isDrawerEnabled()) { if (drawer.isDrawerOpen()) { drawer.closeDrawer(); if (drawer.isOpen()) { drawer.close(); } else { drawer.openDrawer(); drawer.open(); } } else { finish(); Loading Loading @@ -1762,12 +1666,12 @@ public class MessageList extends K9Activity implements MessageListFragmentListen } private void lockDrawer() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); drawer.lock(); drawerToggle.setDrawerIndicatorEnabled(false); } private void unlockDrawer() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); drawer.unlock(); drawerToggle.setDrawerIndicatorEnabled(true); } Loading @@ -1791,9 +1695,11 @@ public class MessageList extends K9Activity implements MessageListFragmentListen List<String> folderServerIds = search.getFolderServerIds(); singleFolderMode = singleAccountMode && folderServerIds.size() == 1; if (singleFolderMode) { openedFolder = folderServerIds.get(0); drawer.selectFolder(folderServerIds.get(0)); } else if (search.getId().equals(SearchAccount.UNIFIED_INBOX)) { drawer.selectUnifiedInbox(); } else { openedFolder = null; drawer.selectFolder(null); } // now we know if we are in single account mode and need a subtitle Loading
app/ui/src/main/java/com/fsck/k9/ui/K9Drawer.java 0 → 100644 +233 −0 Original line number Diff line number Diff line package com.fsck.k9.ui; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.widget.DrawerLayout; import android.util.TypedValue; import android.view.View; import com.fsck.k9.DI; import com.fsck.k9.K9; import com.fsck.k9.activity.MessageList; import com.fsck.k9.mailstore.Folder; import com.fsck.k9.ui.folders.FolderNameFormatter; import com.fsck.k9.ui.settings.SettingsActivity; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.Drawer.OnDrawerItemClickListener; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; public class K9Drawer { // Bit shift for identifiers of user folders items, to leave space for other items private static final short DRAWER_FOLDER_SHIFT = 2; private static final long DRAWER_ID_UNIFIED_INBOX = 0; private static final long DRAWER_ID_PREFERENCES = 1; private final FolderNameFormatter folderNameFormatter = DI.get(FolderNameFormatter.class); private final Drawer drawer; private final MessageList parent; private int headerItemCount = 0; private int iconFolderInboxResId; private int iconFolderOutboxResId; private int iconFolderSentResId; private int iconFolderTrashResId; private int iconFolderDraftsResId; private int iconFolderArchiveResId; private int iconFolderSpamResId; private int iconFolderResId; private final List<Long> userFolderDrawerIds = new ArrayList<>(); private boolean unifiedInboxSelected; private String openedFolderServerId; public K9Drawer(MessageList parent, Bundle savedInstanceState) { this.parent = parent; drawer = new DrawerBuilder() .withActivity(parent) .withDisplayBelowStatusBar(false) .withTranslucentStatusBar(false) .withDrawerLayout(R.layout.material_drawer_fits_not) .withActionBarDrawerToggle(true) .withOnDrawerItemClickListener(createItemClickListener()) .withOnDrawerListener(parent.createOnDrawerListener()) .withSavedInstance(savedInstanceState) .build(); addHeaderItems(); addFooterItems(); initializeFolderIcons(); } private void addHeaderItems() { if (!K9.isHideSpecialAccounts()) { drawer.addItems(new PrimaryDrawerItem() .withName(R.string.integrated_inbox_title) .withIcon(getResId(R.attr.iconUnifiedInbox)) .withIdentifier(DRAWER_ID_UNIFIED_INBOX), new DividerDrawerItem()); headerItemCount += 2; } } private void addFooterItems() { drawer.addItems(new DividerDrawerItem(), new PrimaryDrawerItem() .withName(R.string.preferences_action) .withIcon(getResId(R.attr.iconActionSettings)) .withIdentifier(DRAWER_ID_PREFERENCES) .withSelectable(false)); } private void initializeFolderIcons() { iconFolderInboxResId = getResId(R.attr.iconFolderInbox); iconFolderOutboxResId = getResId(R.attr.iconFolderOutbox); iconFolderSentResId = getResId(R.attr.iconFolderSent); iconFolderTrashResId = getResId(R.attr.iconFolderTrash); iconFolderDraftsResId = getResId(R.attr.iconFolderDrafts); iconFolderArchiveResId = getResId(R.attr.iconFolderArchive); iconFolderSpamResId = getResId(R.attr.iconFolderSpam); iconFolderResId = getResId(R.attr.iconFolder); } private int getResId(int resAttribute) { TypedValue typedValue = new TypedValue(); boolean found = parent.getTheme().resolveAttribute(resAttribute, typedValue, true); if (!found) { throw new AssertionError("Couldn't find resource with attribute " + resAttribute); } return typedValue.resourceId; } private int getFolderIcon(Folder folder) { switch (folder.getType()) { case INBOX: return iconFolderInboxResId; case OUTBOX: return iconFolderOutboxResId; case SENT: return iconFolderSentResId; case TRASH: return iconFolderTrashResId; case DRAFTS: return iconFolderDraftsResId; case ARCHIVE: return iconFolderArchiveResId; case SPAM: return iconFolderSpamResId; default: return iconFolderResId; } } private String getFolderDisplayName(Folder folder) { return folderNameFormatter.displayName(folder); } private OnDrawerItemClickListener createItemClickListener() { return new OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { long id = drawerItem.getIdentifier(); if (id == DRAWER_ID_UNIFIED_INBOX) { parent.openUnifiedInbox(); return false; } else if (id == DRAWER_ID_PREFERENCES) { SettingsActivity.launch(parent); return false; } Folder folder = (Folder) drawerItem.getTag(); parent.openFolder(folder.getServerId()); return false; } }; } public void setUserFolders(@Nullable List<Folder> folders) { clearUserFolders(); if (folders == null) { return; } long openedFolderDrawerId = -1; for (int i = folders.size() - 1; i >= 0; i--) { Folder folder = folders.get(i); long drawerId = folder.getId() << DRAWER_FOLDER_SHIFT; drawer.addItemAtPosition(new PrimaryDrawerItem() .withIcon(getFolderIcon(folder)) .withIdentifier(drawerId) .withTag(folder) .withName(getFolderDisplayName(folder)), headerItemCount); userFolderDrawerIds.add(drawerId); if (folder.getServerId().equals(openedFolderServerId)) { openedFolderDrawerId = drawerId; } } if (openedFolderDrawerId != -1) { drawer.setSelection(openedFolderDrawerId, false); } else if (unifiedInboxSelected) { selectUnifiedInbox(); } } private void clearUserFolders() { for (long drawerId : userFolderDrawerIds) { drawer.removeItem(drawerId); } userFolderDrawerIds.clear(); } public void selectFolder(String folderServerId) { unifiedInboxSelected = false; openedFolderServerId = folderServerId; for (long drawerId : userFolderDrawerIds) { Folder folder = (Folder) drawer.getDrawerItem(drawerId).getTag(); if (folder.getServerId().equals(folderServerId)) { drawer.setSelection(drawerId, false); return; } } } public void selectUnifiedInbox() { unifiedInboxSelected = true; openedFolderServerId = null; drawer.setSelection(DRAWER_ID_UNIFIED_INBOX, false); } public DrawerLayout getLayout() { return drawer.getDrawerLayout(); } public boolean isOpen() { return drawer.isDrawerOpen(); } public void open() { drawer.openDrawer(); } public void close() { drawer.closeDrawer(); } public void lock() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } public void unlock() { drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } }
app/ui/src/main/res/drawable-anydpi/ic_inbox_multiple_dark.xml 0 → 100644 +7 −0 Original line number Diff line number Diff line <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> <path android:fillColor="#fff" android:pathData="M19 3H5c-1.1 0-2 .9-2 2v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 6h-4c0 1.62-1.38 3-3 3s-3-1.38-3-3H5V5h14v4zm-4 7h6v3c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2v-3h6c0 1.66 1.34 3 3 3s3-1.34 3-3z" /> </vector>