diff --git a/README.md b/README.md index e46e1b6..81e2541 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ App for getting video game news from different websites! -See release notes on master branch releases for features that cover last release. +See release notes on master branch releases for features that cover last release. You could also download last .apk version here. (**Android min. version: 4.1**) See changelog on develop branch for not-official features. @@ -14,8 +14,38 @@ See changelog on develop branch for not-official features. -RSS Parser (https://github.com/prof18/RSS-Parser) +# Build + +1. Open Android Studio. +2. Select File -> New -> Project from Version Control -> GitHub +3. Enter your github username and password. +4. Copy this repo's clone url. +5. Select the repository and hit clone. + + # Changelog --11/7/2018: Changed colors. Added app icon inside toolbar. Added a Floating Action Button for back to top compability. --2/7/2018: Bugfixes for Locale and proper onBackPressed when paserMaker.isRunning = true. Change min. version for Android 4.1 Improvement of ParserMaker --27/6/2018: First commit. \ No newline at end of file +**-14/7/2018:** + Added a drawer layout with a navigation view. + + Changed MainActivity's all in one for a Fragment that can handle all categories of news. + + Changed ParserMaker's use of variable Activity in order to avoid a NullException. Now use an interface. + + Created Urls.json file for reading urls depending on language. + + Added GSON library for Json reading. + + Created Categories inside Models package. + + Created LoadUrls for handling the reading of the Json file. + + Created WebViewActivity. + + Deleted icon in toolbar.xml layout. Now is added with toolbar.setIcon() + + Changed harcoded strings and dimens. + +**-11/7/2018:** Changed colors. Added app icon inside toolbar. Added a Floating Action Button for back to top compability. +**-2/7/2018:** Bugfixes for Locale and proper onBackPressed when paserMaker.isRunning = true. Change min. version for Android 4.1 Improvement of ParserMaker +**-27/6/2018:** First commit. \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 30e9d6f..603ff67 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,11 +26,13 @@ dependencies { implementation 'com.android.support:design:26.1.0' implementation 'com.prof.rssparser:rssparser:1.4.1' implementation 'com.squareup.picasso:picasso:2.71828' + implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.squareup.okhttp:okhttp:2.5.0' implementation 'com.squareup.okhttp:okhttp-urlconnection:2.2.0' implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support:cardview-v7:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0' + implementation 'com.android.support:support-v4:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 54d49f5..fe9b738 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,23 +3,33 @@ package="com.example.emmanuel.gamingnews"> - + - + + + + \ No newline at end of file diff --git a/app/src/main/assets/Urls.json b/app/src/main/assets/Urls.json new file mode 100644 index 0000000..3d4fdb9 --- /dev/null +++ b/app/src/main/assets/Urls.json @@ -0,0 +1,65 @@ +[ + { + "language": "es", + "all_urls": [ + "https://www.eurogamer.es/?format=rss", + "https://vandal.elespanol.com/xml.cgi", + "https://www.levelup.com/rss", + "https://puregaming.es/feed/" + ], + "ps4_urls": [ + "http://feeds.feedburner.com/SCEEBlogES", + "https://puregaming.es/juegos-ps4/feed/", + "https://www.egamers.com/category/ps4/feed/", + "http://es.ign.com/ps4.xml", + "http://www.laps4.com/foro/external.php?type=RSS2&forumids=2" + ], + "xboxO_urls":[ + "https://puregaming.es/juegos-xbox-one/feed/", + "https://www.somosxbox.com/feed", + "http://es.ign.com/xbox-one.xml" + ], + "switch_urls": [ + "https://www.nintenderos.com/category/switch/noticias-switch/feed/", + "https://search.nintendo-europe.com/es/feed/news/", + "https://www.eurogamer.es/?format=rss&platform=SWITCH" + ], + "pc_urls": [ + "https://puregaming.es/juegos-pc/feed/", + "https://www.eurogamer.es/?format=rss&platform=PC", + "https://www.egamers.com/category/pc/feed/" + ] + }, + { + "language": "en", + "all_urls": [ + "https://www.gamespot.com/feeds/news/", + "https://www.vg247.com/feed/", + "https://www.eurogamer.net/?format=rss", + "https://kotaku.com/tag/gaming/rss", + "https://www.gameinformer.com/news.xml" + ], + "ps4_urls": [ + "https://www.eurogamer.net/?format=rss&platform=PS4", + "http://feeds.feedburner.com/psblog", + "http://pureplaystation.com/category/latest-news/feed/" + ], + "xboxO_urls":[ + "http://www.thisisxbox.com/feed/", + "https://news.xbox.com/en-us/feed/", + "http://in.ign.com/xbox-one.xml" + ], + "switch_urls": [ + "https://nintendotoday.com/tag/switch/feed/", + "https://kotaku.com/tag/nintendo-switch/rss", + "https://mynintendonews.com/feed/", + "https://nintendowire.com/switch/feed/", + "http://www.nintendolife.com/feeds/news" + ], + "pc_urls": [ + "https://www.rockpapershotgun.com/category/pc-game-news/feed/", + "https://venturebeat.com/category/pc-gaming/feed/", + "https://www.pcgamer.com/rss/" + ] + } +] \ No newline at end of file diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/Fragments/NewsListFragment.java b/app/src/main/java/com/example/emmanuel/gamingnews/Fragments/NewsListFragment.java new file mode 100644 index 0000000..06a8930 --- /dev/null +++ b/app/src/main/java/com/example/emmanuel/gamingnews/Fragments/NewsListFragment.java @@ -0,0 +1,239 @@ +package com.example.emmanuel.gamingnews.Fragments; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import com.example.emmanuel.gamingnews.Adapter.NewsAdapter; +import com.example.emmanuel.gamingnews.Models.NewsModel; +import com.example.emmanuel.gamingnews.R; +import com.example.emmanuel.gamingnews.Utility.ParserMaker; +import com.example.emmanuel.gamingnews.views.WebViewActivity; + +import java.util.ArrayList; +import java.util.List; + + +public class NewsListFragment extends Fragment{ + + private static final String TAG = "NewsListFragment"; + + private RecyclerView recyclerView; + private SwipeRefreshLayout refreshLayout; + private NewsAdapter newsAdapter; + private List newsList = new ArrayList<>(); + private ParserMaker parserMaker; + private FloatingActionButton fab; + private OnFragmentInteractionListener mListener; + + public NewsListFragment() { + // Required empty public constructor + } + + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = inflater.inflate(R.layout.fragment_news_list,container,false); + String[] urls; + recyclerView = view.findViewById(R.id.recyclerview); + refreshLayout = view.findViewById(R.id.refreshlayout); + fab = view.findViewById(R.id.mainFAB); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + recyclerView.smoothScrollToPosition(0); + } + }); + newsAdapter = new NewsAdapter(newsList, clickListener()); + urls = getArguments().getStringArray("urls"); + manageRecyclerView(true,true); + + ParserMaker.OnNewsFinishListener newsFinishListener = new ParserMaker.OnNewsFinishListener() { + @Override + public void onNewsFinish() { + refreshLayout.setRefreshing(false); + parserMaker.setRunning(false); + } + }; + + parserMaker = new ParserMaker(newsFinishListener,urls, + Toast.makeText(getActivity(), R.string.cant_get_articles, Toast.LENGTH_SHORT), + this.newsAdapter,this.newsList); + + parserMaker.create(); + + refreshLayout.setRefreshing(true); + manageRefreshLayout(parserMaker); + return view; + } + + // TODO: Rename method, update argument and hook method into UI event + public void onButtonPressed(Uri uri) { + if (mListener != null) { + mListener.onFragmentInteraction(uri); + } + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnFragmentInteractionListener) { + mListener = (OnFragmentInteractionListener) context; + } else { + throw new RuntimeException(context.toString() + + " must implement OnFragmentInteractionListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if(newsList!=null){ + newsList.clear(); + } + } + + @Override + public void onResume() { + super.onResume(); + //parserMaker.setActivity(parserMaker.isRunning() ? getActivity():null); + } + + @Override + public void onPause() { + super.onPause(); + //parserMaker.setActivity(parserMaker.isRunning() ? getActivity():null); + } + + + + + private void manageRecyclerView(boolean autoMeasure, boolean fixedSize) { + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext()); + layoutManager.setAutoMeasureEnabled(autoMeasure); + + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(newsAdapter); + recyclerView.setHasFixedSize(fixedSize); + + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if(dy > 0 && fab.getVisibility() == View.VISIBLE){ + fab.setVisibility(View.INVISIBLE); + Log.d(TAG,"Entré para esconder"+fab.getVisibility()); + } + else if(dy < 0 && fab.getVisibility() != View.VISIBLE){ + Log.d(TAG,"Entré para mostrar"+fab.getVisibility()); + fab.setVisibility(View.VISIBLE); + } + super.onScrolled(recyclerView, dx, dy); + } + /* + hide() and show() are two methods provided by the FAB to hide/show the FAB button with a smooth animation. + dy is a value that changes when you scroll vertically, when the user scrolls down the value is positive + and when the user scrolls up the value is negative. + So we check if the FAB is visible and the value is positive(i.e. user is scrolling down) + we will hide it and if the FAB is hidden and the value is negative(i.e. user is scrolling up) we will show the FAB. + */ + }); + } + + private void manageRefreshLayout(final ParserMaker parserMaker) { + refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + if(isNetworkAvailable() && !parserMaker.isRunning()) { + refreshLayout.setRefreshing(true); + parserMaker.create(); + } + else if(!isNetworkAvailable()){ + AlertDialog dialog = generateDialog(R.string.check_your_connection); + dialog.show(); + refreshLayout.setRefreshing(false); + } + else if(parserMaker.isRunning()){ + AlertDialog dialog = generateDialog(R.string.still_refreshing); + dialog.show(); + refreshLayout.setRefreshing(false); + } + } + }); + } + + private boolean isNetworkAvailable() { + ConnectivityManager connectivityManager + = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetworkInfo != null; + } + + private AlertDialog generateDialog(int message) + { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setMessage(message); + builder.setNeutralButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }); + return builder.create(); + } + + + private NewsAdapter.NewsViewHolder.OnItemClickListener clickListener() { + return new NewsAdapter.NewsViewHolder.OnItemClickListener() { + @Override + public void OnItemClick(NewsModel item) { + + Intent intent = new Intent(getActivity(), WebViewActivity.class); + intent.putExtra("url",item.getLink()); + + if(fab.getVisibility() == View.VISIBLE) + fab.setVisibility(View.INVISIBLE); + + getActivity().startActivity(intent); + } + }; + } + + + public ParserMaker getParserMaker() { + return parserMaker; + } + + public interface OnFragmentInteractionListener { + // TODO: Update argument type and name + void onFragmentInteraction(Uri uri); + } +} diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/MainActivity.java b/app/src/main/java/com/example/emmanuel/gamingnews/MainActivity.java deleted file mode 100644 index 833e973..0000000 --- a/app/src/main/java/com/example/emmanuel/gamingnews/MainActivity.java +++ /dev/null @@ -1,263 +0,0 @@ -package com.example.emmanuel.gamingnews; - -import android.content.Context; -import android.content.DialogInterface; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.widget.SwipeRefreshLayout; -import android.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.ProgressBar; -import android.widget.Toast; - -import com.example.emmanuel.gamingnews.Adapter.NewsAdapter; -import com.example.emmanuel.gamingnews.Models.NewsModel; -import com.example.emmanuel.gamingnews.Utility.ParserMaker; - - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class MainActivity extends AppCompatActivity { - - private static final String TAG = "MainActivity"; - - private RecyclerView recyclerView; - private SwipeRefreshLayout refreshLayout; - private NewsAdapter newsAdapter; - private List newsList = new ArrayList<>(); - private ParserMaker parserMaker; - private WebView webView; - private ProgressBar progressBar; - private FloatingActionButton fab; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - String[] urls; - setContentView(R.layout.activity_main); - recyclerView = findViewById(R.id.recyclerview); - refreshLayout = findViewById(R.id.refreshlayout); - webView = findViewById(R.id.webview); - fab = findViewById(R.id.mainFAB); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - recyclerView.smoothScrollToPosition(0); - } - }); - newsAdapter = new NewsAdapter(newsList, clickListener()); - if(Locale.getDefault().getLanguage().equals("es")){ - urls = new String[]{"https://www.eurogamer.es/?format=rss","https://vandal.elespanol.com/xml.cgi","https://www.levelup.com/rss","http://www.tierragamer.com/feed/"}; - } - else{ - urls = new String[]{"https://www.gamespot.com/feeds/news/","https://www.vg247.com/feed/","https://www.eurogamer.net/?format=rss","https://kotaku.com/tag/gaming/rss","https://www.gameinformer.com/news.xml"}; - } - Toolbar toolbar = findViewById(R.id.toolbar); - showToolbar(toolbar,R.string.app_name,false); - - manageRecyclerView(true,true); - - parserMaker = new ParserMaker(MainActivity.this,urls, - Toast.makeText(MainActivity.this, "Can't get all articles from sites...", Toast.LENGTH_SHORT), - this.newsAdapter,this.newsList); - - parserMaker.create(); - - refreshLayout.setRefreshing(true); - manageRefreshLayout(parserMaker); - } - - - @Override - protected void onDestroy() { - super.onDestroy(); - if(newsList!=null){ - newsList.clear(); - } - parserMaker.setActivity(null); - } - - @Override - protected void onResume() { - super.onResume(); - parserMaker.setActivity(parserMaker.isRunning() ? MainActivity.this:null); - } - - @Override - protected void onPause() { - super.onPause(); - parserMaker.setActivity(parserMaker.isRunning() ? MainActivity.this:null); - } - - @Override - public void onBackPressed() { - if(webView.getVisibility() == View.INVISIBLE || webView.getVisibility() == View.GONE){ - if(parserMaker.isRunning()){ - //Bugfix for parserMaker's activity setting to null when onBackPressed. This puts MainActivity on stack, but there's - //no other activity, so basic funcionality of onBackPressed() stays the same... - moveTaskToBack(true); - } - else{ - super.onBackPressed(); - } - } - } - - private void showToolbar(Toolbar toolbar, int title, boolean upButton){ - setSupportActionBar(toolbar); - getSupportActionBar().setTitle(title); - getSupportActionBar().setDisplayHomeAsUpEnabled(upButton); - Log.d(TAG,"Title: "+getSupportActionBar().getTitle().toString()); - progressBar = findViewById(R.id.toolbarProgressBar); - progressBar.setVisibility(View.GONE); - progressBar.setIndeterminate(false); - } - - private void manageRecyclerView(boolean autoMeasure, boolean fixedSize) { - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); - layoutManager.setAutoMeasureEnabled(autoMeasure); - - recyclerView.setLayoutManager(layoutManager); - recyclerView.setAdapter(newsAdapter); - recyclerView.setHasFixedSize(fixedSize); - - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - if(dy > 0 && fab.getVisibility() == View.VISIBLE){ - fab.setVisibility(View.INVISIBLE); - Log.d(TAG,"Entré para esconder"+fab.getVisibility()); - } - else if(dy < 0 && fab.getVisibility() != View.VISIBLE){ - Log.d(TAG,"Entré para mostrar"+fab.getVisibility()); - fab.setVisibility(View.VISIBLE); - } - super.onScrolled(recyclerView, dx, dy); - } - /* - hide() and show() are two methods provided by the FAB to hide/show the FAB button with a smooth animation. - dy is a value that changes when you scroll vertically, when the user scrolls down the value is positive - and when the user scrolls up the value is negative. - So we check if the FAB is visible and the value is positive(i.e. user is scrolling down) - we will hide it and if the FAB is hidden and the value is negative(i.e. user is scrolling up) we will show the FAB. - */ - }); - } - - private void manageRefreshLayout(final ParserMaker parserMaker) { - refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if(isNetworkAvailable() && !parserMaker.isRunning()) { - refreshLayout.setRefreshing(true); - if(parserMaker.getActivity() == null) - parserMaker.setActivity(MainActivity.this); - parserMaker.create(); - } - else if(!isNetworkAvailable()){ - AlertDialog dialog = generateDialog("Check your internet connection"); - dialog.show(); - refreshLayout.setRefreshing(false); - } - else if(parserMaker.isRunning()){ - AlertDialog dialog = generateDialog("App is still refreshing"); - dialog.show(); - refreshLayout.setRefreshing(false); - } - } - }); - } - - private boolean isNetworkAvailable() { - ConnectivityManager connectivityManager - = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); - return activeNetworkInfo != null; - } - - private AlertDialog generateDialog(String message) - { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(message); - builder.setNeutralButton("OK", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - } - }); - return builder.create(); - } - - private NewsAdapter.NewsViewHolder.OnItemClickListener clickListener() { - return new NewsAdapter.NewsViewHolder.OnItemClickListener() { - @Override - public void OnItemClick(NewsModel item) { - getSupportActionBar().setTitle("Loading..."); - progressBar.setVisibility(View.VISIBLE); - WebSettings webSettings = webView.getSettings(); - webSettings.setJavaScriptEnabled(true); - - if(fab.getVisibility() == View.VISIBLE) - fab.setVisibility(View.INVISIBLE); - - webView.setWebChromeClient(new WebChromeClient(){ - @Override - public void onProgressChanged(WebView view, int newProgress) { - super.onProgressChanged(view, newProgress); - progressBar.setProgress(newProgress); - if(newProgress == 100){ - progressBar.setVisibility(View.GONE); - getSupportActionBar().setTitle(R.string.app_name); - } - } - } - ); - - webView.setWebViewClient(new WebViewClient() { - public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { - Toast.makeText(getApplicationContext(), "Oh no! " + description, Toast.LENGTH_SHORT).show(); - } - }); - - webView.setOnKeyListener(new View.OnKeyListener() { - @Override - public boolean onKey(View view, int i, KeyEvent keyEvent) { - if(i == KeyEvent.KEYCODE_BACK){ - webView.loadUrl("about:blank"); - progressBar.setVisibility(View.GONE); - webView.setVisibility(View.GONE); - recyclerView.setVisibility(View.VISIBLE); - refreshLayout.setEnabled(true); - getSupportActionBar().setTitle(R.string.app_name); - return true; - } - else{ - return false; - } - } - }); - - webView.loadUrl(item.getLink()); - recyclerView.setVisibility(View.INVISIBLE); - webView.setVisibility(View.VISIBLE); - refreshLayout.setEnabled(false); - } - }; - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/Models/Categories.java b/app/src/main/java/com/example/emmanuel/gamingnews/Models/Categories.java new file mode 100644 index 0000000..d2b6b85 --- /dev/null +++ b/app/src/main/java/com/example/emmanuel/gamingnews/Models/Categories.java @@ -0,0 +1,73 @@ +package com.example.emmanuel.gamingnews.Models; + +import java.util.Arrays; + +public class Categories { + private String language; + private String[] all_urls; + private String[] ps4_urls; + private String[] xboxO_urls; + private String[] switch_urls; + private String[] pc_urls; + + public Categories(String language, String[] all_urls) { + this.language = language; + this.all_urls = all_urls; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String[] getAll_urls() { + return all_urls; + } + + public void setAll_urls(String[] all_urls) { + this.all_urls = all_urls; + } + + public String[] getPs4_urls() { + return ps4_urls; + } + + public void setPs4_urls(String[] ps4_urls) { + this.ps4_urls = ps4_urls; + } + + public String[] getXboxO_urls() { + return xboxO_urls; + } + + public void setXboxO_urls(String[] xboxO_urls) { + this.xboxO_urls = xboxO_urls; + } + + public String[] getSwitch_urls() { + return switch_urls; + } + + public void setSwitch_urls(String[] switch_urls) { + this.switch_urls = switch_urls; + } + + public String[] getPc_urls() { + return pc_urls; + } + + public void setPc_urls(String[] pc_urls) { + this.pc_urls = pc_urls; + } + + @Override + public String toString() { + return "Categories{" + + "language='" + language + '\'' + + ", all_urls=" + Arrays.toString(all_urls) + + '}'; + } +} diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/Objects/LoadUrls.java b/app/src/main/java/com/example/emmanuel/gamingnews/Objects/LoadUrls.java new file mode 100644 index 0000000..cc99ac7 --- /dev/null +++ b/app/src/main/java/com/example/emmanuel/gamingnews/Objects/LoadUrls.java @@ -0,0 +1,89 @@ +package com.example.emmanuel.gamingnews.Objects; + +import android.app.Activity; + +import com.example.emmanuel.gamingnews.Models.Categories; +import com.google.gson.Gson; + +import java.io.IOException; +import java.io.InputStream; + +public class LoadUrls { + private String language; + private InputStream jsonFile; + private String[] allUrls; + private String[] ps4Urls; + private String[] xboxOUrls; + private String[] switchUrls; + private String[] pcUrls; + + public LoadUrls(String language, InputStream jsonFile){ + this.language = language; + this.jsonFile = jsonFile; + } + private Categories[] loadCategories(){ + Gson gson = new Gson(); + return gson.fromJson(loadJSONFromAsset(),Categories[].class); + } + private Categories getLocalCategory(){ + Categories[] categories = loadCategories(); + Categories category = null; + for(Categories cat:categories){ + if(cat.getLanguage().equals(language)){ + category = cat; + break; + } + else if(cat.getLanguage().equals("en") && category == null){ + category = cat; + } + } + return category; + } + + public void setUrls(){ + Categories category = getLocalCategory(); + allUrls = category.getAll_urls(); + ps4Urls = category.getPs4_urls(); + xboxOUrls = category.getXboxO_urls(); + switchUrls = category.getSwitch_urls(); + pcUrls = category.getPc_urls(); + } + + private String loadJSONFromAsset() { + String json = null; + try { + InputStream is = jsonFile; + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + return json; + } catch (IOException ex) { + ex.printStackTrace(); + } + return json; + } + + + public String[] getAllUrls() { + return allUrls; + } + + public String[] getPs4Urls() { + return ps4Urls; + } + + public String[] getXboxOUrls() { + return xboxOUrls; + } + + public String[] getSwitchUrls() { + return switchUrls; + } + + public String[] getPcUrls() { + return pcUrls; + } + +} diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/Utility/ParserMaker.java b/app/src/main/java/com/example/emmanuel/gamingnews/Utility/ParserMaker.java index 98a599f..a1ae53a 100644 --- a/app/src/main/java/com/example/emmanuel/gamingnews/Utility/ParserMaker.java +++ b/app/src/main/java/com/example/emmanuel/gamingnews/Utility/ParserMaker.java @@ -1,6 +1,7 @@ package com.example.emmanuel.gamingnews.Utility; import android.app.Activity; +import android.content.Context; import android.support.v4.widget.SwipeRefreshLayout; import android.text.Html; import android.util.Log; @@ -9,6 +10,7 @@ import com.example.emmanuel.gamingnews.Adapter.NewsAdapter; import com.example.emmanuel.gamingnews.Models.NewsModel; import com.example.emmanuel.gamingnews.R; +import com.example.emmanuel.gamingnews.views.MainActivity; import com.prof.rssparser.Article; import com.prof.rssparser.Parser; @@ -16,6 +18,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.logging.Handler; public class ParserMaker{ @@ -23,28 +26,26 @@ public class ParserMaker{ private static final String TAG = "ParserMaker"; private static final int OBJ_NUMBER = 65532; - private Activity activity; private String[] urls; private Toast toast; private NewsAdapter newsAdapter; private boolean running; private boolean firstRun; - private boolean error; private boolean newItems; private List newsList; + private OnNewsFinishListener onNewsFinishListener; - public ParserMaker(Activity activity,String[] urls, Toast toast, NewsAdapter newsAdapter, List newsList){ - firstRun = true; + public ParserMaker(OnNewsFinishListener onNewsFinishListener,String[] urls, Toast toast, NewsAdapter newsAdapter, List newsList){ + firstRun = newsList.isEmpty(); this.urls = urls; - this.activity = activity; + this.onNewsFinishListener = onNewsFinishListener; this.toast = toast; this.newsAdapter = newsAdapter; this.newsList = newsList; } public void create(){ running = true; - error = false; newItems = false; Parser[] parsers = new Parser[urls.length]; for (int i = 0;i list) { - if(firstRun){ + if(newsList.isEmpty()){ newItems = true; for(com.prof.rssparser.Article article:list){ newsList.add(new NewsModel(article.getImage() == null ? "":article.getImage(),article.getTitle(), @@ -84,10 +85,7 @@ public void onTaskCompleted(ArrayList
list) { } Log.d(TAG,"Size: "+newsList.size()+" Count: "+newsAdapter.getItemCount()); if(stopRefresh){ - if(error){ - toast.show(); - } - if(firstRun || newItems){ + if(newItems){ newItems = false; firstRun = false; orderListRecentFirst(); @@ -99,12 +97,9 @@ public void onTaskCompleted(ArrayList
list) { @Override public void onError() { - error = true; - if(stopRefresh){ - if(newsList.size() != 0){ - firstRun = false; - } - toast.show(); + toast.show(); + if(stopRefresh) { + firstRun = !newsList.isEmpty(); refreshingStatus(); } } @@ -134,7 +129,6 @@ private void orderListRecentFirst() { Collections.sort(newsList, new Comparator() { @Override public int compare(NewsModel newsModel, NewsModel t1) { - Log.d(TAG,"ENTRÉ A COMPARAR"); if(newsModel.getPubDate() != null && t1.getPubDate() != null){ return t1.getPubDate().compareTo(newsModel.getPubDate()); } @@ -146,25 +140,26 @@ public int compare(NewsModel newsModel, NewsModel t1) { } private void refreshingStatus(){ - activity.runOnUiThread(new Runnable() { + onNewsFinishListener.onNewsFinish(); + /*activity.runOnUiThread(new Runnable() { @Override public void run() { ((SwipeRefreshLayout)activity.findViewById(R.id.refreshlayout)).setRefreshing(false); running = false; } - }); - - } - public Activity getActivity() { - return activity; + });*/ } - public void setActivity(Activity activity){ - this.activity = activity; + public void setRunning(boolean running) { + this.running = running; } public boolean isRunning() { return running; } + public interface OnNewsFinishListener{ + void onNewsFinish(); + } + } diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/views/MainActivity.java b/app/src/main/java/com/example/emmanuel/gamingnews/views/MainActivity.java new file mode 100644 index 0000000..4f44876 --- /dev/null +++ b/app/src/main/java/com/example/emmanuel/gamingnews/views/MainActivity.java @@ -0,0 +1,147 @@ +package com.example.emmanuel.gamingnews.views; + +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.design.widget.NavigationView; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.ProgressBar; + +import com.example.emmanuel.gamingnews.Fragments.NewsListFragment; +import com.example.emmanuel.gamingnews.Objects.LoadUrls; +import com.example.emmanuel.gamingnews.R; + + + +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; + +public class MainActivity extends AppCompatActivity implements NewsListFragment.OnFragmentInteractionListener { + + private static final String TAG = "MainActivity"; + private static final String[] News_TAG = {"NewsListFragment_All","NewsListFragment_PS4","NewsListFragment_XboxO", + "NewsListFragment_Switch","NewsListFragment_PC" + }; + + private DrawerLayout drawerLayout; + private ProgressBar progressBar; + private LoadUrls loadUrls; + private NavigationView navigationView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + Toolbar toolbar = findViewById(R.id.toolbar); + navigationView = findViewById(R.id.navigation_view); + showToolbar(toolbar, R.string.app_name, false); + startDrawerLayout(toolbar); + InputStream is = null; + loadUrls = null; + try { + is = getAssets().open("Urls.json"); + loadUrls = new LoadUrls(Locale.getDefault().getLanguage(), is); + loadUrls.setUrls(); + } catch (IOException e) { + e.printStackTrace(); + } + startNavigationView(); + makeFragmentTransaction(loadUrls.getAllUrls(), R.id.all_news,News_TAG[0]); + } + + + @Override + public void onBackPressed() { + NewsListFragment fragment = null; + for(int i = 0;i<5;i++){ + fragment = (NewsListFragment) getSupportFragmentManager().findFragmentByTag(News_TAG[i]); + if(fragment!=null){ + break; + } + } + if (getSupportFragmentManager().getBackStackEntryCount() > 1) { + getSupportFragmentManager().popBackStack(); + } else { + if (fragment.getParserMaker().isRunning()) { + moveTaskToBack(true); + } else { + finish(); + } + } + } + + private void showToolbar(Toolbar toolbar, int title, boolean upButton) { + setSupportActionBar(toolbar); + getSupportActionBar().setTitle(title); + getSupportActionBar().setDisplayHomeAsUpEnabled(upButton); + getSupportActionBar().setLogo(R.mipmap.ic_launcher_round); + toolbar.getLogo().setBounds(3, 3, 3, 3); + Log.d(TAG, "Title: " + getSupportActionBar().getTitle().toString()); + progressBar = findViewById(R.id.toolbarProgressBar); + progressBar.setVisibility(View.GONE); + progressBar.setIndeterminate(false); + } + + + private void startDrawerLayout(Toolbar toolbar) { + drawerLayout = findViewById(R.id.drawer_layout); + ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, + toolbar, R.string.drawer_open, R.string.drawer_close); + drawerLayout.addDrawerListener(drawerToggle); + drawerToggle.syncState(); + } + + private void startNavigationView() { + navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.all_news: + makeFragmentTransaction(loadUrls.getAllUrls(), R.id.all_news,News_TAG[0]); + break; + case R.id.ps4_news: + makeFragmentTransaction(loadUrls.getPs4Urls(), R.id.all_news,News_TAG[1]); + break; + case R.id.xboxo_news: + makeFragmentTransaction(loadUrls.getXboxOUrls(), R.id.all_news,News_TAG[2]); + break; + case R.id.switch_news: + makeFragmentTransaction(loadUrls.getSwitchUrls(), R.id.all_news,News_TAG[3]); + break; + case R.id.PC_news: + makeFragmentTransaction(loadUrls.getPcUrls(), R.id.all_news,News_TAG[4]); + break; + } + return true; + } + }); + } + + private void makeFragmentTransaction(String[] urls, int item, String TAG) { + Bundle bundle = new Bundle(); + bundle.putStringArray("urls", urls); + NewsListFragment newsFragment = (NewsListFragment) getSupportFragmentManager().findFragmentByTag(TAG); + if(newsFragment == null){ + newsFragment = new NewsListFragment(); + } + newsFragment.setArguments(bundle); + getSupportFragmentManager().beginTransaction() + .replace(R.id.container, newsFragment, TAG) + .addToBackStack(null) + .commit(); + navigationView.setCheckedItem(item); + drawerLayout.closeDrawers(); + } + + @Override + public void onFragmentInteraction(Uri uri) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/emmanuel/gamingnews/views/WebViewActivity.java b/app/src/main/java/com/example/emmanuel/gamingnews/views/WebViewActivity.java new file mode 100644 index 0000000..9b6a0c5 --- /dev/null +++ b/app/src/main/java/com/example/emmanuel/gamingnews/views/WebViewActivity.java @@ -0,0 +1,87 @@ +package com.example.emmanuel.gamingnews.views; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.View; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.ProgressBar; +import android.widget.Toast; + +import com.example.emmanuel.gamingnews.R; + +public class WebViewActivity extends AppCompatActivity { + private static final String TAG = "WebViewActivity"; + + private WebView webView; + private ProgressBar progressBar; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_web_view); + Toolbar toolbar = findViewById(R.id.toolbar); + showToolbar(toolbar,R.string.loading,true); + webView = findViewById(R.id.webview); + String url = getIntent().getExtras().getString("url"); + loadUrl(url); + } + + @Override + public void onBackPressed() { + if (webView.canGoBack()) { + webView.goBack(); + return; + } + // Otherwise defer to system default behavior. + webView.loadUrl("about:blank"); + super.onBackPressed(); + } + private void showToolbar(Toolbar toolbar, int title, boolean upButton){ + setSupportActionBar(toolbar); + getSupportActionBar().setTitle(title); + getSupportActionBar().setDisplayHomeAsUpEnabled(upButton); + getSupportActionBar().setLogo(R.mipmap.ic_launcher_round); + Log.d(TAG,"Title: "+getSupportActionBar().getTitle().toString()); + progressBar = findViewById(R.id.toolbarProgressBar); + progressBar.setVisibility(View.INVISIBLE); + progressBar.setIndeterminate(false); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Log.d(TAG,"Entré a terminar "); + finish(); + } + }); + } + + private void loadUrl(String url) { + progressBar.setVisibility(View.VISIBLE); + WebSettings webSettings = webView.getSettings(); + webSettings.setJavaScriptEnabled(true); + webView.setWebChromeClient(new WebChromeClient(){ + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + progressBar.setProgress(newProgress); + if(newProgress == 100){ + progressBar.setVisibility(View.GONE); + getSupportActionBar().setTitle(R.string.app_name); + } + } + } + ); + + webView.setWebViewClient(new WebViewClient() { + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + Toast.makeText(WebViewActivity.this, "Oh no! " + description, Toast.LENGTH_SHORT).show(); + } + }); + + webView.loadUrl(url); + webView.setVisibility(View.VISIBLE); + } +} diff --git a/app/src/main/res/layout/actionbar_toolbar.xml b/app/src/main/res/layout/actionbar_toolbar.xml index 59cd92c..2644284 100644 --- a/app/src/main/res/layout/actionbar_toolbar.xml +++ b/app/src/main/res/layout/actionbar_toolbar.xml @@ -13,16 +13,6 @@ android:layout_height="match_parent" android:orientation="horizontal" > - - - - + android:layout_height="match_parent"> + + - - - - - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_web_view.xml b/app/src/main/res/layout/activity_web_view.xml new file mode 100644 index 0000000..ced8d84 --- /dev/null +++ b/app/src/main/res/layout/activity_web_view.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/cardview_news.xml b/app/src/main/res/layout/cardview_news.xml index bbfb22a..acf90dd 100644 --- a/app/src/main/res/layout/cardview_news.xml +++ b/app/src/main/res/layout/cardview_news.xml @@ -20,7 +20,7 @@ @@ -36,14 +36,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/colorPrimaryLight" - android:textSize="20sp" + android:textSize="@dimen/primary_text_cardv" /> diff --git a/app/src/main/res/layout/fragment_news_list.xml b/app/src/main/res/layout/fragment_news_list.xml new file mode 100644 index 0000000..5b69331 --- /dev/null +++ b/app/src/main/res/layout/fragment_news_list.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/navigation_menu.xml b/app/src/main/res/menu/navigation_menu.xml new file mode 100644 index 0000000..81d516b --- /dev/null +++ b/app/src/main/res/menu/navigation_menu.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 943e4e8..83ad343 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,5 +1,16 @@ Gaming News - Image from this news + Imagen de la noticia + All + PS4 + Xbox One + Nintendo Switch + PC + Abrir navigation drawer + Cerrar navigation drawer + Cargando... + No se obtuvieron todos los artículos de un sitio... + Revisa tu conexión a internet + Aún se esta recargando. \ 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 aa1e51c..0b9c0ba 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,4 +2,9 @@ 12dp 12dp + 10sp + 20sp + 300dp + 10dp + 16dp \ 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 8d413af..3251a4a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,18 @@ Gaming News Image from this news + All + PS4 + Xbox One + Nintendo Switch + PC + Open navigation drawer + Close navigation drawer + + + Hello blank fragment + Loading... + Can\'t get all articles from sites... + Check your internet connection + App is still refreshing