Add recents files to the document browser

The recents mechanism works like this:
Every time the file is opened, it saves that file to the shared
preferences set, by putting it in the first place, and removing the
oldest file from the list, if there are more than 4 recent files.

It also adds dynamic App Shortcuts if the device is 7.0 and above.
Screenshot: http://imgur.com/a/7kWOl

Edited the layout to add a new RecyclerView for recent items, as
well as the headers for both the recycler view's. Recent files
appear only if in home directory, below app bar and above the
file browser. This could be subjected to change in the future.
Screenshot of the recents section: http://imgur.com/a/qrqZq

Change-Id: I5c99aa26351d9ad2313e18b5b696d04a782e6155
Reviewed-on: https://gerrit.libreoffice.org/33759
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
Tested-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
This commit is contained in:
aleksandar-stefanovic 2017-01-31 17:18:57 +01:00 committed by Christian Lohmaier
parent ae1b9d55ee
commit 62cad676e9
5 changed files with 312 additions and 22 deletions

View File

@ -22,23 +22,67 @@
android:layout_height="match_parent">
<!-- The content -->
<android.support.v7.widget.RecyclerView
android:id="@+id/file_recycler_view"
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_normal"
android:orientation="vertical" />
android:layout_height="match_parent">
<!-- The navigation drawer -->
<android.support.design.widget.NavigationView
android:id="@+id/navigation_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/background_normal"
app:menu="@menu/navigation_menu"
android:theme="@style/LibreOfficeTheme.NavigationView" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:divider="@color/doorhanger_divider_light"
android:showDividers="middle">
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="@+id/header_recents"
android:text="@string/title_recents"
android:gravity="center_vertical"
android:textSize="14sp"
android:padding="16dp"
android:textStyle="bold"/>
<!--Recent files-->
<android.support.v7.widget.RecyclerView
android:id="@+id/list_recent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="@+id/header_browser"
android:text="@string/title_browser"
android:gravity="center_vertical"
android:textSize="14sp"
android:padding="16dp"
android:textStyle="bold" />
<!--Document browser-->
<android.support.v7.widget.RecyclerView
android:id="@+id/file_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_normal"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
<!-- The navigation drawer -->
<android.support.design.widget.NavigationView
android:id="@+id/navigation_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/background_normal"
app:menu="@menu/navigation_menu"
android:theme="@style/LibreOfficeTheme.NavigationView" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is part of the LibreOffice project.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground"
tools:ignore="UseCompoundDrawables">
<!--using compound drawables is ignored because more control over the drawable size is needed-->
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_gravity="center_vertical"
android:adjustViewBounds="true"
android:id="@+id/imageView"
android:contentDescription="@string/file_icon_desc"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/textView"
style="@style/ListItemText"/>
</LinearLayout>

View File

@ -31,6 +31,8 @@
<string name="menu_sort_modified">Sort by Date</string>
<string name="menu_preferences">Preferences</string>
<string name="file_icon_desc">fileicon</string>
<string name="title_recents">Recent files</string>
<string name="title_browser">All files</string>
<!-- Pref keys as resources ; Not currently used -->
<string name="EXPLORER_VIEW_TYPE_KEY">EXPLORER_VIEW_TYPE</string>
<string name="CURRENT_DIRECTORY_KEY">CURRENT_DIRECTORY</string>

View File

@ -14,11 +14,15 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
@ -43,10 +47,8 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.support.design.widget.NavigationView;
import org.libreoffice.AboutDialogFragment;
import org.libreoffice.LibreOfficeMainActivity;
@ -66,10 +68,12 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LibreOfficeUIActivity extends AppCompatActivity {
private String LOGTAG = LibreOfficeUIActivity.class.getSimpleName();
private static final String LOGTAG = LibreOfficeUIActivity.class.getSimpleName();
private SharedPreferences prefs;
private int filterMode = FileUtilities.ALL;
private int viewMode;
@ -85,11 +89,12 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
private int currentlySelectedFile;
private static final String CURRENT_DIRECTORY_KEY = "CURRENT_DIRECTORY";
private static final String DOC_PROIVDER_KEY = "CURRENT_DOCUMENT_PROVIDER";
private static final String DOC_PROVIDER_KEY = "CURRENT_DOCUMENT_PROVIDER";
private static final String FILTER_MODE_KEY = "FILTER_MODE";
public static final String EXPLORER_VIEW_TYPE_KEY = "EXPLORER_VIEW_TYPE";
public static final String EXPLORER_PREFS_KEY = "EXPLORER_PREFS";
public static final String SORT_MODE_KEY = "SORT_MODE";
private static final String RECENT_DOCUMENTS_KEY = "RECENT_DOCUMENTS";
public static final int GRID_VIEW = 0;
public static final int LIST_VIEW = 1;
@ -97,7 +102,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private NavigationView navigationDrawer;
private ActionBarDrawerToggle drawerToggle;
RecyclerView fileRecyclerView;
private RecyclerView fileRecyclerView;
private RecyclerView recentRecyclerView;
private boolean canQuit = false;
@ -151,7 +157,25 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
});
}
recentRecyclerView = (RecyclerView) findViewById(R.id.list_recent);
Set<String> recentFileStrings = prefs.getStringSet(RECENT_DOCUMENTS_KEY, new HashSet<String>());
final ArrayList<IFile> recentFiles = new ArrayList<IFile>();
for (String recentFileString : recentFileStrings) {
try {
recentFiles.add(documentProvider.createFromUri(new URI(recentFileString)));
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
recentRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
recentRecyclerView.setAdapter(new RecentFilesAdapter(this, recentFiles));
fileRecyclerView = (RecyclerView) findViewById(R.id.file_recycler_view);
//This should be tested because it possibly disables view recycling
fileRecyclerView.setNestedScrollingEnabled(false);
openDirectory(currentDirectory);
registerForContextMenu(fileRecyclerView);
@ -341,6 +365,18 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
if (dir == null)
return;
//show recent files if in home directory
if (dir.equals(homeDirectory)) {
recentRecyclerView.setVisibility(View.VISIBLE);
findViewById(R.id.header_browser).setVisibility((View.VISIBLE));
findViewById(R.id.header_recents).setVisibility((View.VISIBLE));
} else {
recentRecyclerView.setVisibility(View.GONE);
findViewById(R.id.header_browser).setVisibility((View.GONE));
findViewById(R.id.header_recents).setVisibility((View.GONE));
}
new AsyncTask<IFile, Void, Void>() {
@Override
protected Void doInBackground(IFile... dir) {
@ -374,6 +410,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
}
public void open(final IFile document) {
addDocumentToRecents(document);
new AsyncTask<IFile, Void, File>() {
@Override
protected File doInBackground(IFile... document) {
@ -640,7 +677,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
outState.putString(CURRENT_DIRECTORY_KEY, currentDirectory.getUri().toString());
outState.putInt(FILTER_MODE_KEY, filterMode);
outState.putInt(EXPLORER_VIEW_TYPE_KEY , viewMode);
outState.putInt(DOC_PROIVDER_KEY, documentProvider.getId());
outState.putInt(DOC_PROVIDER_KEY, documentProvider.getId());
Log.d(LOGTAG, currentDirectory.toString() + Integer.toString(filterMode) + Integer.toString(viewMode));
//prefs.edit().putInt(EXPLORER_VIEW_TYPE, viewType).commit();
@ -657,7 +694,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
if (documentProvider == null) {
Log.d(LOGTAG, "onRestoreInstanceState - documentProvider is null");
documentProvider = DocumentProviderFactory.getInstance()
.getProvider(savedInstanceState.getInt(DOC_PROIVDER_KEY));
.getProvider(savedInstanceState.getInt(DOC_PROVIDER_KEY));
}
try {
currentDirectory = documentProvider.createFromUri(new URI(
@ -710,6 +747,87 @@ public class LibreOfficeUIActivity extends AppCompatActivity {
return (int) (dp * scale + 0.5f);
}
private void addDocumentToRecents(IFile iFile) {
String newRecent = iFile.getUri().toString();
Set<String> recentsSet = prefs.getStringSet(RECENT_DOCUMENTS_KEY, new HashSet<String>());
//create array to work with
ArrayList<String> recentsArrayList = new ArrayList<String>(recentsSet);
//remove string if present, so that it doesn't appear multiple times
recentsSet.remove(newRecent);
//put the new value in the first place
recentsArrayList.add(0, newRecent);
/*
* 4 because the number of recommended items in App Shortcuts is 4, and also
* because it's a good number of recent items in general
*/
final int RECENTS_SIZE = 4;
while (recentsArrayList.size() > RECENTS_SIZE) {
recentsArrayList.remove(RECENTS_SIZE);
}
//switch to Set, so that it could be inserted into prefs
recentsSet = new HashSet<String>(recentsArrayList);
prefs.edit().putStringSet(RECENT_DOCUMENTS_KEY, recentsSet).apply();
//update app shortcuts (7.0 and above)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
//Remove all shortcuts, and apply new ones.
shortcutManager.removeAllDynamicShortcuts();
ArrayList<ShortcutInfo> shortcuts = new ArrayList<ShortcutInfo>();
for (String pathString : recentsArrayList) {
//find the appropriate drawable
int drawable = 0;
switch (FileUtilities.getType(pathString)) {
case FileUtilities.DOC:
drawable = R.drawable.writer;
break;
case FileUtilities.CALC:
drawable = R.drawable.calc;
break;
case FileUtilities.DRAWING:
drawable = R.drawable.draw;
break;
case FileUtilities.IMPRESS:
drawable = R.drawable.impress;
break;
}
File file = new File(pathString);
//for some reason, getName uses %20 instead of space
String filename = file.getName().replace("%20", " ");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromFile(file));
String packageName = this.getApplicationContext().getPackageName();
ComponentName componentName = new ComponentName(packageName, LibreOfficeMainActivity.class.getName());
intent.setComponent(componentName);
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, filename)
.setShortLabel(filename)
.setLongLabel(filename)
.setIcon(Icon.createWithResource(this, drawable))
.setIntent(intent)
.build();
shortcuts.add(shortcut);
}
shortcutManager.setDynamicShortcuts(shortcuts);
}
}
class ListItemAdapter extends RecyclerView.Adapter<ListItemAdapter.ViewHolder> {
private Activity mActivity;

View File

@ -0,0 +1,92 @@
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.libreoffice.ui;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.libreoffice.R;
import org.libreoffice.storage.IFile;
import java.util.List;
class RecentFilesAdapter extends RecyclerView.Adapter<RecentFilesAdapter.ViewHolder> {
private LibreOfficeUIActivity mActivity;
private List<IFile> recentFiles;
RecentFilesAdapter(LibreOfficeUIActivity activity, List<IFile> recentFiles) {
this.mActivity = activity;
this.recentFiles = recentFiles;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_recent_files, parent, false);
return new ViewHolder(item);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final IFile iFile = recentFiles.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mActivity.open(iFile);
}
});
String filename = iFile.getName();
holder.textView.setText(filename);
int compoundDrawableInt = 0;
switch (FileUtilities.getType(filename)) {
case FileUtilities.DOC:
compoundDrawableInt = R.drawable.writer;
break;
case FileUtilities.CALC:
compoundDrawableInt = R.drawable.calc;
break;
case FileUtilities.DRAWING:
compoundDrawableInt = R.drawable.draw;
break;
case FileUtilities.IMPRESS:
compoundDrawableInt = R.drawable.impress;
break;
}
holder.imageView.setImageDrawable(ContextCompat.getDrawable(mActivity, compoundDrawableInt));
}
@Override
public int getItemCount() {
return recentFiles.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
ViewHolder(View itemView) {
super(itemView);
this.textView = (TextView) itemView.findViewById(R.id.textView);
this.imageView = (ImageView) itemView.findViewById(R.id.imageView);
}
}
}