How to use DataStore in Settings fragment for saving keys and values in android

Viewed 1193

I don't know how to add DataStore in setting fragment, where the user can change the "value" of the key of the API . This is thehttps://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&orderby=time&minmag=5&limit=10 API im using . From the API i want to change the minmag value where the user can put any value of minmag in setting fragment the result should be saved in shared preference and also the result should be display in the main activityMain Screen

Setting Screen

Im using kotlin, retrofit and following android architecture component

EarthquakeApiService.kt

     private const val BASE_URL = "https://earthquake.usgs.gov/fdsnws/"

// https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&orderby=time&minmag=5&limit=10
private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

private val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()

interface EarthquakeApiService {
    @GET("event/1/query?")
    suspend fun getJson (@Query("minmag") minMagnitude : String,
     @Query("format") formatted : String, @Query("limit") limited: String,
@Query("orderby") orderBy : String) : EarthquakeResponse
}

object BookApi {
    val retrofitService : EarthquakeApiService by lazy { retrofit.create(EarthquakeApiService::class.java) }
}

EarthquakeResponse.kt

data class EarthquakeResponse( val features : Array<Feature> ?)

data class Feature( val properties : Properties)

data class Properties(val mag : Double,
val place : String , val time : Long)

OverviewFragment

   class OverviewFragment : Fragment() {

     private val viewModel: OverviewViewModel by lazy {
        ViewModelProvider(this).get(OverviewViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        val binding: FragmentOverviewBinding = DataBindingUtil.inflate(
            inflater, R.layout.fragment_overview, container, false)
        binding.viewModel = viewModel
        binding.recycleList.adapter = RecyclerviewAdapter()
        binding.lifecycleOwner = this
        setHasOptionsMenu(true)
        binding.button.setOnClickListener { view: View ->
            view.findNavController().navigate(R.id.action_overviewFragment_to_settingsFragment)
        }
        return binding.root
    }

     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
         super.onCreateOptionsMenu(menu, inflater)
         inflater?.inflate(R.menu.overflow_menu, menu)
     }

     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         return NavigationUI.onNavDestinationSelected(item, requireView().findNavController())
                 || super.onOptionsItemSelected(item)
     }
}

OverviewViewModel

    class OverviewViewModel : ViewModel() {
      lateinit var  minMagnitude : String
     lateinit var orderBy: String
     // Internally, we use a MutableLiveData, because we will be updating the List of MarsProperty
    // with new values
    private val _properties = MutableLiveData<EarthquakeResponse> ()

    // The external LiveData interface to the property is immutable, so only this class can modify
    val properties: LiveData<EarthquakeResponse>
        get() = _properties
    init {
        getBookProperties()
    }

    private fun getBookProperties() {
        viewModelScope.launch {
            try {
                _properties.value = BookApi.retrofitService.getJson("2",
                "geojson", "10", "time")
            } catch (e : Exception) {
            }
        }
    }
}

RecyclerviewAdapter.kt

     class RecyclerviewAdapter() : ListAdapter<Feature, RecyclerviewAdapter.EarthquakePropertyViewHolder>(DiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EarthquakePropertyViewHolder {
        return EarthquakePropertyViewHolder.from(parent)
    }

    override fun onBindViewHolder(holder: EarthquakePropertyViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item)
    }
    class EarthquakePropertyViewHolder private constructor(val binding: EarthquakeRawBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(books: Feature) {
            binding.property = books
            binding.executePendingBindings()
        }
        companion object {
            fun from(parent: ViewGroup): EarthquakePropertyViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val view = EarthquakeRawBinding.inflate(layoutInflater, parent, false)
                return EarthquakePropertyViewHolder(view)
            }
        }
    }
}

class  DiffCallback : DiffUtil.ItemCallback<Feature>() {
    override fun areItemsTheSame(oldItem: Feature, newItem: Feature): Boolean {
        return oldItem === newItem
    }
    override fun areContentsTheSame(oldItem: Feature, newItem: Feature): Boolean {
        return oldItem == newItem

    }
}

BindingAdapter.kt

     @BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: EarthquakeResponse?) {
    val adapter = recyclerView.adapter as RecyclerviewAdapter
    if (data != null) {
        adapter.submitList(data.features?.toList())
    }
}

@BindingAdapter("magnitude")
fun bindAuthor(textView: TextView, magName : Double) {
   val decimalFormat = DecimalFormat("0.0")
    val formattedMagnitude = decimalFormat.format(magName)
    textView.setText(formattedMagnitude.toString())
}

@BindingAdapter("place")
fun bindTitle(textView: TextView, titlePlace : String) {
    textView.setText(titlePlace)       
}

@BindingAdapter("time")
fun bindTime(textView: TextView, titleTime :Long) {
    val timeFormat = SimpleDateFormat("h:mm a")
    val formattedTime = timeFormat.format(titleTime)
    textView.setText(formattedTime.toString())
}

@BindingAdapter("date")
fun bindDate(textView: TextView, titleTime :Long) {
    val timeFormat = SimpleDateFormat("LLL dd, yyyy")
    val formattedDate = timeFormat.format(titleTime)
    textView.setText(formattedDate.toString())
}

MainActivity

     class MainActivity : AppCompatActivity() {

    private lateinit var navController: NavController
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

SettingsFragment

class SettingsFragment : PreferenceFragmentCompat() {

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)
    }
}

activity_main.xml

 RelativeLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.kotlinearthquake.MainActivity"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">

<fragment
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myNavHostFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph"
    tools:ignore="MissingClass" />
</RelativeLayout>

earthquake_raw.xml

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto" >

    <data>
        <variable
            name="property"
            type="com.example.kotlinearthquake.network.Feature" />
    </data>

<LinearLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:orientation="horizontal"
    android:paddingStart="16dp"
    android:paddingLeft="16dp"
    android:paddingEnd="16dp"
    android:paddingRight="16dp">

    <TextView
        android:id="@+id/magnitude"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_gravity="center_vertical"
        android:background="@drawable/magnitude_circle"
        android:fontFamily="sans-serif-medium"
        android:gravity="center"
        android:textColor="@android:color/black"
        android:textSize="16sp"
        app:magnitude="@{property.properties.mag}"
        tools:text="8.9" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <TextView
            android:id="@+id/location_offset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:fontFamily="sans-serif-medium"
            android:maxLines="1"
            android:textAllCaps="true"
            android:textColor="@android:color/black"
            android:textSize="12sp"
            tools:text="30km S of\n" />

        <TextView

            android:id="@+id/primary_location"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:maxLines="2"
            android:textColor="@android:color/black"
            android:textSize="12sp"
            app:place="@{property.properties.place}"
            tools:text="Long placeholder that should wrap to more than 2 line of text" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end"
            android:textColor="@color/textColorEarthquakeDetails"
            android:textSize="12sp"
            app:date="@{property.properties.time}"
            tools:text="Mar 6, 2010" />

        <TextView
            android:id="@+id/time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end"
            android:textColor="@color/textColorEarthquakeDetails"
            android:textSize="12sp"
            app:time="@{property.properties.time}"
            tools:text="3:00 PM" />
    </LinearLayout>
</LinearLayout>
</layout>

fragment_overview.xml

    <layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="viewModel"
            type="com.example.kotlinearthquake.overview.OverviewViewModel" />
    </data>


<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context = "com.example.kotlinearthquake.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycle_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:listData="@{viewModel.properties}"
        tools:listitem="@layout/earthquake_raw"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>


    <TextView
        android:id="@+id/empty_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textAppearance="?android:textAppearanceMedium"/>

    <ProgressBar
        android:id="@+id/loading_indicator"
        style="@style/Widget.AppCompat.ProgressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_marginEnd="40dp"
        android:layout_marginBottom="53dp"
        android:text="Setting" />

</RelativeLayout>
</layout>

root_preferences.xml

    <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <ListPreference
        android:defaultValue="@string/settings_order_by_default"
        android:entries="@array/settings_order_by_label"
        android:entryValues="@array/settings_order_by_value"
        android:key="@string/settings_order_by_key"
        android:title="@string/settings_order_by_label"/>

    <EditTextPreference
        android:defaultValue="@string/settings_min_magnitude_default"
        android:inputType="numberDecimal"
        android:key="@string/settings_min_magnitude_key"
        android:selectAllOnFocus="true"
        android:title="@string/settings_min_magnitude_label" />
</PreferenceScreen>

I tried but didn't found any good answer for my problem .. im literally stuck from the last 1 month ,Please help me , I'm still new to android and Kotlin programming.

0 Answers
Related