27 Şubat 2021 Cumartesi

Android Kütüphane Sistemi Mobil Uygulaması - 7 (Kitap Listesi)

    Merhabalar. Android Kütüphane Sistemi Mobil Uygulaması yazı dizisinin yedinci yazısı ile yeniden sizlerleyim. Bu yazıda kitap listesi ekranından bahsedeceğim.Tekrar belirtmekte fayda olacak, uygulamanın kodlarına buradan erişebilirsiniz.

    Burada liste çekilirken verinin fazla olması göz önünde bulundurularak scroll yaptıkça verinin gelmesi yani ScrollListener kullanılmıştır. Bu sayede servis tarafı yorulmayıp daha performanslı bir yapı ortaya çıkmıştır. Kitap listesi ekranı ;

    -Kitap resmi

    -Kitap adı

    -Kitap açıklamasının belli bir kısmı

ögelerinden oluşmaktadır. Ekran görüntüsü aşağıda ki gibidir.


Dilerseniz artık ekranın layout ve classlarına göz atabiliriz.

fragment_kitap_islem.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

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

</androidx.coordinatorlayout.widget.CoordinatorLayout>


class KitapIslemFragment():Fragment() {

private lateinit var kitapIslemView:View;
private lateinit var kitapListeRw:RecyclerView;
private lateinit var pd:Dialog;
private lateinit var kitapService:IKitapIslemService;
private var liste:ArrayList<KitapModel> = ArrayList<KitapModel>();
private lateinit var kitapAdapter:KitapListeAdapter;

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
kitapIslemView = inflater.inflate(R.layout.fragment_kitap_islem,container,false);
initComponents();
initKitapListe();
val scrollListener:EndlessRecyclerViewScrollListener;
scrollListener = object:EndlessRecyclerViewScrollListener(4,kitapListeRw.layoutManager as LinearLayoutManager){
override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView) {
pd.show();
val jsonObj: JSONObject = JSONObject();
jsonObj.put("minKayitNum",((page*4)));
jsonObj.put("maxKayitNum",4);
kitapService.getKitapListe(jsonObj.toString()).enqueue(object:
Callback<ArrayList<KitapModel>> {
override fun onFailure(call: Call<ArrayList<KitapModel>>?, t: Throwable) {
Log.d("Exception",""+t.localizedMessage);
SimpleToast.error(context, resources.getString(R.string.kitapListeHata), "{fa-times-circle}");
pd.dismiss();
}

override fun onResponse(call: Call<ArrayList<KitapModel>>?, response: Response<ArrayList<KitapModel>>) {
if(response.body() != null){
val yeniListe = response.body() as ArrayList<KitapModel>;
liste.addAll(yeniListe);
kitapAdapter.notifyItemInserted(liste.size);
val handler: Handler = Handler(Looper.getMainLooper());
handler.postDelayed(object:Runnable{
override fun run() {
kitapAdapter.notifyDataSetChanged();
}
},1000);
}
pd.dismiss();
}
});


}
}

kitapListeRw.addOnScrollListener(scrollListener);

return kitapIslemView;
}



private fun initComponents(){
kitapListeRw = kitapIslemView.findViewById(R.id.kitapListeRw) as RecyclerView;
kitapService = WebApiUtil.getKitapService(context!!);

pd = Dialog(activity!!);
val pdView: View = layoutInflater.inflate(R.layout.custom_progress_dialog,null);
pd.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
pd.setTitle(null);
pd.setContentView(pdView);
pd.setCancelable(false);

kitapListeRw.setHasFixedSize(true);
//kitapListeRw.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
kitapListeRw.layoutManager = LinearLayoutManager(context);
kitapListeRw.addItemDecoration(LinearSpacingDecoration(itemSpacing = 20, edgeSpacing = 30))
activity!!.kitapEkleBtn.visibility = View.VISIBLE;
activity!!.kitapEkleBtn.setOnClickListener {
ProjectUtil.activityYonlendir(activity!!, KitapEklemeActivity());
}
}

private fun initKitapListe(){
pd.show();
val jsonObj: JSONObject = JSONObject();
jsonObj.put("minKayitNum",0);
jsonObj.put("maxKayitNum",4);
kitapService.getKitapListe(jsonObj.toString()).enqueue(object:
Callback<ArrayList<KitapModel>> {
override fun onFailure(call: Call<ArrayList<KitapModel>>?, t: Throwable) {
Log.d("Exception",""+t.localizedMessage);
SimpleToast.error(context, resources.getString(R.string.kitapListeHata), "{fa-times-circle}");
pd.dismiss();
}

override fun onResponse(call: Call<ArrayList<KitapModel>>?, response: Response<ArrayList<KitapModel>>) {
liste = response.body() as ArrayList<KitapModel>;
kitapAdapter = KitapListeAdapter(context!!,liste);
kitapListeRw.adapter = kitapAdapter;
pd.dismiss();
}
});
}
}

Kitaplar çekildikten sonra adapter recyclerview'a setlenmektedir. Adapter ve onun layout u aşağıda ki gibidir.

card_kitap.xml

<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:id="@+id/cardLayoutId"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:background="@drawable/card_kitap_border"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<RelativeLayout
android:id="@+id/imageLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/kitapCardImageId"
android:layout_width="110dp"
android:layout_height="130dp"
app:srcCompat="@drawable/edit_text_border" />
</RelativeLayout>

<RelativeLayout
android:id="@+id/genelBilgilerRootId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageLayout">

<RelativeLayout
android:id="@+id/genelBilgiler"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/kitapCardAdTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="TextView"
android:textColor="@color/siyah"
android:textSize="16sp"
android:textStyle="bold" />

<TextView
android:id="@+id/kitapTurTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/kitapCardAdTextId"
android:layout_marginTop="5dp"
android:gravity="left"
android:text="TextView"
android:textColor="#4E4E4E"
android:textSize="14sp"/>
<TextView
android:id="@+id/kitapAciklamaTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/kitapTurTextId"
android:layout_marginTop="5dp"
android:gravity="left"
android:text="TextView"
android:textColor="#515151"
android:fontFamily="@font/alegreya"
android:textSize="12sp"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>

KitapListeAdapter.kt

class KitapListeAdapter(private val mContext: Context, private val kitapListe:ArrayList<KitapModel>):
RecyclerView.Adapter<KitapHolder>(){

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KitapHolder {
val kitapTurCardView: View = LayoutInflater.from(mContext).inflate(R.layout.card_kitap,parent,false);
return KitapHolder(kitapTurCardView);
}

override fun getItemCount(): Int {
return kitapListe.size;
}

override fun onBindViewHolder(holder: KitapHolder, position: Int) {
val kitap:KitapModel = kitapListe.get(position);

Glide.with(mContext).load(kitap.kitapResimPath).into(holder.kitapImage);
if(kitap.kitapAd!!.length>55){
holder.kitapAdText.text = kitap.kitapAd!!.substring(0,54)+"...";
}else{
holder.kitapAdText.text = kitap.kitapAd;
}
holder.kitapTurText.text = "Kitap Türü : "+kitap.kitapTur?.aciklama;

if(kitap.kitapAciklama!!.length>110){
holder.kitapAciklamaText.text = kitap.kitapAciklama?.substring(0,110)+"...";
}else{
holder.kitapAciklamaText.text = kitap.kitapAciklama;
}


holder.cardLayoutId.setOnClickListener {
putKitapDetayIntoSharedPreferences(mContext,kitap);
ProjectUtil.activityYonlendir(mContext,KitapDetayActivity());
}
}

fun addAllItems(yeniListe:ArrayList<KitapModel>):Unit{
this.kitapListe.clear();
this.kitapListe.addAll(yeniListe);
}

private fun putKitapDetayIntoSharedPreferences(mContext: Context, kitap: KitapModel) {
kitap.id?.let {
ProjectUtil.putIntDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapId",
it
)
};
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAd",kitap.kitapAd.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"yazarAd",kitap.yazarAd.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAciklama",kitap.kitapAciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapTur",kitap.kitapTur!!.aciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapYayinevi",kitap.yayinEvi!!.aciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapResim",kitap.kitapResimPath.toString());
kitap.alinmatarihi?.let { ProjectUtil.formatDate(it,"dd.MM.yyyy") }?.let {
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAlinmaTarih",
it
)
};
ProjectUtil.putDoubleDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapPuan",kitap.kitapPuan);
}

}

Burada kitap detay ekranına gidilirken putKitapDetayIntoSharedPreferences metodu ile kitaba ait bilgiler shared preferences'a yazılmaktadır.

Kitap resmi Glide kütüphanesi ile çekilirken kitap açıklaması ise aşağıda ki kod kısmı ile ekranda fazla yer kaplamasın diye sınırlandırılmaktadır.

        if(kitap.kitapAd!!.length>55){
holder.kitapAdText.text = kitap.kitapAd!!.substring(0,54)+"...";
}else{
holder.kitapAdText.text = kitap.kitapAd;
}

Burada dikkat edilmesi gereken bir diğer husus ise scroll listener yapmayı sağlayan EndlessRecyclerViewScrollListener classıdır. Bu class aşağıda ki gibidir.

EndlessRecyclerViewScrollListener.kt

abstract class EndlessRecyclerViewScrollListener(private var visibleThreshold: Int = 5): RecyclerView.OnScrollListener() {
private var currentPage = 0
private var previousTotalItemCount = 0
private var loading = true
private val startingPageIndex = 0

private var mLayoutManager: RecyclerView.LayoutManager? = null

constructor(visibleThreshold: Int, layoutManager: LinearLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
}

constructor(visibleThreshold: Int, layoutManager: GridLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
this.visibleThreshold = visibleThreshold * layoutManager.spanCount
}

constructor(visibleThreshold: Int, layoutManager: StaggeredGridLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
this.visibleThreshold = visibleThreshold * layoutManager.spanCount
}

fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int {
var maxSize = 0
for (i in lastVisibleItemPositions.indices) {
if (i == 0) {
maxSize = lastVisibleItemPositions[i]
} else if (lastVisibleItemPositions[i] > maxSize) {
maxSize = lastVisibleItemPositions[i]
}
}
return maxSize
}

override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(view, dx, dy);
}

override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState);

var lastVisibleItemPosition = 0
val totalItemCount = mLayoutManager?.itemCount ?: 0

if (mLayoutManager is StaggeredGridLayoutManager) {
val lastVisibleItemPositions = (mLayoutManager as StaggeredGridLayoutManager).findLastVisibleItemPositions(null)
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions)
} else if (mLayoutManager is GridLayoutManager) {
lastVisibleItemPosition = (mLayoutManager as GridLayoutManager).findLastVisibleItemPosition()
} else if (mLayoutManager is LinearLayoutManager) {
lastVisibleItemPosition = (mLayoutManager as LinearLayoutManager).findLastVisibleItemPosition()
}

if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex
this.previousTotalItemCount = totalItemCount

}

if (totalItemCount > previousTotalItemCount) {
previousTotalItemCount = totalItemCount
}

if (lastVisibleItemPosition + visibleThreshold > totalItemCount) {
currentPage++
onLoadMore(currentPage, totalItemCount, recyclerView)
}

}

fun resetState() {
this.currentPage = this.startingPageIndex
this.previousTotalItemCount = 0
this.loading = true
}

abstract fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView)

}

Soru,istek ve önerilerinizi mesutemrecelenk@gmail.com adresine yazabilirsiniz. Bir sonraki yazıda görüşmek üzere hoşça kalın...


   

20 Şubat 2021 Cumartesi

Android Kütüphane Sistemi Mobil Uygulaması - 6 (Parametreler)

Merhabalar. Android Kütüphane Sistemi Mobil Uygulaması yazı dizisinin altıncı yazısı ile yeniden sizlerleyim. Bu yazıda sistemde ki parametrik değerlerin (kitap türü ve yayınevi) listelenişi ve kaydedilişinden bahsedeceğim.Tekrar belirtmekte fayda olacak, uygulamanın kodlarına buradan erişebilirsiniz.

Öncelikle parametre activity'sine sol taraftan parametre seçilerek gidilebiliyor. Bu kısımda  temel de BottomNavigation'u extend eden custom bir component kullandım. Parametre ekranının görüntüsü aşağıdaki gibidir.



Dilerseniz bu activity'nin layout dosyasına bakalım ve daha sonra da burada kullandığım custom component bahsine geçelim.

activity_parametre.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/parametreRootLayoutId"
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="match_parent">

<FrameLayout
android:id="@+id/parametreFragmentTutucu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="90dp"
app:layout_constraintBottom_toTopOf="@+id/parametreBottomNavigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">

</FrameLayout>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/parametreEkleFloatingButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
app:layout_constraintEnd_toEndOf="parent"
android:backgroundTint="@color/colorAccent"
android:layout_marginTop="1dp"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/parametreFragmentTutucu"
app:srcCompat="@drawable/ic_add_24dp" />

<com.mesutemre.kutuphanesistemi.customcomponents.CurvedBottomNavigationView
android:id="@+id/parametreBottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">

</com.mesutemre.kutuphanesistemi.customcomponents.CurvedBottomNavigationView>

</androidx.constraintlayout.widget.ConstraintLayout>

Burada FrameLayout listeleri tutmakla görevli olup, FloatingActionButton ise parametre kayıt popup ımızı açmaktadır. Listeler arası geçiş ve NavigationBottom ise CurvedBottomNavigationView componenti ile sağlanmaktadır. Bu componentin kodları aşağıda ki gibidir.

CurvedBottomNavigationView.kt

class CurvedBottomNavigationView(context: Context, attrs: AttributeSet) :BottomNavigationView(context, attrs) {

private lateinit var mPath: Path;
private lateinit var mPaint: Paint;

private val CURVE_CIRCLE_RADIUS = 110 / 2;

private var mFirstCurveStartPoint: Point = Point();
private var mFirstCurveEndPoint: Point = Point();
private var mFirstCurveControlPoint1: Point = Point();
private var mFirstCurveControlPoint2: Point = Point();

private var mSecondCurveStartPoint: Point = Point();
private var mSecondCurveEndPoint: Point = Point();
private var mSecondCurveControlPoint1: Point = Point();
private var mSecondCurveControlPoint2: Point = Point();

private var mNavigationBarWidth: Int = 0;
private var mNavigationBarHeight: Int = 0;

init {
this.init();
}

private fun init(): Unit {
mPath = Path();
mPaint = Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
val colors = IntArray(3);
colors[0] = ContextCompat.getColor(
context,
R.color.bottom_start_color
);
colors[1] = ContextCompat.getColor(
context,
R.color.bottom_center_color
);
colors[2] = ContextCompat.getColor(
context,
R.color.bottom_end_color
);

val positions = FloatArray(3); //floatArrayOf(0f, 0.3f, 0.6f);
positions[0] = 0f;
positions[1] = 0.2f;
positions[2] = 0.4f;
mPaint.setShader(
LinearGradient(
0f, 0f, measuredWidth.toFloat(), 0f,
colors,
positions,
Shader.TileMode.CLAMP
)
);

mPaint.setShader(
LinearGradient(
0f, 0f, 0f, 250f,
colors, positions,
Shader.TileMode.MIRROR
)
);
setBackgroundColor(Color.TRANSPARENT);
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh);

mNavigationBarWidth = getWidth();
mNavigationBarHeight = getHeight();

mFirstCurveStartPoint.set(
(mNavigationBarWidth / 2) - (CURVE_CIRCLE_RADIUS * 2) - (CURVE_CIRCLE_RADIUS / 3),
0
);
mFirstCurveEndPoint.set(
mNavigationBarWidth / 2,
CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4)
);
mSecondCurveStartPoint = mFirstCurveEndPoint;
mSecondCurveEndPoint.set(
(mNavigationBarWidth / 2) + (CURVE_CIRCLE_RADIUS * 2) + (CURVE_CIRCLE_RADIUS / 3),
0
);

mFirstCurveControlPoint1.set(
mFirstCurveStartPoint.x + CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4),
mFirstCurveStartPoint.y
);
// the coordinates (x,y) of the 2nd control point on a cubic curve
mFirstCurveControlPoint2.set(
mFirstCurveEndPoint.x - (CURVE_CIRCLE_RADIUS * 2) + CURVE_CIRCLE_RADIUS,
mFirstCurveEndPoint.y
);

mSecondCurveControlPoint1.set(
mSecondCurveStartPoint.x + (CURVE_CIRCLE_RADIUS * 2) - CURVE_CIRCLE_RADIUS,
mSecondCurveStartPoint.y
);
mSecondCurveControlPoint2.set(
mSecondCurveEndPoint.x - (CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4)),
mSecondCurveEndPoint.y
);

mPath.reset();
mPath.moveTo(0F, 0F);
mPath.lineTo(mFirstCurveStartPoint.x.toFloat(), mFirstCurveStartPoint.y.toFloat());

mPath.cubicTo(
mFirstCurveControlPoint1.x.toFloat(), mFirstCurveControlPoint1.y.toFloat(),
mFirstCurveControlPoint2.x.toFloat(), mFirstCurveControlPoint2.y.toFloat(),
mFirstCurveEndPoint.x.toFloat(), mFirstCurveEndPoint.y.toFloat()
);
mPath.cubicTo(
mSecondCurveControlPoint1.x.toFloat(), mSecondCurveControlPoint1.y.toFloat(),
mSecondCurveControlPoint2.x.toFloat(), mSecondCurveControlPoint2.y.toFloat(),
mSecondCurveEndPoint.x.toFloat(), mSecondCurveEndPoint.y.toFloat()
);

mPath.lineTo(mNavigationBarWidth.toFloat(), 0F);
mPath.lineTo(mNavigationBarWidth.toFloat(), mNavigationBarHeight.toFloat());
mPath.lineTo(0F, mNavigationBarHeight.toFloat());
mPath.close();
}

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
}


@SuppressLint("ResourceAsColor")
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas);
canvas?.drawPath(mPath, mPaint);
}
}

Burada NavigationBottom componenti radius şekil verilerek özelleştirilmiştir. Burada tanımlanan

    val colors = IntArray(3);

değişkeni CustomNavigationBottomView'ın dikeyde alacağı renklerin setlendiği değişkendir. Bu işlem LinearGradient nesnesi ile sağlanmaktadır. CURVE_CIRCLE_RADIUS değişkeninin değeri değiştirilerek radiusluk artırılabilir ya da azaltılabilir. Şimdi de activitye göz atalım.

ParametreActivity.kt

class ParametreActivity : AppCompatActivity() {

private lateinit var tempFragment: Fragment;

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_parametre);

val actionbar = supportActionBar;
actionbar!!.title = resources.getString(R.string.parametreActivityTitle);
actionbar.setDisplayHomeAsUpEnabled(true);

val pd: Dialog = Dialog(this);
val pdView: View = layoutInflater.inflate(R.layout.custom_progress_dialog,null);
pd.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
pd.setTitle(null);
pd.setContentView(pdView);
pd.setCancelable(false);

initNavBottomPreferences(parametreBottomNavigation);

supportFragmentManager.beginTransaction()?.replace(R.id.parametreFragmentTutucu,
YayineviListeFragment()
)?.commit();

parametreBottomNavigation.setOnNavigationItemSelectedListener { menuItem ->
if(menuItem.itemId == R.id.yayinEviItem){
tempFragment = YayineviListeFragment();
}else if(menuItem.itemId == R.id.kitapTurItem){
tempFragment = KitapturListeFragment();
}
supportFragmentManager.beginTransaction().replace(R.id.parametreFragmentTutucu,tempFragment)?.commit();
true;
}

parametreEkleFloatingButton.setOnClickListener {
openParametreEklemeDlg(this,pd);
}
}

override fun onSupportNavigateUp(): Boolean {
onBackPressed();
return true;
}

private fun initNavBottomPreferences(navBottomMenu: CurvedBottomNavigationView){
navBottomMenu.inflateMenu(R.menu.parametre_menu_nav_items);
navBottomMenu.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED;
navBottomMenu.menu.getItem(1).isVisible = false;
}

private fun openParametreEklemeDlg(c: Context, pd: Dialog) {
val view:View = layoutInflater.inflate(R.layout.dialog_parametre_ekleme,null);
val alertDialogBuilder = AlertDialog.Builder(this)
.setTitle(R.string.paramEkleDlgTitle)
.setView(view)
.setPositiveButton(R.string.kaydetLabel, null)
.setNegativeButton(R.string.iptalLabel, null)
.show();
val paramTipCombo: Spinner = view.findViewById(R.id.paramTypeSpinner) as Spinner;
val paramAciklama: EditText = view.findViewById(R.id.paramText) as EditText;
val paramTipArr = c.resources.getStringArray(R.array.parametreTipArr);
val adapter = ArrayAdapter(alertDialogBuilder.context,android.R.layout.simple_list_item_1,paramTipArr);
paramTipCombo.adapter = adapter;

val kaydetButton: Button = alertDialogBuilder.getButton(AlertDialog.BUTTON_POSITIVE);
kaydetButton.setOnClickListener {
val selectedParamTip = paramTipCombo.selectedItem;
val aciklama = paramAciklama.text.toString();

if(selectedParamTip.equals(resources.getString(R.string.paramTipSeciniz))){
SimpleToast.warning(c, resources.getString(R.string.parametreSecinizUyari), "{fa-exclamation-triangle}");
return@setOnClickListener;
}

if(aciklama.isEmpty()){
SimpleToast.warning(c, resources.getString(R.string.aciklamaBosUyari), "{fa-exclamation-triangle}");
return@setOnClickListener;
}

val jsonObj: JSONObject = JSONObject();
jsonObj.put("aciklama",aciklama);
val parametreService: IParametreService = WebApiUtil.getParametreService(c);

pd.show();

if(selectedParamTip.equals(resources.getString(R.string.paramKitapTur))){
kitapTurKaydet(parametreService,pd,jsonObj.toString());
alertDialogBuilder.dismiss();
pd.dismiss();
}else if(selectedParamTip.equals(resources.getString(R.string.paramYayinevi))){
yayinEviKaydet(parametreService,pd,jsonObj.toString());
alertDialogBuilder.dismiss();
}
}

val iptalButton: Button = alertDialogBuilder.getButton(AlertDialog.BUTTON_NEGATIVE);
iptalButton.setOnClickListener {
alertDialogBuilder.dismiss();
}
}

private fun kitapTurKaydet(parametreService: IParametreService,pd:Dialog,jsonStr:String){
parametreService.kitapTurKaydet(jsonStr).enqueue(object:
Callback<ResponseStatusModel> {
override fun onFailure(call: Call<ResponseStatusModel>?, t: Throwable) {
SimpleToast.error(applicationContext, resources.getString(R.string.kitapTurSilmeHata), "{fa-times-circle}");
pd.dismiss();
}

override fun onResponse(call: Call<ResponseStatusModel>?, response: Response<ResponseStatusModel>) {
if(response.body() != null){
val respModel = response.body() as ResponseStatusModel;
SimpleToast.info(applicationContext, respModel.statusMessage, "{fa-check}");
supportFragmentManager.beginTransaction().replace(R.id.parametreFragmentTutucu,KitapturListeFragment())?.commit();
pd.dismiss();
}
}
});
}

private fun yayinEviKaydet(parametreService: IParametreService,pd:Dialog,jsonStr:String){
parametreService.yayinEviKaydet(jsonStr).enqueue(object:
Callback<ResponseStatusModel> {
override fun onFailure(call: Call<ResponseStatusModel>?, t: Throwable) {
SimpleToast.error(applicationContext, resources.getString(R.string.yayinEviSilmeHata), "{fa-times-circle}");
pd.dismiss();
}

override fun onResponse(call: Call<ResponseStatusModel>?, response: Response<ResponseStatusModel>) {
if(response.body() != null){
val respModel = response.body() as ResponseStatusModel;
SimpleToast.info(applicationContext, respModel.statusMessage, "{fa-check}");
pd.dismiss();
supportFragmentManager.beginTransaction().replace(R.id.parametreFragmentTutucu,YayineviListeFragment())?.commit();
}
}
});
}
}

Burada initNavBottomPreferences metodu ile bottom navigation un menüleri de setlenmiştir. 

parametre_menu_nav_items.xml

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

<item
android:id="@+id/yayinEviItem"
android:icon="@drawable/ic_format_list_numbered_24dp"
app:showAsAction="ifRoom"
android:title="@string/yayinEvleriItemLabel"/>

<item
android:id="@+id/sepet"
app:showAsAction="never"
android:title=""/>

<item
android:id="@+id/kitapTurItem"
android:icon="@drawable/ic_format_list_numbered_24dp"
app:showAsAction="ifRoom"
android:title="@string/kitapTurleriItemLabel"/>

</menu>

Menüde ki kitapTurItem ve yayinEviItem itemlerı ile kitap türleri ya da yayın evleri listelerine ulaşılmaktadır.

Bu listeler fragment olup FrameLayout üzerinde gösterilmektedir. Bu fragmentlara (KitapturListeFragment ve YayineviListeFragment) buradan erişebilirsiniz.

FloatingActionButton ile parametre kayıt popup ı açılıyor demiştik. Bu işlem aşağıda ki metodda olmaktadır.

private fun openParametreEklemeDlg(c: Context, pd: Dialog) {
val view:View = layoutInflater.inflate(R.layout.dialog_parametre_ekleme,null);
val alertDialogBuilder = AlertDialog.Builder(this)
.setTitle(R.string.paramEkleDlgTitle)
.setView(view)
.setPositiveButton(R.string.kaydetLabel, null)
.setNegativeButton(R.string.iptalLabel, null)
.show();
val paramTipCombo: Spinner = view.findViewById(R.id.paramTypeSpinner) as Spinner;
val paramAciklama: EditText = view.findViewById(R.id.paramText) as EditText;
val paramTipArr = c.resources.getStringArray(R.array.parametreTipArr);
val adapter = ArrayAdapter(alertDialogBuilder.context,android.R.layout.simple_list_item_1,paramTipArr);
paramTipCombo.adapter = adapter;

val kaydetButton: Button = alertDialogBuilder.getButton(AlertDialog.BUTTON_POSITIVE);
kaydetButton.setOnClickListener {
val selectedParamTip = paramTipCombo.selectedItem;
val aciklama = paramAciklama.text.toString();

if(selectedParamTip.equals(resources.getString(R.string.paramTipSeciniz))){
SimpleToast.warning(c, resources.getString(R.string.parametreSecinizUyari), "{fa-exclamation-triangle}");
return@setOnClickListener;
}

if(aciklama.isEmpty()){
SimpleToast.warning(c, resources.getString(R.string.aciklamaBosUyari), "{fa-exclamation-triangle}");
return@setOnClickListener;
}

val jsonObj: JSONObject = JSONObject();
jsonObj.put("aciklama",aciklama);
val parametreService: IParametreService = WebApiUtil.getParametreService(c);

pd.show();

if(selectedParamTip.equals(resources.getString(R.string.paramKitapTur))){
kitapTurKaydet(parametreService,pd,jsonObj.toString());
alertDialogBuilder.dismiss();
pd.dismiss();
}else if(selectedParamTip.equals(resources.getString(R.string.paramYayinevi))){
yayinEviKaydet(parametreService,pd,jsonObj.toString());
alertDialogBuilder.dismiss();
}
}

val iptalButton: Button = alertDialogBuilder.getButton(AlertDialog.BUTTON_NEGATIVE);
iptalButton.setOnClickListener {
alertDialogBuilder.dismiss();
}
}

Burada validation uyarılarını SimpleToast kütüphanesi ile vermekteyim. Bu kütüphaneyi kullanmak için build.gradle (Module:App) dosyanıza aşağıda ki dependency i eklemeniz gerekmektedir.

    implementation 'com.github.Pierry:SimpleToast:v1.7'

Burada ki kayıt popup ekranı aşağıda ki gibidir.



Bu popup ın layout dosyası aşağıda ki gibidir.

dialog_parametre_ekleme.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"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<Spinner
android:id="@+id/paramTypeSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="35dp"
android:layout_marginEnd="5dp"
style="@style/spinner_style"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<EditText
android:id="@+id/paramText"
android:layout_width="0dp"
android:layout_height="45dp"
android:layout_marginStart="5dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="5dp"
android:background="@drawable/edit_text_border"
android:ems="10"
android:hint="@string/paramAciklamaHint"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/paramTypeSpinner" />

</androidx.constraintlayout.widget.ConstraintLayout>

Soru,istek ve önerilerinizi mesutemrecelenk@gmail.com adresine yazabilirsiniz. Bir sonraki yazıda görüşmek üzere hoşça kalın...