Wednesday, December 13, 2023

Android java: SQLiteOpenHelper, Fragment & RecyclerView in java

 

Android Studio Hedgehog | 2023.1.1

Note: For personal reference using SearchView, Filter (text), SQLiteOpenHelper, RecyclerView and Fragment

Create new Project (No Activity)

Name CA Price List
Package Name com.dedetok.capricelist

Create Activity -> Empty View Activity

Activity Name: Main Activity
Layout Name activity_main
Laucher Activity checked

AndroidManifest.xml

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

    <!-- for >= android 6 api level 23 -->
    <uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.CAPriceList"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

build.gradle.kts(Module :app)

plugins {
    id("com.android.application")
}

android {
    namespace = "com.dedetok.capricelist"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.dedetok.capricelist"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
,,,

Resource -> Values -> strings.xml

<resources>
    <string name="app_name">CA Price List</string>
    <string name="t_cancel">Cancel</string>
    <string name="t_save">Save</string>
    <string name="t_delete">Delete</string>
    <string name="t_product_name">Product Name</string>
    <string name="t_product_price">Product Price</string>
    <string name="t_product_code">Product Code</string>
    <string name="t_product_id">Product ID</string>
    <string name="t_new_product">New Product</string>
</resources>

Menu

my_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id = "@+id/menu_add_pricelist"
        android:title="@string/t_new_product"
        />
</menu>

Layout

layout_price_list.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/pricelist_item"
    android:minHeight="48dp"
    android:layout_margin="5dp"
    >

</TextView>

layout_fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <SearchView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/sv_text"
        />
    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
    />
</LinearLayout>

layout_fragment_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:id="@+id/product_id"
        android:text="@string/t_product_id"
        android:layout_margin="15dp"
        />
    <EditText
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:id="@+id/product_name"
        android:minHeight="48dp"
        android:hint="@string/t_product_name"
        android:autofillHints="@string/t_product_name"
        android:inputType="text"
        android:layout_margin="15dp"
        />

    <EditText
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:id="@+id/product_price"
        android:minHeight="48dp"
        android:autofillHints="@string/t_product_price"
        android:hint="@string/t_product_price"
        android:inputType="text"
        android:layout_margin="15dp"
        />
    <EditText
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:id="@+id/product_code"
        android:minHeight="48dp"
        android:autofillHints="@string/t_product_code"
        android:hint="@string/t_product_code"
        android:inputType="text"
        android:layout_margin="15dp"
        />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_margin="15dp"
        android:gravity="center_horizontal"
        >
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/t_cancel"
            android:id="@+id/b_cancel_fragment_detail"
            android:contentDescription="@string/t_cancel"
            android:layout_margin="5dp"
            />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/t_save"
            android:id="@+id/b_save_fragment_detail"
            android:contentDescription="@string/t_save"
            android:layout_margin="5dp"
            />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/t_delete"
            android:id="@+id/b_delete_fragment_detail"
            android:contentDescription="@string/t_delete"
            android:layout_margin="5dp"
            />
    </LinearLayout>
</LinearLayout>

activity_main.xml

<?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=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/my_fragmentcontainerview"
        android:scrollbars="vertical"
        app:layoutManager="LinearLayoutManager"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

Create java package: New -> Packages : com.dedetok.capricelist.DBHelper

Java in com.dedetok.capricelist.DBHelper packages

PriceList.java

package com.dedetok.capricelist.DBHelper;


/*
 * Table for price_list
 */
public class PriceList {
    public static final String TABLENAME = "price_list";

    /*
     * column name and mapping
     */
    // Primary Key
    public static final String IDPRODUCT = "id_product";
    public long idProduct;

    public static final String NAMEPRODUCT = "name_product";
    public String nameProduct;

    public static final String PRICEPRODUCT = "price_product";
    public String priceProduct;

    public static final String CODEPRODUCT = "code_product";
    public String codeProduct;

    //debug
    public String getText() {
        return idProduct+" "+nameProduct+" "+priceProduct+" "+codeProduct;
    }
}

MySQLiteHelper.java

package com.dedetok.capricelist.DBHelper;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;

public class MySQLiteHelper extends SQLiteOpenHelper {

    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "CAPriceList.db";
    private static final String SQLCREATEDB = "create TABLE "+PriceList.TABLENAME +"(" +
            PriceList.IDPRODUCT+ " INTEGER PRIMARY KEY AUTOINCREMENT," +
            PriceList.NAMEPRODUCT+ " TEXT NOT NULL," +
            PriceList.PRICEPRODUCT+ " TEXT NOT NULL," +
            PriceList.CODEPRODUCT+ " Text);";

    public MySQLiteHelper(@Nullable Context myAppContext, @Nullable String myDBName, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(myAppContext, myDBName, factory, version);
    }

    /*
     * Mandatory to create   table
     */
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQLCREATEDB);

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // TODO

    }
}

BoyerMooreTextSearch.java -> fast match string better then indexOf() or contain()

package com.dedetok.capricelist.DBHelper;

public class BoyerMooreTextSearch {
    /**
     * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm#Java_implementation
     *
     * Returns the index within this string of the first occurrence of the
     * specified substring. If it is not a substring, return -1.
     *
     * There is no Galil because it only generates one match.
     *
     * @param haystack The string to be scanned
     * @param needle The target string to search
     * @return The start index of the substring
     */
    public static int indexOf(char[] haystack, char[] needle) {
        if (needle.length == 0) {
            return 0;
        }
        int charTable[] = makeCharTable(needle);
        int offsetTable[] = makeOffsetTable(needle);
        for (int i = needle.length - 1, j; i < haystack.length;) {
            for (j = needle.length - 1; needle[j] == haystack[i]; --i, --j) {
                if (j == 0) {
                    return i;
                }
            }
            // i += needle.length - j; // For naive method
            i += Math.max(offsetTable[needle.length - 1 - j], charTable[haystack[i]]);
        }
        return -1;
    }

    /**
     * Makes the jump table based on the mismatched character information.
     */
    private static int[] makeCharTable(char[] needle) {
        final int ALPHABET_SIZE = Character.MAX_VALUE + 1; // 65536
        int[] table = new int[ALPHABET_SIZE];
        for (int i = 0; i < table.length; ++i) {
            table[i] = needle.length;
        }
        for (int i = 0; i < needle.length; ++i) {
            table[needle[i]] = needle.length - 1 - i;
        }
        return table;
    }

    /**
     * Makes the jump table based on the scan offset which mismatch occurs.
     * (bad-character rule).
     */
    private static int[] makeOffsetTable(char[] needle) {
        int[] table = new int[needle.length];
        int lastPrefixPosition = needle.length;
        for (int i = needle.length; i > 0; --i) {
            if (isPrefix(needle, i)) {
                lastPrefixPosition = i;
            }
            table[needle.length - i] = lastPrefixPosition - i + needle.length;
        }
        for (int i = 0; i < needle.length - 1; ++i) {
            int slen = suffixLength(needle, i);
            table[slen] = needle.length - 1 - i + slen;
        }
        return table;
    }

    /**
     * Is needle[p:end] a prefix of needle?
     */
    private static boolean isPrefix(char[] needle, int p) {
        for (int i = p, j = 0; i < needle.length; ++i, ++j) {
            if (needle[i] != needle[j]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns the maximum length of the substring ends at p and is a suffix.
     * (good-suffix rule)
     */
    private static int suffixLength(char[] needle, int p) {
        int len = 0;
        for (int i = p, j = needle.length - 1;
             i >= 0 && needle[i] == needle[j]; --i, --j) {
            len += 1;
        }
        return len;
    }

}

Java in com.dedetok.capricelist packages

DBCARepository.java

package com.dedetok.capricelist;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.dedetok.capricelist.DBHelper.MySQLiteHelper;
import com.dedetok.capricelist.DBHelper.PriceList;
import java.util.ArrayList;

// https://www.geeksforgeeks.org/singleton-class-in-android/
// https://www.androidcode.ninja/android-sqlite-transaction-tutorial/


public class DBCARepository {

    private static MySQLiteHelper mySQLiteHelper = null;

    // private static instance variable to hold the singleton instance
    private static volatile DBCARepository myDBCARepository = null;

    // private constructor to prevent instantiation of the class
    private DBCARepository(Context appContext) {
        if (mySQLiteHelper == null) {
            mySQLiteHelper = new MySQLiteHelper(appContext,
                MySQLiteHelper.DATABASE_NAME, null,
                MySQLiteHelper.DATABASE_VERSION);
        }
    }

    // public static method to retrieve the singleton instance
    public static DBCARepository getInstance() {
        return myDBCARepository;
    }

    public static void prepareDB(Context myAppContext) {
        // Check if the instance is already created
        if(myDBCARepository == null) {
            // synchronize the block to ensure only one thread can execute at a time
            synchronized (DBCARepository.class) {
                // check again if the instance is already created
                if (myDBCARepository == null) {
                    // create the singleton instance
                    myDBCARepository = new DBCARepository(myAppContext);
                }
            }
        }
    }

    public ArrayList<PriceList> getPriceLists() {
        // https://developer.android.com/training/data-storage/sqlite
        SQLiteDatabase myDB = mySQLiteHelper.getReadableDatabase();

        String[] projection =   {
                PriceList.IDPRODUCT, //0
                PriceList.NAMEPRODUCT, //1
                PriceList.PRICEPRODUCT, //2
                PriceList.CODEPRODUCT //3
        };

        // Filter results WHERE "title" = 'My Title'
        // String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
        String selection = null; // Not Used set null
        // String[] selectionArgs = { "My Title" };
        String[] selectionArgs = null; // Not used set null

        // How you want the results sorted in the resulting Cursor
        //String sortOrder =
        //        FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
        String sortOrder = null; // Not used set null

        Cursor cursor =  myDB.query(
                PriceList.TABLENAME,
                projection,             // The array of columns to return (pass null to get all)
                selection,              // The columns for the WHERE clause
                selectionArgs,          // The values for the WHERE clause
                null,                   // don't group the rows
                null,                   // don't filter by row groups
                sortOrder               // The sort order
        );

        ArrayList itemList = new ArrayList<>();
        while(cursor.moveToNext()) {
            PriceList mPriceList = new PriceList();
            mPriceList.idProduct = cursor.getLong(0);
            //Log.e("dedetok", Long.toString(cursor.getLong(0))); // debug
            mPriceList.nameProduct = cursor.getString(1);
            //Log.e("dedetok", cursor.getString(1)); // debug
            mPriceList.priceProduct = cursor.getString(2);
            mPriceList.codeProduct = cursor.getString(3);
            itemList.add(mPriceList);
            //Log.e("dedetok", "getPriceLists()"+ mPriceList.getText()); //debug
        }
        cursor.close();
        myDB.close();

        return itemList;
    }

    /*
     * insert a new Price List, ID is auto number
     */
    public long insertPriceList(PriceList newPriceList) {
        //Log.e("dedetok", "DBACARepository insertPriceList get DB"); // debug
        SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
        ContentValues myContent = new ContentValues();
        myContent.put(PriceList.NAMEPRODUCT, newPriceList.nameProduct);
        myContent.put(PriceList.PRICEPRODUCT, newPriceList.priceProduct);
        myContent.put(PriceList.CODEPRODUCT, newPriceList.codeProduct);
        //Log.e("dedetok", "DBACARepository insertPriceList insert data"); // debug
        long retValue = myDB.insert(PriceList.TABLENAME, null, myContent);
        //Log.e("dedetok", "DBACARepository insertPriceList insert data result "+retValue); // debug
        //Log.e("dedetok", "DBACARepository insertPriceList close db"); // debug
        myDB.close();
        return retValue;
    }

    // Save / update
    /*
     * To update price list after editing
     */
    public int updatePriceList(PriceList myPriceList) {
        SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
        ContentValues myContent = new ContentValues();
        myContent.put(PriceList.IDPRODUCT, myPriceList.idProduct);
        myContent.put(PriceList.NAMEPRODUCT, myPriceList.nameProduct);
        myContent.put(PriceList.PRICEPRODUCT, myPriceList.priceProduct);
        myContent.put(PriceList.CODEPRODUCT, myPriceList.codeProduct);
        // Filter results WHERE "title" = 'My Title'
        // String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
        String selection = PriceList.IDPRODUCT + " = ?";
        // String[] selectionArgs = { "My Title" };
        String[] selectionArgs = {Long.toString(myPriceList.idProduct)}; // Not used set null
        int retVal = myDB.update(PriceList.TABLENAME, myContent, selection, selectionArgs);
        return retVal;
    }

    /*
     * delete
     */
    public int deletePriceList(PriceList myPriceList) {
        SQLiteDatabase myDB = mySQLiteHelper.getWritableDatabase();
        // Filter results WHERE "title" = 'My Title'
        // String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
        String selection = PriceList.IDPRODUCT + " = ?";
        // String[] selectionArgs = { "My Title" };
        String[] selectionArgs = {Long.toString(myPriceList.idProduct)};
        int retVal = myDB.delete(PriceList.TABLENAME, selection, selectionArgs);
        return retVal;
    }
}

PriceListsAdapter.java

package com.dedetok.capricelist;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;

import com.dedetok.capricelist.DBHelper.BoyerMooreTextSearch;
import com.dedetok.capricelist.DBHelper.PriceList;

import java.util.ArrayList;

// https://developer.android.com/develop/ui/views/layout/recyclerview

public class PriceListsAdapter extends RecyclerView.Adapter implements Filterable {

    // variable
    private ArrayList<PriceList> myPriceListsFiltered;
    private ArrayList<PriceList> myPriceListsOriginal;

    /*
     * construtor to initilize array list
     */
    public PriceListsAdapter() {
        myPriceListsOriginal = DBCARepository.getInstance().getPriceLists();
        myPriceListsFiltered = myPriceListsOriginal;
    }

    /*
     * mandatory extending RecyclerView.Adapter
     * constructor
     */
    @NonNull
    @Override
    public PriceListsAdapter.PriceListHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Create a new view, which defines the UI of the list item
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.layout_price_list, parent, false);
        return new PriceListsAdapter.PriceListHolder (view);
    }

    /*
     * mandatory extending RecyclerView.Adapter
     */
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        PriceList myPriceList = myPriceListsFiltered.get(position);
        String tmpString = Long.toString(myPriceList.idProduct)+" "+
                myPriceList.nameProduct+" "+
                myPriceList.priceProduct+" "+
                myPriceList.codeProduct;
        ((PriceListHolder) holder).textView.setText(tmpString);
        // https://www.geeksforgeeks.org/how-to-apply-onclicklistener-to-recyclerview-items-in-android/
        holder.itemView.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        PriceList mPriceList = myPriceListsFiltered.get(holder.getAdapterPosition());
                        FragmentDetail myFragmentDetail = new FragmentDetail(mPriceList);
                        ((FragmentActivity) view.getContext()).getSupportFragmentManager().
                                beginTransaction().
                                replace(R.id.my_fragmentcontainerview, myFragmentDetail).
                                addToBackStack("List").
                                commit();


                        //Log.e("dedetok", "position "+ Integer.toString(holder.getAdapterPosition())); // debug
                    }
                }
        );

    }

    /*
     * mandatory extending RecyclerView.Adapter
     * return number of item on ArrayList<PriceList> myPriceLists
     */
    @Override
    public int getItemCount() {
        return myPriceListsFiltered.size();
    }

    /*
     * implements android.widget.Filterable;
     * https://codingwithmitch.com/blog/filtering-recyclerview-searchview/
     */
    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                String tmpPattern = charSequence.toString().toUpperCase();

                if (tmpPattern.isEmpty()) {
                    myPriceListsFiltered = myPriceListsOriginal;
                } else {
                    myPriceListsFiltered = new ArrayList<PriceList>();
                    for (PriceList myPriceList : myPriceListsOriginal) {
                        String tmpText = myPriceList.nameProduct.toUpperCase();
                        if (BoyerMooreTextSearch.indexOf(tmpText.toCharArray(), tmpPattern.toCharArray())> -1) {
                            myPriceListsFiltered.add(myPriceList);
                        }
                    }
                }
                FilterResults results = new FilterResults();
                results.values = myPriceListsFiltered;
                return results;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults results) {
                myPriceListsFiltered = (ArrayList<PriceList>) results.values;
                notifyDataSetChanged();
            }
        };
    }

    private class PriceListHolder extends RecyclerView.ViewHolder {

        public TextView textView;

        /*
         * mandatory extends RecyclerView.ViewHolder
         */
        public PriceListHolder(@NonNull View view) {
            super(view);
            textView = view.findViewById(R.id.pricelist_item);
        }


    }
}

FragmentDetail.java

package com.dedetok.capricelist;

import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;

import com.dedetok.capricelist.DBHelper.PriceList;

public class FragmentDetail extends Fragment {

    PriceList myPriceList=null;

    /*
     * constructor to inflate fragment
     */
    public FragmentDetail() {
        super(R.layout.layout_fragment_detail);
    }

    public FragmentDetail(PriceList myPriceList) {
        super(R.layout.layout_fragment_detail);
        this.myPriceList = myPriceList;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // EditText
        EditText etProductName = view.findViewById(R.id.product_name);
        EditText etProductPrice = view.findViewById(R.id.product_price);
        EditText etProductCode = view.findViewById(R.id.product_code);
        if (myPriceList!=null) {
            // if edit or delete data
            TextView tvProductID = view.findViewById(R.id.product_id);
            tvProductID.setText(myPriceList.codeProduct);
            etProductName.setText(myPriceList.nameProduct);
            etProductPrice.setText(myPriceList.priceProduct);
            etProductCode.setText(myPriceList.codeProduct);
        }

        // button cancel
        Button bCancelFragmentDetail = view.findViewById(R.id.b_cancel_fragment_detail);
        bCancelFragmentDetail.setOnClickListener(cancelFragmentDetail -> getParentFragmentManager().popBackStack());

        // button save
        Button bSaveFragmentDetail = view.findViewById(R.id.b_save_fragment_detail);
        bSaveFragmentDetail.setOnClickListener(saveFragmentDetail -> {
            if (myPriceList ==null) {
                // new data
                //Log.e("dedetok", "FragmentDetail insert data"); //debug
                PriceList newPriceList = new PriceList();
                newPriceList.nameProduct = etProductName.getText().toString();
                newPriceList.priceProduct = etProductPrice.getText().toString();
                newPriceList.codeProduct = etProductCode.getText().toString();
                DBCARepository.getInstance().insertPriceList(newPriceList);
                //Log.e("dedetok", "FragmentDetail insert data end"); // debug
                getParentFragmentManager().popBackStack();
            } else {
                // save existing data
                myPriceList.nameProduct = etProductName.getText().toString();
                myPriceList.priceProduct = etProductPrice.getText().toString();
                myPriceList.codeProduct = etProductCode.getText().toString();
                DBCARepository.getInstance().updatePriceList(myPriceList);
                getParentFragmentManager().popBackStack();
            }
        });

        // https://stackoverflow.com/questions/38411879/alert-confirmation-dialog-android
        // https://stackoverflow.com/questions/10207206/how-to-display-alertdialog-in-a-fragment
        Button bDeleteFragmentDetail = view.findViewById(R.id.b_delete_fragment_detail);
        if (myPriceList == null) {
            // new data, we don't have to delete
            bDeleteFragmentDetail.setVisibility(View.INVISIBLE);
        } else {
            bDeleteFragmentDetail.setVisibility(View.VISIBLE);
            bDeleteFragmentDetail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
                    alert.setTitle("Delete");
                    alert.setMessage("Are you sure you want to delete?");
                    alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            DBCARepository.getInstance().deletePriceList(myPriceList);
                            Log.e("dedetok", "deleted"); // debug
                            dialogInterface.dismiss();
                        }
                    });
                    alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            dialogInterface.dismiss();
                        }
                    });
                    alert.show();
                }
            });
        }
    }
}

FragmentList.java

package com.dedetok.capricelist;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SearchView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class FragmentList extends Fragment {


    /*
     * constructor to inflate fragment
     */
    public FragmentList() {
        super(R.layout.layout_fragment_list);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //recyclerview
        RecyclerView myRecyclerView = view.findViewById(R.id.my_recycler_view);
        LinearLayoutManager myLinearLayout = new LinearLayoutManager(getActivity().getApplicationContext());
        myLinearLayout.setOrientation(LinearLayoutManager.VERTICAL);
        myRecyclerView.setLayoutManager(myLinearLayout);
        PriceListsAdapter myPriceListAdapter = new PriceListsAdapter();
        myRecyclerView.setAdapter(myPriceListAdapter);

        // https://codingwithmitch.com/blog/filtering-recyclerview-searchview/
        // SearchView
        SearchView mySearchView = view.findViewById(R.id.sv_text);
        // add listener for searchview
        mySearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                myPriceListAdapter.getFilter().filter(s);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                myPriceListAdapter.getFilter().filter(s);
                return false;            }
        });

    }
}

MainActivity.java

package com.dedetok.capricelist;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;


public class MainActivity extends AppCompatActivity {

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

        // initialize database
        Log.e("dedetok", "MainActivity OnCreate Initilize database"); // debug
        DBCARepository.prepareDB(getApplicationContext());
        Log.e("dedetok", "MainActivity OnCreate Initilize database end"); // debug

        getSupportFragmentManager().beginTransaction().
                add(R.id.my_fragmentcontainerview, FragmentList.class, null).
                commit();

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.my_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId()==R.id.menu_add_pricelist) {
            // open fragment Detail for new PriceList
            getSupportFragmentManager().beginTransaction().
                    replace(R.id.my_fragmentcontainerview, FragmentDetail.class,null).
                    addToBackStack("List").
                    commit();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

NOTE: Some code may reference to other source code in comment (some has modified to make it run), do not remove urls if you wish to copy paste code and use the code.


No comments:

Post a Comment