diff options
author | Size43 | 2015-06-03 12:36:04 +0200 |
---|---|---|
committer | Size43 | 2015-06-03 12:36:04 +0200 |
commit | 0b5a12e523d90b3721d1b310283dff655dcccee5 (patch) | |
tree | 3972b88a11f96c56a2f051ad7f67a1f3cf8b7952 /app/src | |
parent | Strings.xml (diff) | |
parent | Error handling ArticleActivity (diff) |
merge
Diffstat (limited to 'app/src')
37 files changed, 1038 insertions, 257 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 58a53b3..d572cc5 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,11 +12,6 @@ <activity android:name="org.rssin.android.UnifiedInboxActivity" android:label="@string/title_activity_unifiedinbox" > - <intent-filter android:label="@string/app_name" > - <action android:name="android.intent.action.MAIN" /> - - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> </activity> <activity android:name="org.rssin.android.SettingsActivity" @@ -57,6 +52,15 @@ android:name="org.rssin.android.ArticleActivity" android:label="@string/title_activity_article" > </activity> + <activity + android:name="org.rssin.android.HomeScreenActivity" + android:label="@string/title_activity_home_screen" > + <intent-filter android:label="@string/app_name" > + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> </application> </manifest> diff --git a/app/src/main/java/org/rssin/android/ArticleActivity.java b/app/src/main/java/org/rssin/android/ArticleActivity.java index 2e5460c..7d9fa2b 100755 --- a/app/src/main/java/org/rssin/android/ArticleActivity.java +++ b/app/src/main/java/org/rssin/android/ArticleActivity.java @@ -24,18 +24,35 @@ public class ArticleActivity extends ActionBarActivity { Intent intent = getIntent(); Bundle arguments = intent.getExtras(); container = (SortedFeedItemContainer) arguments.getSerializable("item"); - FeedItem item = container.getFeeditem(); + try { + FeedItem item = container.getFeeditem(); - TextView title = (TextView) findViewById(R.id.article_title); - title.setText(item.getTitle()); - TextView description = (TextView) findViewById(R.id.article_description); - description.setText(Html.fromHtml(item.getDescription())); - TextView author = (TextView) findViewById(R.id.article_author); - author.setText("Written by: " + item.getAuthor()); - TextView date = (TextView) findViewById(R.id.article_date); - date.setText("Published on: " + item.getPubDate().toString()); + TextView title = (TextView) findViewById(R.id.article_title); + title.setText(item.getTitle()); + setTitle(item.getTitle()); - new Thread(new FeedSorterTrainer(container.getSorter())).start(); + TextView description = (TextView) findViewById(R.id.article_description); + description.setText(Html.fromHtml(item.getDescription())); + + TextView author = (TextView) findViewById(R.id.article_author); + if (item.getAuthor() != null) { + author.setText(getResources().getString(R.string.article_author) + " " + item.getAuthor()); + } else { + author.setText(R.string.article_author_unknown); + } + + TextView date = (TextView) findViewById(R.id.article_date); + if (item.getPubDate() != null) { + date.setText(getResources().getString(R.string.article_published_on) + " " + item.getPubDate().toString()); + } else { + date.setText(R.string.article_published_on_unknown); + } + + new Thread(new FeedSorterTrainer(container.getSorter())).start(); + } catch (NullPointerException e) { + Frontend.error(this, R.string.error_load_article, e); + finish(); + } } @Override diff --git a/app/src/main/java/org/rssin/android/FilterActivity.java b/app/src/main/java/org/rssin/android/FilterActivity.java index 5003cfb..189fd55 100755 --- a/app/src/main/java/org/rssin/android/FilterActivity.java +++ b/app/src/main/java/org/rssin/android/FilterActivity.java @@ -45,7 +45,7 @@ public class FilterActivity extends ActionBarActivity { // @todo Check on -1? Shouldn't happen anyway. filter = filtersList.getFilterFromHashCode(filterHashCode); - filter.ensureFeedSorter(DefaultStorageProvider.getInstance(this)); + filter.ensureFeedSorter(InternalStorageProvider.getInstance(this)); setTitle(filter.getTitle()); @@ -90,7 +90,7 @@ public class FilterActivity extends ActionBarActivity { protected void onDestroy() { super.onDestroy(); try { - filter.storeFeedSorter(DefaultStorageProvider.getInstance(this)); + filter.storeFeedSorter(InternalStorageProvider.getInstance(this)); } catch (Exception e) { Frontend.warning(this, R.string.error_save_feedsorter, e); } diff --git a/app/src/main/java/org/rssin/android/FilterSettingsActivity.java b/app/src/main/java/org/rssin/android/FilterSettingsActivity.java index 296d2e5..931a86c 100755 --- a/app/src/main/java/org/rssin/android/FilterSettingsActivity.java +++ b/app/src/main/java/org/rssin/android/FilterSettingsActivity.java @@ -18,9 +18,11 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import org.rssin.rssin.Feed; @@ -55,6 +57,82 @@ public class FilterSettingsActivity extends ActionBarActivity { filter = filtersList.getFilterFromHashCode(filterHashCode); setTitle(); + + try { + setupFeedsList(); + } catch (IOException e) { + Frontend.error(this, R.string.error_load_feeds, e); + } + } + + /** + * Setup the list of feeds + * @throws IOException + */ + protected void setupFeedsList() throws IOException { + final FeedAdapter feedAdapter = new FeedAdapter( + this, + R.layout.item_filter_settings_feed, + FeedsList.getInstance(this).getFeeds(), + filter); + + final ListView feedsListView = (ListView) findViewById(R.id.filter_settings_feeds_list); + feedsListView.setAdapter(feedAdapter); + + feedsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + Feed feed = feedAdapter.getItem(position); + List<Integer> hashCodes = filter.getFeedHashCodes(); + if (hashCodes.contains(feed.hashCode())) { + hashCodes.remove((Integer) feed.hashCode()); + } else { + hashCodes.add(feed.hashCode()); + } + try { + filter.store(DefaultStorageProvider.getInstance()); + feedAdapter.notifyDataSetChanged(); + } catch (Exception e) { + Frontend.error(getBaseContext(), R.string.error_save_filters, e); + filter.getFeeds().add(feed); + } + } + }); + + /** + * @todo Allow users to enter links without scheme (http:// ...) + */ + findViewById(R.id.filter_settings_add_feed_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EditText editText = (EditText) findViewById(R.id.filter_settings_add_feed); + String value = editText.getText().toString(); + try { + URL url = new URL(value); + Feed feed = new Feed(url); + try { + feed.store(DefaultStorageProvider.getInstance()); + FeedsList.getInstance().getFeeds().add(feed); + filter.getFeedHashCodes().add(feed.hashCode()); + + try { + filter.store(DefaultStorageProvider.getInstance()); + feed.store(DefaultStorageProvider.getInstance()); + feedAdapter.notifyDataSetChanged(); + editText.setText(""); + } catch (Exception e) { + Frontend.error(getBaseContext(), R.string.error_save_filters, e); + filter.getFeeds().remove(feed); + } + } catch (Exception e) { + Frontend.error(getBaseContext(), R.string.error_save_feeds, e); + FeedsList.getInstance().getFeeds().remove(feed); + } + } catch (MalformedURLException e) { + Frontend.info(getBaseContext(), R.string.error_invalid_url, e); + } + } + }); } @Override @@ -68,9 +146,6 @@ public class FilterSettingsActivity extends ActionBarActivity { int id = item.getItemId(); switch (id) { - case R.id.filter_settings_action_feeds: - openFeedsDialog(); - return true; case R.id.filter_settings_action_title: openTitleDialog(); return true; @@ -98,17 +173,6 @@ public class FilterSettingsActivity extends ActionBarActivity { } /** - * Open dialog to edit feeds - */ - public void openFeedsDialog() { - FeedsDialogFragment f = new FeedsDialogFragment(); - Bundle bundle = new Bundle(); - bundle.putInt("filter", filter.hashCode()); - f.setArguments(bundle); - f.show(getFragmentManager(), ""); - } - - /** * Open dialog to edit title * For the moment, we temporarily disable rotating because we can't get it working otherwise. * @todo make rotating possible @@ -160,148 +224,58 @@ public class FilterSettingsActivity extends ActionBarActivity { } /** - * Custom Dialog to display & edit feeds + * Custom ArrayAdapter to display feeds */ - public static class FeedsDialogFragment extends DialogFragment { - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_filter_settings_feeds, null); - - final FiltersList filtersList = FiltersList.getInstance(); - final Filter filter = filtersList.getFilterFromHashCode(getArguments().getInt("filter")); - - try { - final FeedAdapter feedAdapter = new FeedAdapter( - getActivity(), - R.layout.item_filter_settings_feed, - FeedsList.getInstance(getActivity()).getFeeds(), - filter); - - ListView feedsListView = (ListView) view.findViewById(R.id.filter_settings_feeds_list); - feedsListView.setAdapter(feedAdapter); - - /** - * @todo nicer selected feed layout - * @todo deselecting feeds doesn't work - */ - feedsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Feed feed = feedAdapter.getItem(position); - List<Integer> hashCodes = filter.getFeedHashCodes(); - if (hashCodes.contains(feed.hashCode())) { - hashCodes.remove(Integer.valueOf(feed.hashCode())); - } else { - hashCodes.add(feed.hashCode()); - } - try { - filter.store(DefaultStorageProvider.getInstance()); - feedAdapter.notifyDataSetChanged(); - } catch (Exception e) { - Frontend.error(getActivity(), R.string.error_save_filters, e); - filter.getFeeds().add(feed); - } - } - }); + private static class FeedAdapter extends SortedArrayAdapter<Feed> { + + Context context; + int layoutResourceId; + Filter filter; + + public FeedAdapter(Context context, int resource, List<Feed> objects, Filter filter) { + super(context, resource, objects); + this.context = context; + layoutResourceId = resource; + items = objects; + this.filter = filter; + } - view.findViewById(R.id.filter_settings_add_feed_button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - EditText editText = (EditText) view.findViewById(R.id.filter_settings_add_feed); - String value = editText.getText().toString(); - try { - URL url = new URL(value); - Feed feed = new Feed(url); - try { - feed.store(DefaultStorageProvider.getInstance()); - FeedsList.getInstance().getFeeds().add(feed); - filter.getFeedHashCodes().add(feed.hashCode()); - - try { - filter.store(DefaultStorageProvider.getInstance()); - feed.store(DefaultStorageProvider.getInstance()); - feedAdapter.notifyDataSetChanged(); - editText.setText(""); - } catch (Exception e) { - Frontend.error(getActivity(), R.string.error_save_filters, e); - filter.getFeeds().remove(feed); - } - } catch (Exception e) { - Frontend.error(getActivity(), R.string.error_save_feeds, e); - FeedsList.getInstance().getFeeds().remove(feed); - } - } catch (MalformedURLException e) { - Frontend.info(getActivity(), R.string.error_invalid_url, e); - } - } - }); + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + FeedHolder holder; + + if (row == null) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + row = inflater.inflate(layoutResourceId, parent, false); + + holder = new FeedHolder(); + holder.layout = (RelativeLayout) row.findViewById(R.id.filter_settings_feed_item); + holder.title = (TextView) row.findViewById(R.id.filter_settings_feed_item_title); + holder.url = (TextView) row.findViewById(R.id.filter_settings_feed_item_url); + holder.checkBox = (CheckBox) row.findViewById(R.id.filter_settings_feed_item_checkbox); + + row.setTag(holder); + } else { + holder = (FeedHolder) row.getTag(); + } - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setMessage(R.string.filter_settings_feeds).setPositiveButton(R.string.button_ok, null); - builder.setView(view); + Feed feed = items.get(position); + holder.title.setText(feed.getTitle()); + holder.url.setText(feed.getURL().toString()); + holder.checkBox.setChecked(filter.getFeedHashCodes().contains(feed.hashCode())); - return builder.create(); - } catch (IOException e) { - dismiss(); - Frontend.error(getActivity(), R.string.error_load_feeds, e); - return null; - } + return row; } /** - * Custom ArrayAdapter to display feeds + * TextViews holder */ - private static class FeedAdapter extends SortedArrayAdapter<Feed> { - - Context context; - int layoutResourceId; - Filter filter; - - public FeedAdapter(Context context, int resource, List<Feed> objects, Filter filter) { - super(context, resource, objects); - this.context = context; - layoutResourceId = resource; - items = objects; - this.filter = filter; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - FeedHolder holder; - - if (row == null) { - LayoutInflater inflater = ((Activity) context).getLayoutInflater(); - row = inflater.inflate(layoutResourceId, parent, false); - - holder = new FeedHolder(); - holder.layout = (LinearLayout) row.findViewById(R.id.filter_settings_feed_item); - holder.title = (TextView) row.findViewById(R.id.filter_settings_feed_item_title); - holder.url = (TextView) row.findViewById(R.id.filter_settings_feed_item_url); - - row.setTag(holder); - } else { - holder = (FeedHolder) row.getTag(); - } - - Feed feed = items.get(position); - holder.title.setText(feed.getTitle()); - holder.url.setText(feed.getURL().toString()); - if (filter.getFeedHashCodes().contains(feed.hashCode())) { - holder.layout.setBackgroundColor(Color.RED); - } - - return row; - } - - /** - * TextViews holder - */ - private static class FeedHolder { - LinearLayout layout; - TextView title; - TextView url; - } + private static class FeedHolder { + RelativeLayout layout; + TextView title; + TextView url; + CheckBox checkBox; } } diff --git a/app/src/main/java/org/rssin/android/HomeScreenActivity.java b/app/src/main/java/org/rssin/android/HomeScreenActivity.java new file mode 100755 index 0000000..ebcf180 --- /dev/null +++ b/app/src/main/java/org/rssin/android/HomeScreenActivity.java @@ -0,0 +1,200 @@ +package org.rssin.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.ActionBar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.support.v4.widget.DrawerLayout;
+
+import com.android.volley.VolleyError;
+
+import org.rssin.listener.FallibleListener;
+import org.rssin.rssin.Filter;
+import org.rssin.rssin.R;
+import org.rssin.rssin.SortedFeedItemContainer;
+import org.rssin.rssin.UnifiedFilterLoader;
+
+import java.io.IOException;
+import java.util.List;
+
+
+public class HomeScreenActivity extends ActionBarActivity
+ implements NavigationDrawerFragment.NavigationDrawerCallbacks {
+
+ /**
+ * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
+ */
+ private NavigationDrawerFragment mNavigationDrawerFragment;
+
+ /**
+ * Used to store the last screen title. For use in {@link #restoreActionBar()}.
+ */
+ private CharSequence mTitle;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_home_screen);
+
+ mNavigationDrawerFragment = (NavigationDrawerFragment)
+ getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
+ mTitle = getTitle();
+
+ // Set up the drawer.
+ mNavigationDrawerFragment.setUp(
+ R.id.navigation_drawer,
+ (DrawerLayout) findViewById(R.id.drawer_layout));
+ }
+
+ @Override
+ public void onNavigationDrawerItemSelected(int position) {
+ // update the main content by replacing fragments
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ fragmentManager.beginTransaction()
+ .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
+ .commit();
+ }
+
+ public void onSectionAttached(int number) {
+ switch (number) {
+ case 1:
+ mTitle = getString(R.string.title_section1);
+ break;
+ case 2:
+ mTitle = getString(R.string.title_section2);
+ break;
+ case 3:
+ mTitle = getString(R.string.title_section3);
+ break;
+ default:
+ mTitle = "ERROR";
+ break;
+ }
+ }
+
+ public void restoreActionBar() {
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setTitle(mTitle);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (!mNavigationDrawerFragment.isDrawerOpen()) {
+ // Only show items in the action bar relevant to this screen
+ // if the drawer is not showing. Otherwise, let the drawer
+ // decide what to show in the action bar.
+ getMenuInflater().inflate(R.menu.home_screen, menu);
+ restoreActionBar();
+ return true;
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_settings) {
+ Intent intent = new Intent(this, UnifiedInboxActivity.class);
+ startActivity(intent);
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * A placeholder fragment containing a simple view.
+ */
+ public static class PlaceholderFragment extends Fragment {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ private static final String ARG_SECTION_NUMBER = "section_number";
+
+ /**
+ * Returns a new instance of this fragment for the given section
+ * number.
+ */
+ public static PlaceholderFragment newInstance(int sectionNumber) {
+ PlaceholderFragment fragment = new PlaceholderFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_SECTION_NUMBER, sectionNumber);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public PlaceholderFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View rootView = inflater.inflate(R.layout.fragment_home_screen, container, false);
+ final RecyclerView mRecyclerView = (RecyclerView) rootView.findViewById(R.id.unified_inbox_feeditems);
+ final Context context = mRecyclerView.getContext();
+ RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
+ mRecyclerView.setLayoutManager(mLayoutManager);
+
+ try {
+ FiltersList filtersList = FiltersList.getInstance(context);
+
+ for(Filter filter : filtersList.getFilters()) {
+ filter.ensureFeedSorter(DefaultStorageProvider.getInstance(context));
+ filter.ensureFeeds(DefaultStorageProvider.getInstance(context));
+ }
+
+ /**
+ * @todo Load feeds in separate thread so that the UI is immediately available
+ *
+ * @todo Now, feed items are only returned after *all* feeds have been loaded. With many
+ * filters that may take a while, so it would be preferable to return intermediate
+ * results. We could do this for example with {@link org.rssin.listener.RealtimeListener}
+ */
+ UnifiedFilterLoader loaderAndSorter = new UnifiedFilterLoader(filtersList.getFilters());
+ loaderAndSorter.getFilteredFeedItems(new VolleyFetcher(context), new FallibleListener<List<SortedFeedItemContainer>, VolleyError>() {
+ @Override
+ public void onReceive(List<SortedFeedItemContainer> data) {
+ FeedItemAdapter feedItemAdapter = new FeedItemAdapter(data);
+ mRecyclerView.setAdapter(feedItemAdapter);
+ mRecyclerView.setHasFixedSize(true);
+ }
+
+ @Override
+ public void onError(VolleyError error) {
+ Frontend.error(context, R.string.error_net_load);
+ }
+ });
+ } catch (IOException e) {
+ Frontend.error(context, R.string.error_load_filters, e);
+ }
+
+ return rootView;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ ((HomeScreenActivity) activity).onSectionAttached(
+ getArguments().getInt(ARG_SECTION_NUMBER));
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerAdapter.java b/app/src/main/java/org/rssin/android/NavigationDrawerAdapter.java new file mode 100755 index 0000000..d2e58ce --- /dev/null +++ b/app/src/main/java/org/rssin/android/NavigationDrawerAdapter.java @@ -0,0 +1,118 @@ +package org.rssin.android;
+
+import android.database.DataSetObserver;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import org.rssin.rssin.R;
+
+/**
+ * @author Jos.
+ */
+class NavigationDrawerAdapter implements ListAdapter {
+ private static final int ITEM_VIEW_TYPE_VIDEO = 0;
+ private static final int ITEM_VIEW_TYPE_SEPARATOR = 1;
+ private static final int ITEM_VIEW_TYPE_COUNT = 2;
+ private final Object[] menuItems = new Object[] {
+ "MAIN",
+ new MenuItemHolder("Text 1"),
+ "FILTERS",
+ new MenuItemHolder("Text 1"),
+ "FEEDS",
+ new MenuItemHolder("Lorem ipsum"),
+ new MenuItemHolder("Dolor sit amet"),
+ new MenuItemHolder("Text 1"),
+ new MenuItemHolder("Text 1"),
+ new MenuItemHolder("Text Text Text"),
+ new MenuItemHolder("Even more text"),
+ };
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItemViewType(position) != ITEM_VIEW_TYPE_SEPARATOR;
+ }
+
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+
+ }
+
+ @Override
+ public int getCount() {
+ return menuItems.length;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return menuItems[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final int type = getItemViewType(position);
+
+ // First, let's create a new convertView if needed. You can also
+ // create a ViewHolder to speed up changes if you want ;)
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext()).inflate(
+ type == ITEM_VIEW_TYPE_SEPARATOR ? R.layout.separator_navigation_drawer : R.layout.item_navigation_drawer, parent, false);
+ }
+
+ // We can now fill the list item view with the appropriate data.
+ if (type == ITEM_VIEW_TYPE_SEPARATOR) {
+ ((TextView) convertView.findViewById(R.id.separator_navigation_drawer_text)).setText((String) getItem(position));
+ } else {
+ final MenuItemHolder video = (MenuItemHolder) getItem(position);
+ ((TextView) convertView.findViewById(R.id.item_navigation_drawer_text)).setText(video.text);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return (menuItems[position] instanceof String) ? ITEM_VIEW_TYPE_SEPARATOR : ITEM_VIEW_TYPE_VIDEO;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return ITEM_VIEW_TYPE_COUNT;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ class MenuItemHolder
+ {
+ private String text;
+ public MenuItemHolder(String text)
+ {
+ this.text = text;
+ }
+ }
+}
diff --git a/app/src/main/java/org/rssin/android/NavigationDrawerFragment.java b/app/src/main/java/org/rssin/android/NavigationDrawerFragment.java new file mode 100755 index 0000000..8ad0ca9 --- /dev/null +++ b/app/src/main/java/org/rssin/android/NavigationDrawerFragment.java @@ -0,0 +1,280 @@ +package org.rssin.android;
+
+import android.database.DataSetObserver;
+import android.support.v7.app.ActionBarActivity;
+import android.app.Activity;
+import android.support.v7.app.ActionBar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.rssin.rssin.R;
+
+/**
+ * Fragment used for managing interactions for and presentation of a navigation drawer.
+ * See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
+ * design guidelines</a> for a complete explanation of the behaviors implemented here.
+ */
+public class NavigationDrawerFragment extends Fragment {
+
+ /**
+ * Remember the position of the selected item.
+ */
+ private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
+
+ /**
+ * Per the design guidelines, you should show the drawer on launch until the user manually
+ * expands it. This shared preference tracks this.
+ */
+ private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
+
+ /**
+ * A pointer to the current callbacks instance (the Activity).
+ */
+ private NavigationDrawerCallbacks mCallbacks;
+
+ /**
+ * Helper component that ties the action bar to the navigation drawer.
+ */
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private DrawerLayout mDrawerLayout;
+ private ListView mDrawerListView;
+ private View mFragmentContainerView;
+
+ private int mCurrentSelectedPosition = 1;
+ private boolean mFromSavedInstanceState;
+ private boolean mUserLearnedDrawer;
+
+ public NavigationDrawerFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Read in the flag indicating whether or not the user has demonstrated awareness of the
+ // drawer. See PREF_USER_LEARNED_DRAWER for details.
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
+
+ if (savedInstanceState != null) {
+ mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
+ mFromSavedInstanceState = true;
+ }
+
+ // Select either the default item (0) or the last selected item.
+ selectItem(mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // Indicate that this fragment would like to influence the set of actions in the action bar.
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mDrawerListView = (ListView) inflater.inflate(
+ R.layout.fragment_navigation_drawer, container, false);
+ mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ selectItem(position);
+ }
+ });
+
+ mDrawerListView.setAdapter(new NavigationDrawerAdapter());
+ mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
+ return mDrawerListView;
+ }
+
+ public boolean isDrawerOpen() {
+ return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
+ }
+
+ /**
+ * Users of this fragment must call this method to set up the navigation drawer interactions.
+ *
+ * @param fragmentId The android:id of this fragment in its activity's layout.
+ * @param drawerLayout The DrawerLayout containing this fragment's UI.
+ */
+ public void setUp(int fragmentId, DrawerLayout drawerLayout) {
+ mFragmentContainerView = getActivity().findViewById(fragmentId);
+ mDrawerLayout = drawerLayout;
+
+ // set a custom shadow that overlays the main content when the drawer opens
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
+ // set up the drawer's list view with items and click listener
+
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+
+ // ActionBarDrawerToggle ties together the the proper interactions
+ // between the navigation drawer and the action bar app icon.
+ mDrawerToggle = new ActionBarDrawerToggle(
+ getActivity(), /* host Activity */
+ mDrawerLayout, /* DrawerLayout object */
+ R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
+ R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
+ R.string.navigation_drawer_close /* "close drawer" description for accessibility */
+ ) {
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
+ }
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ if (!mUserLearnedDrawer) {
+ // The user manually opened the drawer; store this flag to prevent auto-showing
+ // the navigation drawer automatically in the future.
+ mUserLearnedDrawer = true;
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
+ }
+
+ getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
+ }
+ };
+
+ // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
+ // per the navigation drawer design guidelines.
+ if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
+ mDrawerLayout.openDrawer(mFragmentContainerView);
+ }
+
+ // Defer code dependent on restoration of previous instance state.
+ mDrawerLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ mDrawerToggle.syncState();
+ }
+ });
+
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ }
+
+ private void selectItem(int position) {
+ mCurrentSelectedPosition = position;
+ if (mDrawerListView != null) {
+ mDrawerListView.setItemChecked(position, true);
+ }
+ if (mDrawerLayout != null) {
+ mDrawerLayout.closeDrawer(mFragmentContainerView);
+ }
+ if (mCallbacks != null) {
+ mCallbacks.onNavigationDrawerItemSelected(position);
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ mCallbacks = (NavigationDrawerCallbacks) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mCallbacks = null;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // Forward the new configuration the drawer toggle component.
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ // If the drawer is open, show the global app actions in the action bar. See also
+ // showGlobalContextActionBar, which controls the top-left area of the action bar.
+ if (mDrawerLayout != null && isDrawerOpen()) {
+ inflater.inflate(R.menu.global, menu);
+ showGlobalContextActionBar();
+ }
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+// if (item.getItemId() == R.id.action_example) {
+// Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
+// return true;
+// }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * Per the navigation drawer design guidelines, updates the action bar to show the global app
+ * 'context', rather than just what's in the current screen.
+ */
+ private void showGlobalContextActionBar() {
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ actionBar.setTitle(R.string.app_name);
+ }
+
+ private ActionBar getActionBar() {
+ return ((ActionBarActivity) getActivity()).getSupportActionBar();
+ }
+
+ /**
+ * Callbacks interface that all activities using this fragment must implement.
+ */
+ public static interface NavigationDrawerCallbacks {
+ /**
+ * Called when an item in the navigation drawer is selected.
+ */
+ void onNavigationDrawerItemSelected(int position);
+ }
+}
diff --git a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java index 4cc9386..4c23fa9 100755 --- a/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java +++ b/app/src/main/java/org/rssin/android/SharedPreferencesStorageProvider.java @@ -69,18 +69,15 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(element); oos.close(); - String string = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT); + baos.close(); + String base64 = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT); context.getSharedPreferences(key.toString(), Context.MODE_PRIVATE) .edit() - .putString(element.getClass().getName(), string) + .putString(element.getClass().getName(), base64) .apply(); - if (element.getClass() == Filter.class) { - storeFilterKey(key); - } else if (element.getClass() == Feed.class) { - storeFeedKey(key); - } + Log.v("SPSP", "Store to " + key.toString() + ":\n" + base64); } @Override @@ -89,8 +86,9 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage if (serialized == null) { throw new IOException("No sharedPreference with key " + key.toString() + " and class " + className.getName()); } - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(serialized, Base64.DEFAULT))); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(serialized.getBytes(), Base64.DEFAULT))); Object obj = ois.readObject(); + Log.v("SPSP", "Fetch " + className.toString() + " from " + key.toString() + ": " + obj.toString()); return (Storable) className.cast(obj); } @@ -118,8 +116,10 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage .getStringSet("filters", new HashSet<String>()); List<Filter> filters = new ArrayList<>(); for (String name : names) { + Log.v("SPSP", "allFilters: " + name); Filter filter = getFilter(name); if (filter != null) { + Log.v("SPSP", "allFilters: not null, returning"); filters.add(filter); } } @@ -137,6 +137,7 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage try { return (Filter) fetch(key.toString(), Filter.class); } catch (Exception e) { + Log.w("SPSP", "Fetch filter " + key.toString(), e); return null; } } @@ -145,12 +146,7 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage public void removeFilter(Object key) { SharedPreferences sharedPreferences = context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE); Set<String> names = new HashSet<>(sharedPreferences.getStringSet("filters", new HashSet<String>())); - for (String name : names) - Log.d("SPSP", "Old name: " + name); - Log.d("SPSP", "Removing name " + key.toString()); names.remove(key.toString()); - for (String name : names) - Log.d("SPSP", "New name: " + name); sharedPreferences .edit() .putStringSet("filters", names) @@ -161,9 +157,8 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage /** * Keep track of a new key for a filter in the administration SharedPreferences * @param key - * @throws Exception */ - protected void storeFilterKey(Object key) throws Exception { + protected void storeFilterKey(Object key) { SharedPreferences sharedPreferences = context.getSharedPreferences(ADMIN_PREF_KEY, Context.MODE_PRIVATE); Set<String> names = new HashSet<>(sharedPreferences.getStringSet("filters", new HashSet<String>())); names.add(key.toString()); @@ -187,6 +182,12 @@ class SharedPreferencesStorageProvider implements StorageProvider, FilterStorage } @Override + public void storeFeed(Object key, Feed feed) throws Exception { + store(key, feed); + storeFeedKey(key); + } + + @Override public Feed getFeed(Object key) { try { return (Feed) fetch(key.toString(), Feed.class); diff --git a/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java b/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java index ec8dce7..5a11621 100755 --- a/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java +++ b/app/src/main/java/org/rssin/android/UnifiedInboxActivity.java @@ -41,7 +41,7 @@ public class UnifiedInboxActivity extends ActionBarActivity { filtersList = FiltersList.getInstance(this); for(Filter filter : filtersList.getFilters()) { - filter.ensureFeedSorter(DefaultStorageProvider.getInstance(this)); + filter.ensureFeedSorter(InternalStorageProvider.getInstance(this)); filter.ensureFeeds(DefaultStorageProvider.getInstance(this)); } diff --git a/app/src/main/java/org/rssin/rssin/Feed.java b/app/src/main/java/org/rssin/rssin/Feed.java index 55d0e5d..ae8b5f2 100755 --- a/app/src/main/java/org/rssin/rssin/Feed.java +++ b/app/src/main/java/org/rssin/rssin/Feed.java @@ -5,6 +5,7 @@ import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import org.rssin.serialization.Jsonable; +import org.rssin.storage.FeedStorageProvider; import org.rssin.storage.Storable; import org.rssin.storage.StorageProvider; @@ -110,12 +111,12 @@ public class Feed implements Storable, Comparable<Feed>, Jsonable { * @param storageProvider * @throws Exception */ - public synchronized void store(StorageProvider storageProvider) throws Exception { + public synchronized void store(FeedStorageProvider storageProvider) throws Exception { if (storageKey == null) { storageKey = storageProvider.uniqueKey(); } - storageProvider.store(storageKey, this); + storageProvider.storeFeed(storageKey, this); } @Override diff --git a/app/src/main/java/org/rssin/rssin/Filter.java b/app/src/main/java/org/rssin/rssin/Filter.java index 7f1d95e..e7e0158 100755 --- a/app/src/main/java/org/rssin/rssin/Filter.java +++ b/app/src/main/java/org/rssin/rssin/Filter.java @@ -1,5 +1,6 @@ package org.rssin.rssin; +import android.support.annotation.Nullable; import android.util.Log; import org.json.JSONArray; @@ -73,14 +74,6 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { setTitle(title); } - private void writeObject(ObjectOutputStream stream) throws JSONException, IOException { - stream.writeObject(toJson().toString()); - } - - private void readObject(ObjectInputStream stream) throws JSONException, IOException, ClassNotFoundException { - fromJson(new JSONObject((String) stream.readObject())); - } - public List<Integer> getFeedHashCodes() { return feedHashCodes; } @@ -181,8 +174,8 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { } @Override - public int compareTo(Filter another) { - return title.compareTo(another.title); + public int compareTo(@Nullable Filter another) { + return another == null ? -1 : title.compareTo(another.title); } @Override @@ -198,7 +191,6 @@ public class Filter implements Storable, Comparable<Filter>, Jsonable { public void fromJson(JSONObject json) throws JSONException { title = json.getString("title"); feedHashCodes = JsonSerializer.integersListFromJson(json.getJSONArray("feedHashCodes")); - JSONArray keywordsJson = json.getJSONArray("keywords"); storageKey = json.getString("storageKey"); } diff --git a/app/src/main/java/org/rssin/rssin/dummy/DummyContent.java b/app/src/main/java/org/rssin/rssin/dummy/DummyContent.java new file mode 100755 index 0000000..059f859 --- /dev/null +++ b/app/src/main/java/org/rssin/rssin/dummy/DummyContent.java @@ -0,0 +1,55 @@ +package org.rssin.rssin.dummy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class for providing sample content for user interfaces created by
+ * Android template wizards.
+ * <p/>
+ * TODO: Replace all uses of this class before publishing your app.
+ */
+public class DummyContent {
+
+ /**
+ * An array of sample (dummy) items.
+ */
+ public static List<DummyItem> ITEMS = new ArrayList<DummyItem>();
+
+ /**
+ * A map of sample (dummy) items, by ID.
+ */
+ public static Map<String, DummyItem> ITEM_MAP = new HashMap<String, DummyItem>();
+
+ static {
+ // Add 3 sample items.
+ addItem(new DummyItem("1", "Item 1"));
+ addItem(new DummyItem("2", "Item 2"));
+ addItem(new DummyItem("3", "Item 3"));
+ }
+
+ private static void addItem(DummyItem item) {
+ ITEMS.add(item);
+ ITEM_MAP.put(item.id, item);
+ }
+
+ /**
+ * A dummy item representing a piece of content.
+ */
+ public static class DummyItem {
+ public String id;
+ public String content;
+
+ public DummyItem(String id, String content) {
+ this.id = id;
+ this.content = content;
+ }
+
+ @Override
+ public String toString() {
+ return content;
+ }
+ }
+}
diff --git a/app/src/main/java/org/rssin/storage/FeedStorageProvider.java b/app/src/main/java/org/rssin/storage/FeedStorageProvider.java index eac78ce..13932a6 100644 --- a/app/src/main/java/org/rssin/storage/FeedStorageProvider.java +++ b/app/src/main/java/org/rssin/storage/FeedStorageProvider.java @@ -17,6 +17,13 @@ public interface FeedStorageProvider<K> { List<Feed> allFeeds(); /** + * Save a Filter + * @param key + * @param feed + */ + void storeFeed(K key, Feed feed) throws Exception; + + /** * Get the feed for a specific key * @param key * @return @@ -29,4 +36,10 @@ public interface FeedStorageProvider<K> { */ void removeFeed(K key); + /** + * Get a new, unique, usable key + * @return + */ + K uniqueKey(); + } diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png Binary files differnew file mode 100755 index 0000000..236bff5 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png Binary files differnew file mode 100755 index 0000000..c59f601 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_drawer.png diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png Binary files differnew file mode 100755 index 0000000..ffe3a28 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png Binary files differnew file mode 100755 index 0000000..1ed2c56 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_drawer.png diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png Binary files differnew file mode 100755 index 0000000..fabe9d9 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png Binary files differnew file mode 100755 index 0000000..a5fa74d --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_drawer.png diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png Binary files differnew file mode 100755 index 0000000..b91e9d7 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png Binary files differnew file mode 100755 index 0000000..9c4685d --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_drawer.png diff --git a/app/src/main/res/layout/activity_filter_settings.xml b/app/src/main/res/layout/activity_filter_settings.xml index 6ee5331..f0a773c 100644 --- a/app/src/main/res/layout/activity_filter_settings.xml +++ b/app/src/main/res/layout/activity_filter_settings.xml @@ -4,10 +4,7 @@ tools:context="org.rssin.android.FilterSettingsActivity" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingLeft="0dp" - android:paddingRight="0dp" - android:paddingTop="0dp" - android:paddingBottom="0dp" + android:padding="0dp" android:orientation="vertical"> <LinearLayout @@ -16,23 +13,24 @@ android:orientation="horizontal"> <EditText - android:id="@+id/filter_settings_add_keyword" + android:id="@+id/filter_settings_add_feed" android:layout_width="0dip" android:layout_weight="1" android:layout_height="wrap_content" - android:maxLines="1"/> + android:maxLines="1" + android:inputType="textUri"/> <Button + android:id="@+id/filter_settings_add_feed_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/filter_settings_add_keyword" - android:onClick="addKeyword"/> + android:text="@string/filter_settings_add_feed"/> </LinearLayout> <ListView android:id="@+id/filter_settings_feeds_list" android:layout_width="match_parent" - android:layout_height="match_parent"></ListView> + android:layout_height="match_parent"/> </LinearLayout> diff --git a/app/src/main/res/layout/activity_home_screen.xml b/app/src/main/res/layout/activity_home_screen.xml new file mode 100755 index 0000000..f6fcc0c --- /dev/null +++ b/app/src/main/res/layout/activity_home_screen.xml @@ -0,0 +1,24 @@ +<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
+ android:layout_width="match_parent" android:layout_height="match_parent"
+ tools:context="org.rssin.android.HomeScreenActivity">
+
+ <!-- As the main content view, the view below consumes the entire
+ space available using match_parent in both dimensions. -->
+ <FrameLayout android:id="@+id/container" android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- android:layout_gravity="start" tells DrawerLayout to treat
+ this as a sliding drawer on the left side for left-to-right
+ languages and on the right side for right-to-left languages.
+ If you're not building against API 17 or higher, use
+ android:layout_gravity="left" instead. -->
+ <!-- The drawer is given a fixed width in dp and extends the full height of
+ the container. -->
+ <fragment android:id="@+id/navigation_drawer"
+ android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
+ android:layout_gravity="start" android:name="org.rssin.android.NavigationDrawerFragment"
+ tools:layout="@layout/fragment_navigation_drawer" />
+
+</android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/fragment_filter_settings_feeds.xml b/app/src/main/res/layout/fragment_filter_settings_feeds.xml deleted file mode 100644 index 9c1e1f4..0000000 --- a/app/src/main/res/layout/fragment_filter_settings_feeds.xml +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - - <EditText - android:id="@+id/filter_settings_add_feed" - android:layout_width="0dip" - android:layout_weight="1" - android:layout_height="wrap_content" - android:maxLines="1" - android:inputType="textUri"/> - - <Button - android:id="@+id/filter_settings_add_feed_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/filter_settings_add_feed"/> - - </LinearLayout> - - <ListView - android:id="@+id/filter_settings_feeds_list" - android:layout_width="match_parent" - android:layout_height="match_parent"/> - -</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_screen.xml b/app/src/main/res/layout/fragment_home_screen.xml new file mode 100755 index 0000000..a502805 --- /dev/null +++ b/app/src/main/res/layout/fragment_home_screen.xml @@ -0,0 +1,15 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ tools:context="org.rssin.android.HomeScreenActivity$PlaceholderFragment">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/unified_inbox_feeditems"
+ android:scrollbars="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/fragment_navigation_drawer.xml b/app/src/main/res/layout/fragment_navigation_drawer.xml new file mode 100755 index 0000000..6b9ec1d --- /dev/null +++ b/app/src/main/res/layout/fragment_navigation_drawer.xml @@ -0,0 +1,7 @@ +<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:choiceMode="singleChoice"
+ android:divider="@android:color/transparent" android:dividerHeight="0dp"
+ android:background="#cccc" tools:context="org.rssin.android.NavigationDrawerFragment" />
\ No newline at end of file diff --git a/app/src/main/res/layout/item_filter_settings_feed.xml b/app/src/main/res/layout/item_filter_settings_feed.xml index 4f027eb..e7e5196 100644 --- a/app/src/main/res/layout/item_filter_settings_feed.xml +++ b/app/src/main/res/layout/item_filter_settings_feed.xml @@ -1,20 +1,36 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/filter_settings_feed_item" - android:orientation="vertical" + android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:padding="10dp"> + android:padding="@dimen/listview_item_padding"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical"> - <TextView android:id="@+id/filter_settings_feed_item_title" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:textSize="@dimen/font_size_large"/> + <TextView android:id="@+id/filter_settings_feed_item_title" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textSize="@dimen/font_size_large"/> - <TextView android:id="@+id/filter_settings_feed_item_url" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:textSize="@dimen/font_size_normal"/> + <TextView android:id="@+id/filter_settings_feed_item_url" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textSize="@dimen/font_size_normal"/> -</LinearLayout>
\ No newline at end of file + </LinearLayout> + + <CheckBox + android:id="@+id/filter_settings_feed_item_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="false" + android:clickable="false" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true"/> + +</RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/item_navigation_drawer.xml b/app/src/main/res/layout/item_navigation_drawer.xml new file mode 100755 index 0000000..32a8837 --- /dev/null +++ b/app/src/main/res/layout/item_navigation_drawer.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/itemLayout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:orientation="vertical"
+
+ android:layout_marginTop="0dp"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="55dp"
+ >
+
+ <TextView
+ android:id="@+id/item_navigation_drawer_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/separator_navigation_drawer.xml b/app/src/main/res/layout/separator_navigation_drawer.xml new file mode 100755 index 0000000..856093c --- /dev/null +++ b/app/src/main/res/layout/separator_navigation_drawer.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+xmlns:android="http://schemas.android.com/apk/res/android"
+android:id="@+id/itemLayout"
+android:layout_width="fill_parent"
+android:layout_height="wrap_content"
+android:layout_alignParentLeft="true"
+android:orientation="vertical"
+android:layout_marginTop="0dp"
+android:background="?android:attr/activatedBackgroundIndicator"
+ >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="35dp"
+ >
+
+ <TextView
+ android:id="@+id/separator_navigation_drawer_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="1dp"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:background="#DADADC"
+
+ ></View>
+
+</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/menu/global.xml b/app/src/main/res/menu/global.xml new file mode 100755 index 0000000..fc41e98 --- /dev/null +++ b/app/src/main/res/menu/global.xml @@ -0,0 +1,5 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/menu/home_screen.xml b/app/src/main/res/menu/home_screen.xml new file mode 100755 index 0000000..cf4b03a --- /dev/null +++ b/app/src/main/res/menu/home_screen.xml @@ -0,0 +1,9 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="org.rssin.android.HomeScreenActivity">
+ <item android:id="@+id/action_example" android:title="@string/action_example"
+ app:showAsAction="withText|ifRoom" />
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/menu/menu_filter_settings.xml b/app/src/main/res/menu/menu_filter_settings.xml index 848c9df..655ee84 100644 --- a/app/src/main/res/menu/menu_filter_settings.xml +++ b/app/src/main/res/menu/menu_filter_settings.xml @@ -6,11 +6,6 @@ tools:context=".FilterSettingsActivity"> <item - android:id="@+id/filter_settings_action_feeds" - android:title="@string/filter_settings_action_feeds" - app:showAsAction="ifRoom" /> - - <item android:id="@+id/filter_settings_action_title" android:title="@string/filter_settings_action_title" app:showAsAction="ifRoom" /> diff --git a/app/src/main/res/values-large/refs.xml b/app/src/main/res/values-large/refs.xml new file mode 100755 index 0000000..d152eb1 --- /dev/null +++ b/app/src/main/res/values-large/refs.xml @@ -0,0 +1,4 @@ +<resources>
+
+
+</resources>
\ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/refs.xml b/app/src/main/res/values-sw600dp/refs.xml new file mode 100755 index 0000000..d152eb1 --- /dev/null +++ b/app/src/main/res/values-sw600dp/refs.xml @@ -0,0 +1,4 @@ +<resources>
+
+
+</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 0121f92..512350a 100644..100755 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -9,4 +9,8 @@ <dimen name="font_size_large">20sp</dimen> <dimen name="font_size_normal">16sp</dimen> <dimen name="font_size_small">14sp</dimen> + + <!-- Per the design guidelines, navigation drawers should be between 240dp and 320dp: + https://developer.android.com/design/patterns/navigation-drawer.html --> + <dimen name="navigation_drawer_width">240dp</dimen> </resources> diff --git a/app/src/main/res/values/refs.xml b/app/src/main/res/values/refs.xml new file mode 100755 index 0000000..d152eb1 --- /dev/null +++ b/app/src/main/res/values/refs.xml @@ -0,0 +1,4 @@ +<resources>
+
+
+</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2362102..83cda21 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,6 +13,8 @@ <string name="title_activity_filters">Filters</string> <string name="title_activity_filter_settings">Filter</string> <string name="title_activity_filter">Filter</string> + <string name="title_activity_article">Article</string> + <string name="title_activity_feeds">Feeds</string> <string name="filters_action_add">Add</string> @@ -39,11 +41,11 @@ <string name="error_net_load">Internet problem</string> <string name="error_save_feedsorter">Couldn\'t store personal preferences</string> - <string name="title_activity_feeds">Feeds</string> - <string name="hello_world">Hello world!</string> - <string name="title_activity_article">ArticleActivity</string> + <string name="error_load_article">Couldn\'t load article</string> + <string name="feeds">feeds</string> + <string name="article_action_dislike">Dislike</string> <string name="article_action_like">Like</string> <string name="title_activity_home_screen">HomeScreenActivity</string> @@ -56,4 +58,9 @@ <string name="navigation_drawer_close">Close navigation drawer</string> <string name="action_example">Example action</string> + + <string name="article_author">Written by:</string> + <string name="article_author_unknown">Unknown author</string> + <string name="article_published_on">Published on:</string> + <string name="article_published_on_unknown"/> </resources> |