How to build Android Dictionary App from Scratch

In this episode on how to build app from scratch, we are going to create an android dictionary app.

Android dictionary app is a utility app that helps users to understand the meaning of certain word or term.

Although, we can just have terms and their meaning in the app but we need to rich our android dictionary app so that it will contain the features below.

Dictionary App Features

  1. Terms and meaning
  2. Text to Voice
  3. Ability to save favorite word
  4. Ability to delete favorite word
  5. Ability to share it with your friends and families
  6. Ability to search word / term
  7. Built in Wikipedia reference
  8. You can create your own word and its meaning
  9. Ability to send feedback 
  10. Simple and sleek design

Hand sketch of our Dictionary App 

Dictionary App Screenshot

App Video Recording

1. CREATE A NEW ANDROID PROJECT

  • Open Android Studio
  • Go to file menu
  • Select  new
  • Enter project name 
  • Enter activity name
  • Keep other default settings
  • Click on finish button to create a new android project

2. ADD LIBRARY DEPENDENCIES IN BUILD.GRADLE

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    //implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.google.android.material:material:1.1.0-alpha01'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
    //Recycler view
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    //Room persistence data
    implementation 'androidx.room:room-common:2.0.0-rc01'
    implementation 'androidx.room:room-runtime:2.0.0-rc01'
    annotationProcessor "androidx.room:room-compiler:2.0.0-rc01"
    implementation 'android.arch.lifecycle:livedata:1.1.1'
    //Sqlite database
    implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
    //fast Adapter
    implementation 'com.mikepenz:fastadapter:3.3.1'
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation 'com.mikepenz:fastadapter-commons:3.3.1'
    //View binding
    implementation 'com.jakewharton:butterknife:8.8.1'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0-alpha1'
    annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"

    //debug db
    debugImplementation 'com.amitshekhar.android:debug-db:1.0.3'


    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}

3. UPDATE COLORS.XML

Open res folder > strings.xml and add the code below to it.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#00796b</color>
    <color name="colorPrimaryDark">#004c40</color>
    <color name="colorAccent">#37464f</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBlack">#000000</color>
    <color name="colorDark">#666666</color>
    <color name="colorSecondary">#62717b</color>
    <color name="colorBackground">#cfd8dc</color>
</resources>

4. UPDATE STYLES.XML

Open res folder > styles.xml and add the code below to it.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>

4. UPDATE DIMENS.XML

Open res folder > dimens.xml and add the code below to it.

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="nav_header_vertical_spacing">8dp</dimen>
    <dimen name="nav_header_height">176dp</dimen>
    <dimen name="fab_margin">16dp</dimen>
</resources>

5. UPDATE DRAWABLES.XML

Open res folder > drawables.xml and add the code below to it.

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
    <item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
    <item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
    <item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
    <item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
    <item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
</resources>

Create Splash / Intro Page 

The application starts with an intro page which delays for 2 seconds before it navigates to the main page of the app.

Open the default MainActivity.java and its layout file – activity_main.xml and paste the code below.

MainActivity.java

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private static final int SPLASH_TIME = 2000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        super.onCreate(savedInstanceState);


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();
        if(null != actionBar){
            actionBar.hide();
        }

        Handler handler = new Handler();
        handler.postDelayed(() -> {
            Intent intent = new Intent(MainActivity.this, BoardActivity.class);
            startActivity(intent);
            finish();
        }, SPLASH_TIME);
    }
}

The layout file contains two TextViews and an ImageView. Open activitiy_main.xml and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground"
tools:context=".MainActivity">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="20dp"
    tools:ignore="UseCompoundDrawables">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/logo"
        android:contentDescription="@string/app_name"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Simple Dictionary"
        android:textColor="@color/colorBlack"
        android:textAllCaps="true"
        android:layout_marginTop="10dp"
        android:textSize="15sp"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:layout_marginTop="4dp"
        android:textColor="@color/colorAccent"
        android:text="From Inducesmile.com"/>

</LinearLayout>

</FrameLayout>

Create Navigation Drawer with Page Links

Create a new Activity class. We are going to use the default Android Studio template for Navigation Drawer.

Right click on your project > New > Activity > Navigation Drawer Activity.

Enter a name for the activity class and click Ok button.

Modify the Navigation Drawer Link

Go to res folder > menu > activity_board_drawer.xml. Double click the file to open it in Android Studio.

Copy and paste the code below to the file

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_dictionary"
            android:icon="@drawable/ic_book_grey_500_24dp"
            android:title="Dictionary" />

        <item
            android:id="@+id/nav_create"
            android:icon="@drawable/ic_storage_grey_500_24dp"
            android:title="Create Your Dictionary" />

        <item
            android:id="@+id/nav_favorite"
            android:icon="@drawable/ic_favorite_grey_500_24dp"
            android:title="Favorite" />

    </group>

    <item android:title="Get in touch">
        <menu>
            <item
                android:id="@+id/nav_share"
                android:icon="@drawable/ic_menu_share"
                android:title="Share" />
            <item
                android:id="@+id/nav_feedback"
                android:icon="@drawable/ic_menu_send"
                android:title="Feedback" />
        </menu>
    </item>

</menu>

Modify Navigation Drawer Header

We are going to change the default navigation drawer Android Studio generated for us.

Go to res folder > layout folder > nav_header.xml. Open the file and paste the code below to it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="256dp"
    android:background="@color/colorSecondary"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/nav_header_desc"
        android:paddingTop="@dimen/nav_header_vertical_spacing"
        app:srcCompat="@drawable/logo" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/nav_header_vertical_spacing"
        android:layout_gravity="center"
        android:text="@string/nav_header_title"
        android:textColor="@color/colorWhite"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:textStyle="italic"
        android:textColor="@color/colorBackground"
        android:text="From Inducesmile.com" />

</LinearLayout>

Create Required Fragment Classes for Navigation Drawer

We are going to create four Fragment classes – Dictionary page, add word page, Favorite page and Feedback page.

We will start with the dictionary page.

Create a new Fragment class for Dictionary Word List

Create a new folder by going to New > Directory. In the dialog box that opens name the directory fragment or any name of your choice.

Create a new Fragment file inside the created directory and name it dictionary or any word of your choice.

Go to New > Fragment > Blank Fragment and name your Fragment. I named mine Dictionary since it s the name of the application we are working.

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
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 com.inducesmile.simpledictionary.DictionaryActivity;
import com.inducesmile.simpledictionary.R;
import com.inducesmile.simpledictionary.appUtils.Constants;



public class WordListFragment extends Fragment {


    private static final String TAG = WordListFragment.class.getSimpleName();

    private RecyclerView recyclerView;
    private FastAdapter fastAdapter;
    private ItemAdapter<SimpleItem> itemAdapter;

    public static WordListFragment getInstance() {
        WordListFragment wordListFragment = new WordListFragment();
        Bundle bundle = new Bundle();
        wordListFragment.setArguments(bundle);
        return wordListFragment;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_word_list, container, false);

        setHasOptionsMenu(true);

        Objects.requireNonNull(getActivity()).setTitle("Dictionary");

        recyclerView = (RecyclerView)view.findViewById(R.id.dictionary_words);

        setUpRecyclerView();

        itemAdapter.getItemFilter().withFilterPredicate(new IItemAdapter.Predicate<SimpleItem>() {
            @Override
            public boolean filter(@NonNull SimpleItem item, CharSequence constraint) {
                String userInput = String.valueOf(constraint);
                return item.name.toLowerCase().startsWith(userInput.toLowerCase());
            }
        });

        return view;
    }

    private void setUpRecyclerView(){
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setHasFixedSize(true);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        addAdapterToView();
    }

    private void addAdapterToView(){
        itemAdapter = new ItemAdapter<>();
        fastAdapter = FastAdapter.with(itemAdapter);
        recyclerView.setAdapter(fastAdapter);

        fastAdapter.withSelectable(true);
        fastAdapter.withOnClickListener(new OnClickListener<SimpleItem>() {
            @Override
            public boolean onClick(View v, @NonNull IAdapter<SimpleItem> adapter, @NonNull SimpleItem item, int position) {
                Log.d(TAG, "Selected position " + position + " - " + item.name);
                // Handle click here
                Intent dictionaryIntent = new Intent(getActivity(), DictionaryActivity.class);
                dictionaryIntent.putExtra(Constants.WORD, item.name);
                Objects.requireNonNull(getActivity()).startActivity(dictionaryIntent);

                return true;
            }
        });
        itemAdapter.add(getData());
    }

    private List<SimpleItem> getData(){

        DbBackend dbBackend = new DbBackend(getActivity());
        List<SqliteDictionary> allWords = dbBackend.dictionaryWords();

        List<SimpleItem> data = new ArrayList<>();
        if(allWords != null){
            for (SqliteDictionary dic : allWords){
                data.add(new SimpleItem().withName(dic.getWord()));
            }
        }
        return data;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.board, menu);

        MenuItem searchItem = menu.findItem(R.id.search);
        SearchView searchView = (SearchView)searchItem.getActionView();

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                Log.d(TAG, "Submit text : " + query + " Adapter Counter " + itemAdapter.getAdapterItemCount());
                itemAdapter.filter(query);
                Log.d(TAG, "Adapter Counter " + itemAdapter.getAdapterItemCount());
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                Log.d(TAG, "New text : " + newText);
                itemAdapter.filter(newText);
                return true;
            }
        });

        super.onCreateOptionsMenu(menu, inflater);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.search) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Add the Fragment class layout file by going the res folder > layout folder and double click fragment_word_list.xml.

Open the file and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".fragments.WordListFragment">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/dictionary_words"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </androidx.recyclerview.widget.RecyclerView>

</FrameLayout>

When you are done you will end up will a list of words as shown below.

Create Detailed Activity Page

We are going to create a detailed activity page that will display the meaning of a selected word when it is clicked.

Go to New > Activity > Empty Activity and add the name of the activity in the open dialog. 

We will also as icons for share, favorite, text to speech and Wikipedia launcher.

Open the newly created activity and add the code below.

DictionaryActivity.java

public class DictionaryActivity extends AppCompatActivity {

    private static final String TAG = DictionaryActivity.class.getSimpleName();

    private AppCompatTextView meaning;

    private String wordName;

    private TextToSpeech convertToSpeech;

    private DbBackend dbBackend;

    private SqliteDictionary singleDictionary;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dictionary);

        setTitle("Definition");

        ActionBar actionBar = getSupportActionBar();
        if(actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        dbBackend = new DbBackend(DictionaryActivity.this);

        AppCompatTextView word = (AppCompatTextView)findViewById(R.id.main_word);
        Bundle bundle = getIntent().getExtras();
        if(bundle == null){
            Toast.makeText(this, "Missing word", Toast.LENGTH_LONG).show();
        }else{
            String key;
            wordName = bundle.getString(Constants.WORD);
            word.setText(wordName);
        }

        meaning = (AppCompatTextView)findViewById(R.id.meaning);
        singleDictionary = dbBackend.getDictionaryByName(wordName);
        if(singleDictionary != null){
            meaning.setText(singleDictionary.getMeaning());
        }else{
            Toast.makeText(this, "Meaning of a word not found", Toast.LENGTH_LONG).show();
        }

        AppCompatTextView openWikiButtom = (AppCompatTextView)findViewById(R.id.wiki);
        openWikiButtom.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(TextUtils.isEmpty(wordName)){
                    Toast.makeText(DictionaryActivity.this, "No word found to search in wikipedia", Toast.LENGTH_SHORT).show();
                }else{
                    Intent wikiIntent = new Intent(DictionaryActivity.this, WikiActivity.class);
                    wikiIntent.putExtra(Constants.WORD, wordName);
                    startActivity(wikiIntent);
                }
            }
        });

        AppCompatTextView textToVoice = (AppCompatTextView)findViewById(R.id.voice);
        textToVoice.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                convertToSpeech = new TextToSpeech(DictionaryActivity.this, new TextToSpeech.OnInitListener() {
                    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                    @Override
                    public void onInit(int status) {
                        if (status != TextToSpeech.ERROR) {
                            convertToSpeech.setLanguage(Locale.US);
                            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                                convertToSpeech.speak(meaning.getText().toString(), TextToSpeech.QUEUE_FLUSH, null, null);
                            } else {
                                convertToSpeech.speak(meaning.getText().toString(), TextToSpeech.QUEUE_FLUSH, null);
                            }
                        }
                    }
                });
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.option_menu_layout, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_favorite:
                addNewFavourite();
                return true;

            case R.id.action_share:
                shareText(singleDictionary.getWord(), singleDictionary.getMeaning());
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void addNewFavourite(){
        FavouriteModel fModel = new FavouriteModel(this);
        if(singleDictionary.getWord().equals("")){
            Toast.makeText(DictionaryActivity.this, "Favourite failed to add", Toast.LENGTH_SHORT).show();
        }else{
            fModel.addFavourite(singleDictionary.getWord());
            Toast.makeText(DictionaryActivity.this, "Favourite successfully added", Toast.LENGTH_SHORT).show();
        }
    }

    public void shareText(String subject, String body) {
        Intent txtIntent = new Intent(android.content.Intent.ACTION_SEND);
        txtIntent .setType("text/plain");
        txtIntent .putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
        txtIntent .putExtra(android.content.Intent.EXTRA_TEXT, body);
        startActivity(Intent.createChooser(txtIntent ,"Share"));
    }
}

Open the layout file and add the code below.

activity_dictionary.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".DictionaryActivity">

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_above="@+id/bottom_layout"
        android:paddingStart="16dp"
        android:paddingEnd="16dp"
        android:paddingTop="16dp"
        android:orientation="vertical">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/main_word"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Abdomen"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:textSize="16sp"/>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginBottom="12dp"
            android:layout_marginTop="12dp"
            android:background="@color/colorBackground"/>

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/meaning"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:lineHeight="20dp"
            android:text="Abdomen is the part of the human body that is location in the stomach area and it is in the middle part"
            android:textColor="@color/colorDark"
            android:textSize="13sp"/>

    </androidx.appcompat.widget.LinearLayoutCompat>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/bottom_layout"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:padding="8dp"
        android:orientation="horizontal"
        android:background="@color/colorBackground"
        android:layout_alignParentBottom="true">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/wiki"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="12sp"
            android:textColor="@color/colorBlack"
            android:text="WIKI"
            android:drawableTop="@drawable/ic_web_100_24dp"
            android:layout_weight="1"/>

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="12dp"
            android:layout_marginTop="12dp"
            android:background="@color/colorDark"/>

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/voice"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="12sp"
            android:textColor="@color/colorBlack"
            android:text="VOICE"
            android:drawableTop="@drawable/ic_voice_24dp"
            android:layout_weight="1"/>

    </androidx.appcompat.widget.LinearLayoutCompat>

</RelativeLayout>

Create a New Activity to Open Wikipedia

We will create a new Activity class which will receive a word and opens a page of that word if found in Wikipedia.

Create a new activity file by going to New > Activity > Empty Activity.

Name your new activity. Open the file in your editor. Copy and paste the code below to the file.

WikiActivity.java

public class WikiActivity extends AppCompatActivity {

    private static final String TAG = WikiActivity.class.getSimpleName();

    private WebView webView;


    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wiki);

        setTitle("Wikipedia");

        webView = (WebView)findViewById(R.id.wiki_content);

        webView.setWebViewClient(new CustomWebViewClient());

        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setBuiltInZoomControls(true);
        settings.setAllowContentAccess(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            settings.setSafeBrowsingEnabled(true);
        }

        Bundle bundle = getIntent().getExtras();
        if(bundle == null){
            Toast.makeText(this, "Missing word", Toast.LENGTH_LONG).show();
        }else{
            String key;
            String wordName = bundle.getString(Constants.WORD);
            loadSearchWordOnWiki(wordName);
        }
    }

    class CustomWebViewClient extends WebViewClient{
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if(url.startsWith("https:") && url.contains("wikipedia")){
                webView.loadUrl(url);
            }
            return true;
        }
    }

    private void loadSearchWordOnWiki(String dicWord){
        String searchQuery = "https://en.wikipedia.org/wiki/" + dicWord;
        webView.loadUrl(searchQuery);
    }
}

In its layout file, we use a WebView widget to render the Wikipedia page. 

Open the layout file and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WikiActivity">

    <WebView
        android:id="@+id/wiki_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="12dp">

    </WebView>

</androidx.constraintlayout.widget.ConstraintLayout>

Create Favorite Page

Follow the same process we used above to create a new Fragment for user favorite words. 

The page will list all user favorite words with ability to delete any one of them.

Open the Fragment class and add the code below to it.

public class FavoritesFragment extends Fragment {

    private static final String TAG = FavoritesFragment.class.getSimpleName();

    private RecyclerView recyclerView;

    private LinearLayoutManager linearLayoutManager;

    private FavouriteModel fModel;

    public static FavoritesFragment getInstance() {
        FavoritesFragment favoritesFragment = new FavoritesFragment();
        Bundle bundle = new Bundle();
        favoritesFragment.setArguments(bundle);
        return favoritesFragment;
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_favorites, container, false);

        Objects.requireNonNull(getActivity()).setTitle("Favorites");

        fModel = new FavouriteModel(getActivity());

        recyclerView = (RecyclerView)view.findViewById(R.id.my_favorites);
        setUpRecyclerView();
        return view;
    }

    private void setUpRecyclerView(){
        linearLayoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setHasFixedSize(true);
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        ItemAdapter<FavouriteAdapterModel> itemAdapter = new ItemAdapter<>();
        FastAdapter fastAdapter = FastAdapter.with(itemAdapter);
        recyclerView.setAdapter(fastAdapter);

        fastAdapter.withSelectable(true);
        fastAdapter.withEventHook(new ClickEventHook<FavouriteAdapterModel>() {
            @Override
            public void onClick(@NonNull View v, int position, @NonNull FastAdapter<FavouriteAdapterModel> fastAdapters, @NonNull FavouriteAdapterModel item) {

                if(v instanceof AppCompatImageView){
                    Log.d(TAG, "Icon is clicked");
                    // delete icon is click.
                    // Ask user if it is an intended action
                    DeleteDialog deleteDialog = new DeleteDialog(getActivity());
                    deleteDialog.showDeleteDialogMessage(fModel, new FavouriteWord(item.name), itemAdapter);
                }

                if(v instanceof AppCompatTextView){
                    Log.d(TAG, "Text is clicked");
                    //Dictionary word has been click
                    Intent dictionaryIntent = new Intent(getActivity(), DictionaryActivity.class);
                    dictionaryIntent.putExtra(Constants.WORD, item.name);
                    Objects.requireNonNull(getActivity()).startActivity(dictionaryIntent);
                }
            }

            @Nullable
            @Override
            public List<View> onBindMany(RecyclerView.ViewHolder viewHolder) {
                List<View> allViews = new ArrayList<>();
                if (viewHolder instanceof FavouriteAdapterModel.ViewHolder) {
                    AppCompatImageView imgIcon = ((FavouriteAdapterModel.ViewHolder) viewHolder).deleteIcon;
                    AppCompatTextView textContent = ((FavouriteAdapterModel.ViewHolder) viewHolder).word;
                    allViews.add(imgIcon);
                    allViews.add(textContent);
                    return allViews;
                }
                return null;
            }

        });

        List<FavouriteAdapterModel> data = getFavouriteAdapterModels();
        itemAdapter.add(data);

    }

    private List<FavouriteAdapterModel> getFavouriteAdapterModels() {
        List<FavouriteWord> myFavourites = fModel.getAllFavourites();
        List<FavouriteAdapterModel> data = new ArrayList<>();

        for(FavouriteWord word : myFavourites){
            data.add(new FavouriteAdapterModel().withName(word.getWord()));
        }
        return data;
    }
}

Open the fragment_favorites.xml file and paste the code below.

<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
    tools:context=".fragments.FavoritesFragment">


    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/top_note"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:orientation="vertical">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:layout_gravity="center"
            android:padding="18dp"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:text="VIEW YOUR FAVOURITE WORDS "/>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/colorBackground"/>

    </androidx.appcompat.widget.LinearLayoutCompat>


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/top_note">


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/my_favorites"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="6dp">

        </androidx.recyclerview.widget.RecyclerView>

    </FrameLayout>

</RelativeLayout>

How to download the complete source code

You can follow this tutorial and complete the tutorial with the code snippets provided in the tutorial.

The source code is not free to download because we spent a lot of time to create these apps from scratch and your little donation will help us to even create more apps from scratch.

Donate

Summary

We have walked through the process of creating beautify android dictionary application with so many supported features.

Since the tutorial is pretty long, we might have omitted some code.

If you have questions or suggestions, kindly use the comment box below.

I look forward in seeing you in our next build from scratch episode.

Add a Comment