Last active
April 22, 2022 23:48
-
-
Save yogithesymbian/b476ef3640cb4f1343ef3816064be8be to your computer and use it in GitHub Desktop.
Kotlin Template Generator StarterPackJelly 2021-2022 - [![License](https://poser.pugx.org/laravel/lumen-framework/license.svg)](https://github.com/yogithesymbian) crud + infinite pagination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
plugins { | |
id 'com.android.application' | |
id 'kotlin-android' | |
} | |
apply plugin: 'com.google.gms.google-services' | |
apply plugin: 'kotlin-parcelize' | |
android { | |
// lintOptions { | |
// checkReleaseBuilds false | |
// // Or, if you prefer, you can continue to check for errors in release builds, | |
// // but continue the build even when errors are found: | |
// // Turns off checks for the issue IDs you specify. | |
// disable 'TypographyFractions', 'TypographyQuotes' | |
// // Turns on checks for the issue IDs you specify. These checks are in | |
// // addition to the default lint checks. | |
// enable 'RtlHardcoded', 'RtlCompat', 'RtlEnabled' | |
// // To enable checks for only a subset of issue IDs and ignore all others, | |
// // list the issue IDs with the 'check' property instead. This property overrides | |
// // any issue IDs you enable or disable using the properties above. | |
// check 'NewApi', 'HandlerLeak' | |
// // If set to true, turns off analysis progress reporting by lint. | |
// quiet true | |
// // if set to true (default), stops the build if errors are found. | |
// abortOnError false | |
// // if true, only report errors. | |
// ignoreWarnings true | |
// baseline file("lint-baseline.xml") | |
// } | |
compileSdk 31 | |
defaultConfig { | |
applicationId "id.scodeid.kotlin_setup_starterpackjelly2021" | |
minSdk 18 | |
targetSdk 31 | |
versionCode 1 | |
versionName "1.0" | |
// | |
buildConfigField "String", "BASE_URL", '"http://192.168.216.190:3001/"' | |
// buildConfigField "String", "BASE_URL_ONLINE", '"http://47.254.248.35/api/api-remote-login-apps/public/"' | |
// buildConfigField "String", "API_TOKEN", '"bearer NExsTm5WT29zZ0RCczRoMkFuVnFJNHVVM3VLaFNERkJuWU9acUpOaA=="' | |
multiDexEnabled true | |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | |
} | |
buildTypes { | |
release { | |
minifyEnabled false | |
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |
} | |
} | |
compileOptions { | |
sourceCompatibility JavaVersion.VERSION_1_8 | |
targetCompatibility JavaVersion.VERSION_1_8 | |
} | |
kotlinOptions { | |
jvmTarget = '1.8' | |
} | |
buildFeatures { | |
viewBinding true | |
} | |
} | |
dependencies { | |
implementation 'androidx.core:core-ktx:1.6.0' | |
implementation 'androidx.appcompat:appcompat:1.3.1' | |
implementation 'com.google.android.material:material:1.4.0' | |
implementation 'androidx.constraintlayout:constraintlayout:2.1.1' | |
implementation "androidx.fragment:fragment-ktx:1.3.6" | |
implementation "androidx.activity:activity-ktx:1.3.1" | |
implementation 'androidx.multidex:multidex:2.0.1' | |
/** | |
* FAN ( Fast Android Networking ) | |
*/ | |
implementation 'com.amitshekhar.android:android-networking:1.0.2' | |
implementation 'com.amitshekhar.android:rx2-android-networking:1.0.2' | |
/** | |
* Architecture Component | |
* LifeCycle Component | |
*/ | |
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' | |
implementation 'androidx.annotation:annotation:1.2.0' | |
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' | |
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' | |
implementation 'androidx.work:work-runtime-ktx:2.7.0' | |
implementation 'com.google.android.gms:play-services-base:17.6.0' | |
androidTestImplementation "androidx.arch.core:core-testing:2.1.0" | |
//gson | |
implementation 'com.google.code.gson:gson:2.8.8' | |
implementation "androidx.browser:browser:1.3.0" | |
// firebase | |
implementation platform('com.google.firebase:firebase-bom:28.4.2') | |
implementation 'com.google.firebase:firebase-analytics-ktx' | |
// Declare the dependencies for the Firebase Cloud Messaging and Analytics libraries | |
// When using the BoM, you don't specify versions in Firebase library dependencies | |
implementation 'com.google.firebase:firebase-messaging-ktx' | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/yogithesymbian/Kotlin-Setup-Starterpackjelly-2021 | |
// model viemodel viewmodelfacotry interface livedata | |
// soon will publish | |
// (File Header.java) | |
/** | |
* Android Studio Arctic Fox | 2020.3.1 Patch 3 | |
* Build #AI-203.7717.56.2031.7784292, built on October 1, 2021 | |
* Runtime version: 11.0.10+0-b96-7281165 x86_64 | |
* VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. | |
* macOS 11.6 | |
* GC: G1 Young Generation, G1 Old Generation | |
* Memory: 2048M | |
* Cores: 8 | |
* Registry: external.system.auto.import.disabled=true, ide.balloon.shadow.size=0 | |
* Non-Bundled Plugins: com.mallowigi, com.robohorse.robopojogenerator, dev.polek.adbwifi, Dart, com.thoughtworks.gauge, org.jetbrains.kotlin, io.flutter, com.chrisrm.idea.MaterialThemeUI, org.intellij.plugins.markdown | |
* ----------------------------------- | |
* \ ^__^ | |
* \ (oo)\_______ | |
* (__)\ )\/\ | |
* ||----w | | |
* || || | |
* git clone https://github.com/yogithesymbian/Kotlin-Setup-Starterpackjelly-2021/tree/master | |
* 2021 - 2022 (C) Yogi Arif Widodo (yogithesymbian) | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fragmentactivity | |
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end | |
import android.annotation.SuppressLint | |
import android.os.Bundle | |
import android.util.Log | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import androidx.fragment.app.Fragment | |
import androidx.fragment.app.viewModels | |
import androidx.lifecycle.Observer | |
import androidx.recyclerview.widget.LinearLayoutManager | |
import androidx.recyclerview.widget.DefaultItemAnimator | |
import androidx.recyclerview.widget.RecyclerView | |
import id.scode.kuisioner.R | |
import id.scode.kuisioner.utils.gone | |
import id.scode.kuisioner.utils.visible | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.GlobalScope | |
import kotlinx.coroutines.launch | |
import kotlinx.coroutines.withContext | |
import kotlin.properties.Delegates | |
import kotlinx.coroutines.* | |
import gone | |
import visible | |
#parse("File Header.java") | |
class ${NAME} : Fragment(), $View_Interface_Class { | |
private lateinit var binding: ${Item_Layout_ID_Binding}Binding | |
private val observer = | |
Observer<MutableList<${Model_Class}>> { item -> | |
if (item != null) | |
scoreAdapter.setData(item) | |
binding.$ProgressBar?.gone() | |
} | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
page$Adapter_Class = 0 | |
totalPage$Adapter_Class = 0 | |
} | |
override fun onCreateView( | |
inflater: LayoutInflater, | |
container: ViewGroup?, | |
savedInstanceState: Bundle? | |
): View { | |
binding = ${Item_Layout_ID_Binding}Binding.inflate(inflater, container, false) | |
GlobalScope.launch { | |
show$View_Model_Class() | |
} | |
return binding.root | |
} | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
scoreAdapter = $Adapter_Class(mutableList) { | |
Log.d(TAG_LOG,"clicked ${it.soal}") | |
//try { | |
// val intent = Intent(requireContext(), ScoreDetailActivity::class.java) | |
// intent.putExtra(ScoreDetailActivity.EXTRA_SCORE_DATA, it) | |
// requireContext().startActivity(intent) | |
//} catch (e: Exception) { | |
// Log.d(TAG_LOG, "clicked $e") | |
//} | |
} | |
initListener$Adapter_Class() | |
} | |
private fun initListener$Adapter_Class() { | |
binding.$Id_Recycler | |
.addOnScrollListener(object : RecyclerView.OnScrollListener() { | |
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { | |
val linearLayoutManager = recyclerView.layoutManager as LinearLayoutManager | |
val countItem = linearLayoutManager.itemCount | |
val lastVisiblePosition = | |
linearLayoutManager.findLastCompletelyVisibleItemPosition() | |
val isLastPosition = countItem.minus(1) == lastVisiblePosition | |
if (isLastPosition && page$Adapter_Class < totalPage$Adapter_Class) { | |
page$Adapter_Class = page$Adapter_Class .plus(1) | |
val viewModel: $View_Model_Class by viewModels { $View_Model_Factory_Class(this@HomeFragment) } | |
Log.e(TAG_LOG, "page : $page$Adapter_Class") | |
viewModel.show$View_Model_Class(requireContext(), page$Adapter_Class .toString()) | |
} | |
} | |
}) | |
} | |
private suspend fun show$View_Model_Class() { | |
try{ | |
// get history absen where no expired date | |
withContext(Dispatchers.Main) { | |
scoreAdapter.notifyDataSetChanged() | |
binding.$Id_Recycler .itemAnimator = DefaultItemAnimator() | |
binding.$Id_Recycler .setHasFixedSize(true) | |
binding.$Id_Recycler .layoutManager = LinearLayoutManager(requireContext()) | |
binding.$Id_Recycler .adapter = scoreAdapter | |
} | |
val viewModel: $View_Model_Class by viewModels { $View_Model_Factory_Class(this) } | |
withContext(Dispatchers.Main) { | |
viewModel.liveData().observe(viewLifecycleOwner, observer) | |
Log.e(TAG_LOG, "page : $page$Adapter_Class") | |
if (scoreAdapter.itemCount == 0) | |
viewModel.show$View_Model_Class(requireContext(), page$Adapter_Class .toString()) | |
} | |
} catch (e: Exception){ | |
Log.d(TAG_LOG, "exception request ${e.printStackTrace()}") | |
} | |
} | |
override fun showLoading$View_Interface_Class() { | |
binding.$ProgressBar?.visible() | |
} | |
override fun hideLoading$View_Interface_Class() { | |
binding.$ProgressBar?.gone() | |
} | |
override fun paginationTotalPage$View_Interface_Class(totalPageDef: Int) { | |
totalPage$Adapter_Class = totalPageDef | |
} | |
// override fun show$View_Interface_Class(data: MutableList<${Model_Class}>?) { | |
// GlobalScope.launch { | |
// mutableList.clear() | |
// val assign = async { | |
// data?.let { | |
// mutableList.addAll(it) | |
// } | |
// } | |
// assign.await() | |
// } | |
//} | |
companion object { | |
val TAG_LOG = ${NAME}::class.java.simpleName | |
lateinit var scoreAdapter: $Adapter_Class | |
private var mutableList: MutableList<${Model_Class}> = mutableListOf() | |
// pagination | |
private var page$Adapter_Class by Delegates.notNull<Int>() | |
private var totalPage$Adapter_Class by Delegates.notNull<Int>() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// View_Interface_Class | |
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end | |
#parse("File Header.java") | |
interface ${NAME} { | |
fun showLoading${NAME}() | |
fun hideLoading${NAME}() | |
fun paginationTotalPage${NAME}(totalPageDef: Int) | |
// fun show${NAME}( | |
// data: MutableList<${Model_Class}> | |
//) | |
//fun showSingle${NAME}( | |
// data: ${Model_Class} | |
//) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ViewModel | |
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end | |
import android.content.Context | |
import android.util.Log | |
import android.widget.Toast | |
import androidx.lifecycle.LiveData | |
import androidx.lifecycle.MutableLiveData | |
import androidx.lifecycle.ViewModel | |
import com.androidnetworking.AndroidNetworking | |
import com.androidnetworking.common.Priority | |
import com.androidnetworking.error.ANError | |
import com.androidnetworking.interfaces.JSONObjectRequestListener | |
import org.json.JSONObject | |
import com.google.gson.Gson | |
import kotlinx.coroutines.* | |
import org.json.JSONObject | |
#parse("File Header.java") | |
class ${NAME}(val view: $viewinterface) : ViewModel() { | |
val mutableLiveData = MutableLiveData<MutableList<${Model_Class}>>() | |
// val mutableLiveDataSingle = MutableLiveData<${Model_Class}?>() | |
companion object { | |
val TAG_LOG: String = ${NAME}::class.java.simpleName | |
private var mutableList: MutableList<${Model_Class}> = mutableListOf() | |
// private var mutableListSingle: ${Model_Class}? = null | |
} | |
fun show${NAME}( | |
context: Context, | |
page: String | |
) { | |
view.showLoading() | |
val gson = Gson() | |
Log.d( | |
TAG_LOG, """ | |
request api is in background | |
server : $Class_EndPoint_And_Url | |
""".trimIndent() | |
) | |
AndroidNetworking.$getOrPost($Class_EndPoint_And_Url) | |
.addHeaders("Authorization", "${BuildConfig.API_TOKEN}") | |
.addQueryParameter("page", page) | |
.addQueryParameter("size", "5") | |
//.addBodyParameter("password", pass) | |
.setPriority(Priority.LOW) | |
.build() | |
.getAsJSONObject(object : JSONObjectRequestListener { | |
override fun onResponse(response: JSONObject) { | |
GlobalScope.launch { | |
val jsonArrayData = async { response.toString() } | |
val responseJson = async { | |
gson.fromJson( | |
jsonArrayData.await(), | |
${Model_Class_Response}::class.java | |
) | |
} | |
Log.d(TAG_LOG, """ ------ | |
response ${responseJson.await()} | |
""".trimIndent()) | |
val data = responseJson.await()?.results | |
data?.let { | |
// view.show$viewinterface(data) | |
mutableLiveData.postValue(it) | |
} | |
withContext(Dispatchers.Main) { | |
view.hideLoading() | |
Toast.makeText(context,"${toast_message}", Toast.LENGTH_LONG).show() | |
} | |
mutableLiveData.postValue(data) | |
view.paginationTotalPage$View_Interface_Class(response.optInt("total_pages")) | |
} | |
} | |
override fun onError(anError: ANError) { | |
if (anError.errorCode != 0) { | |
Log.d( TAG_LOG, "onError errorCode : ${anError.errorCode}") | |
Log.d( TAG_LOG, "onError errorBody : ${anError.errorBody}") | |
Log.d(TAG_LOG, "onError errorDetail : ${anError.errorDetail}") | |
if (anError.errorCode == "404".toInt()) | |
mutableList.clear() | |
mutableLiveData.postValue(mutableList) | |
// if (anError?.errorCode == "404".toInt()) | |
// mutableListSingle = null | |
// mutableLiveDataSingle.postValue(mutableListSingle) | |
} else { | |
Log.d( TAG_LOG, "onError errorDetail : " + anError.errorDetail) | |
} | |
} | |
}) | |
} | |
fun liveData(): LiveData<MutableList<${Model_Class}>> { | |
return mutableLiveData | |
} | |
// fun liveDataSingle(): LiveData<${Model_Class}?> { | |
// return mutableLiveDataSingle | |
// } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// View_Model_Factory_Class | |
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end | |
import androidx.lifecycle.ViewModel | |
import androidx.lifecycle.ViewModelProvider | |
#parse("File Header.java") | |
class ${NAME}(private val view: $viewinterface) : | |
ViewModelProvider.Factory { | |
override fun <T : ViewModel?> create(modelClass: Class<T>): T { | |
return ${viewinterface}Model(view) as T | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// RecyclerView | Adapter | |
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end | |
import android.content.Context | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import androidx.recyclerview.widget.RecyclerView | |
import kotlinx.android.extensions.LayoutContainer | |
#parse("File Header.java") | |
class ${NAME} ( | |
private val items: MutableList<${Model_Class}>, | |
private val listener: (${Model_Class}) -> Unit | |
) : RecyclerView.Adapter<${NAME}.${ViewHolder_Class}>(){ | |
init { | |
setHasStableIds(true) | |
} | |
fun setData(itemsData: MutableList<${Model_Class}>) { | |
// items.clear() | |
items.addAll(itemsData) | |
notifyDataSetChanged() | |
} | |
class ${ViewHolder_Class}(override val containerView: View): RecyclerView.ViewHolder(containerView), | |
LayoutContainer { | |
private val binding = ${Item_Layout_ID_Binding}Binding.bind(containerView) | |
fun bindItem(item: ${Model_Class}, listener: (${Model_Class}) -> Unit) { | |
//item.image.let { Picasso.get().load(it).fit().into(img_main) } | |
with(binding){ | |
// this.txtScore.text = item.score.toString() | |
containerView.setOnClickListener { listener(item) } | |
} | |
} | |
} | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = | |
${ViewHolder_Class}(LayoutInflater.from(parent.context).inflate(R.layout.${Item_Layout_ID}, parent, false)) | |
override fun getItemCount(): Int = items.size | |
override fun onBindViewHolder(holder: ${ViewHolder_Class}, position: Int) = | |
holder.bindItem(items[position], listener) | |
override fun getItemId(position: Int): Long { | |
return position.toLong() | |
} | |
override fun getItemViewType(position: Int): Int { | |
return position | |
} | |
companion object{ | |
val TAG_LOG = ${NAME}::class.java.simpleName | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment