Reimplementing CrytpoNews in Native Android (UPDATE #2 : ADDED SETTINGS CUSTOMIZATION)

in #utopian-io4 years ago (edited)

@princessdharmy and I decided to build a native version of CryptoNews originally started by @johnesan in xamarin(which was discontinued due to being a cross platform framework, it comes with so many limitations that makes the application unable to fully harness the power of native functionalities).

History

The aim of the application is to fetch news feed from preferred blogs and display on the application. it is structured in such a way that you can scroll through them like you would do on your social media timeline. It also leverages you the ability to read any of these news

Updates and New Features

  • User can now test a Website before Saving it

Before this update, this feature was not available. A User can can now Test a website if he wishes to use a different website other than the default 4 we provided.
Group 29.png

  • How it was implemented

First I Created a PreferenceUtils Class to hold title and Url, I used SharedPreferences to save this Url as saving them to a database was not entirely necessary for this case.

public class PreferenceUtils {


    private SharedPreferences mSharedPreferences;
    private SharedPreferences mSharedPreferencesTest;

    public static final String  FIRST_URL = "first_url";
    public static final String  SECOND_URL = "second_url";
    public static final String  THIRD_URL = "third_url";
    public static final String  FOURTH_URL = "fourth_url";
    public static  final String TEST_URL = "test_url";

    public static final String  FIRST_TITLE = "first_title";
    public static final String  SECOND_TITLE = "second_title";
    public static final String  THIRD_TITLE = "third_title";
    public static final String  FOURTH_TITLE = "fourth_title";

    public static  final String URLCHANGED = "url_change";

    public static final String NEWS_WAS_STORED = "news_was_Stored";

    @Inject
    public PreferenceUtils(Context context) {
        mSharedPreferences = context.getSharedPreferences("cryptoNews_key",
                Context.MODE_PRIVATE);
        mSharedPreferencesTest = PreferenceManager.getDefaultSharedPreferences(context);
    }
 public void storeFirstUrl(String url) {
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putString(FIRST_URL, url);
        editor.apply();
    }
  public void storeFirstTitle(String url) {
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putString(FIRST_TITLE, url);
        editor.apply();
    } 

    public String getFirstTitle (){
        return  mSharedPreferences.getString(FIRST_TITLE, "CCN");
    }
 public String getFirstUrl(){
        return  mSharedPreferences.getString(FIRST_URL, "https://ccn.com");
}

..........Complete Code in Repo ..............
}

Secondly I provided a separate Retrofit service to make the Api Call to see if the desired url returned the Appropriate data. As you can notice the testUrl is passed to the method and the cal is made in CheckValidUrl class.

public class TestWebServiceNoDagger {

    public static  TestApiService provideTestWebService(String testUrl){
        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(testUrl)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(providesOkHttpClientBuilder());

        return  builder.build().create(TestApiService.class);
    }

}
public class CheckValidUrlRepository {


    PreferenceUtils preferenceUtils = new PreferenceUtils(AppController.getContextInstance());


    TestApiService newsApiService  = TestWebServiceNoDagger.
            provideTestWebService(preferenceUtils.getTestUrl());

    boolean isValidUrl;


    public CheckValidUrlRepository() {

    }

    public LiveData<List<News>> isValidUrl(){
        MutableLiveData<List<News>> newsMutableLiveData = new MutableLiveData<>();
        newsApiService.getLatestNews()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<List<News>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(List<News> news) {
                        newsMutableLiveData.setValue(news);

                    }

                    @Override
                    public void onError(Throwable e) {
                        newsMutableLiveData.setValue(null);
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "onComplete was reached");

                    }
                });
        return  newsMutableLiveData;

    }
}

In the Fragment i am checking too see if the data returned from the livedata is null. If its null the testurl failed the test and the user is not allowed to save the Url.
We didnt use Dagger to provide the instances of the repository class because we want to be abe to change the data during runtime without restarting the activity.

  • User Can save Website

The user can easily save the new url to the Sharedpreferences and is done here

 //Save the new data to the appropriate preference
        binding.get().saveButton.setOnClickListener(view -> {
            savedItem = true;
            listener.onBackPressed(savedItem);
            switch (value){
                case  FIRST_URL:
                    preferenceUtils.storeFirstUrl(binding.get().websiteUrl.getText().toString());
                    preferenceUtils.storeFirstTitle(binding.get().websiteTitle.getText().toString());
                    break;
                case SECOND_URL:
                    preferenceUtils.storeSecondTitle(binding.get().websiteUrl.getText().toString());
                    preferenceUtils.storeSecondUrl(binding.get().websiteTitle.getText().toString());
                    break;
                case THIRD_URL:
                    preferenceUtils.storeThirdUrl(binding.get().websiteUrl.getText().toString());
                    preferenceUtils.storeThirdTitle(binding.get().websiteTitle.getText().toString());
                    break;
                case  FOURTH_URL:
                    preferenceUtils.storeFourthUrl(binding.get().websiteUrl.getText().toString());
                    preferenceUtils.storeFourthTitle(binding.get().websiteTitle.getText().toString());
                    break;
                default:
                    break;
            }
  • User Can Choose What Font Size to use

We want to give the User a complete control on how the news appears on the app so we added a Font Size Feature. This is Experimental because the Ui may be a little distorted as it still needs a little tweaking.

How i was Implemented

Once the user Selects a Font size in the settings and returns to the MainActivity, i placed the code to check if the user has changed the font in the onResume Method as this method is being called first according to Android LifeCycle Processes.
The code is shown below

@Override
    public void onResume() {
        super.onResume();

        //refresh if font size Changed

        if(refreshFontSize()){
            if (mAdapter == null) {
                mAdapter = new NewsAdapter(getContext());
            }
                mAdapter.setFontSizes(mFontSizeTitle, mFontSizeDetails);
                mAdapter.notifyDataSetChanged();
//                Toast.makeText(getContext(), preferenceUtils.getFontSize(), Toast.LENGTH_SHORT).show();

        }

    }

If the check passes, the adapter is notified, and the font size is set automatically. Here is the method for the font sizes.

 private boolean refreshFontSize() {
        final String fontSize = preferenceUtils.getFontSize();
        if ((mCurrentFontSize == null || (!mCurrentFontSize.equals(fontSize)))){
            mCurrentFontSize = fontSize;

            if (fontSize.equals("0")){
                mFontSizeTitle = 10;
                mFontSizeDetails = 9;
            }else  if (fontSize.equals("1"))
            {mFontSizeTitle = 13;
                mFontSizeDetails = 10;}
                else {
                mFontSizeTitle = 14;
                mFontSizeDetails = 11;
            }
            return true;
        }else {

            return false;
        }
    }

In the adapter this line of code is added to set the Font size

   holder.date.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mFontSizeDetails);
  • User Can choose to read Article inApp or through Favorite Browser
    We want to be able to give a user the opportunity choose where the News should be read from since different browsers renders pages differently. A user may prefer another way.

How it was implemented

We implement this in the NewsAdapter in the onClick method.
we checked if the user preference in the settings was In App or Web Browsers then we take the user to where the preferred choice.
This is shown below.

     @Override
        public void onClick(View v) {
            Context context = v.getContext();
            Intent intent = new Intent(context, NewsWebPageActivity.class);

            News data = newsList.get(getLayoutPosition());

            //Get the link of the website to be opened on the Web page
            String link = data.getGuid().getRendered();
            //Get the title of each news and format it to normal characters
            String title = String.valueOf(Html.fromHtml(data.getTitle().getRendered()));

            if (!preferenceUtils.getViewNewsWithIn().equals("0")){
                openURLInBrowser(link);
            }else {
            //Pass the title and link to the next activity
            intent.putExtra("url", link);
            intent.putExtra("title", title);
            context.startActivity(intent);
            }
        }

        private void openURLInBrowser(String url) {
            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            context.startActivity(browserIntent);
        }
    }

The OpenURLInBrowser() method takes the user to action screen where he selects a browser to use.

videotogif_2018.03.20_16.18.02.gif

Roadmap

  • Searching all news
  • Persisting user news
  • Providing different layouts
  • Providing different themes for user
  • Push Notifications
  • News Posts sharing
  • Incorporating more news and giving the user the flexibility of deciding what he wants to read per time.

Resources

  • Github Commits - List of commits can be found here
  • Apk for download - Download here



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

Great post, very descriptive! Keep up the good work!

You can contact us on Discord.
[utopian-moderator]

Hey @mathemandy I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x