First I have declared the variables in the layout file
<data>
<variable
name="signUpViewModel"
type="ac.connect.ui.signup.SignUpViewModel" />
</data>
Now I'm trying to use a function of StringExtension class which takes string value as parameter and to set the result to textView
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="20dp"
android:textStyle="bold"
android:background="#C1BDBD"
android:textColor="#3D3C3C"
app:capitalizeFirstLetter="#{signUpViewModel.name}" />
capitalize First Letter function
fun capitalizeFirstLetter(value: String): String {
var ans = ""
val words = value.split(" ")
words.forEach {
ans += it.capitalize() + " "
}
return ans
}
ViewModel
class SignUpViewModel(private val setProfileUseCase: SetProfileUseCase) :
ViewModel() {
private val _profile = MutableLiveData<ProfileModel>()
val profile: LiveData<ProfileModel>
get() = _profile
private val _name = MutableLiveData<String>()
val name: LiveData<String>
get() = _name
fun setName(name: Editable) {
_name.value = name.toString()
}
fun setProfileData() {
viewModelScope.launch {
val profile = ProfileModel(
name = "kamal nayan",
branch = "CSE",
gender = "Male",
mobileNumber = "+91-73555555517",
rollNo = "GCS/345353",
uid = "ghafagaraggGGG"
)
val response = setProfileUseCase.invoke(profile)
_profile.value = profile
response.successOrError(::handleProductDetailsSuccess, ::handleSignUpFailure)
}
}
private fun handleProductDetailsSuccess(response: Boolean) {
_name.value = "User Data Uploaded Successfully"
}
private fun handleSignUpFailure(failure: Failure, error: ErrorResponse?) {
Timber.log(Log.ERROR, error?.message)
}
}
Fragment Code:
class SignUpFragment : Fragment(R.layout.fragment_sign_up) {
private val viewModel: SignUpViewModel by viewModel()
private var binding by autoCleared<FragmentSignUpBinding>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentSignUpBinding.bind(view)
binding.signUpViewModel = viewModel
binding.lifecycleOwner = this
binding.signUp.setOnClickListener {
viewModel.setProfileData()
}
}
companion object {
fun newInstance(): SignUpFragment {
return SignUpFragment()
}
}
}
The output is blank , like no text in the textView
Kindly help me with this, Thanks in advance.
I think the problem is you are not setting the value of the variable stringExtensions when setting up your DataBinding
import ac.connect.utils.StringExtensions
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentSignUpBinding.bind(view)
binding.signUpViewModel = viewModel
// binding.stringExtensions = StringExtensions() // If it is a class
// binding.stringExtensions = StringExtensions // If it is an object
binding.lifecycleOwner = this
binding.signUp.setOnClickListener {
viewModel.setProfileData()
}
}
If I understand right you need make BindingAdapter. So you need rewrite your 'capitalizeFirstLetter' function as below.
#BindingAdapter("app:capitalizeFirstLetter")
#JvmStatic fun capitalizeFirstLetter(textView: TextView, value: String){
var ans = ""
val words = value.split(" ")
words.forEach {
ans += it.capitalize() + " "
}
textView.setText(ans)
}
Also I didn't see where you call setName function. Are you sure that _name.value is not empty?
Related
I am trying to pass the data from NgoSignup1Fragment to NgoSignup2Fragment but i am getting null in NgoSignup2Fragment as you can see Debug Image, I didn't know what's the issue if anyone would help it will helpful for me.
class NgoSignup1Fragment : Fragment() {
private lateinit var communicator: Communicator
private lateinit var nextBtn: Button
private var name : TextInputEditText ?=null
private var mail : TextInputEditText ?=null
private var phone : TextInputEditText ?=null
private var add :TextInputEditText ?=null
private var pinCode :TextInputEditText ?=null
private var password :TextInputEditText ?=null
private var confirmPassword :TextInputEditText ?=null
private val emailPattern = "[a-zA-Z0-9._-]+#[a-z]+\\.+[a-z]+"
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
val v = layoutInflater.inflate(R.layout.ngo_signup1_fragment, container, false)
communicator = activity as Communicator
nextBtn = v.findViewById(R.id.btn_ngosignup1_next)
name = v?.findViewById(R.id.et_ngosignup_name)
mail = v?.findViewById(R.id.et_ngosignup_mail)
phone = v?.findViewById(R.id.et_ngosignup_phone)
add = v?.findViewById(R.id.et_ngosignup_address)
pinCode = v?.findViewById(R.id.et_ngosignup_pincode)
password =v?.findViewById(R.id.et_ngosignup_password)
confirmPassword =v?.findViewById(R.id.et_ngosignup_confirmpassword)
nextBtn.setOnClickListener {
val orgName = name?.text.toString().trim()
val orgMail = mail?.text.toString().trim()
val orgPhone = phone?.text.toString().trim()
val officeAdd = add?.text.toString().trim()
val orgPinCode = pinCode?.text.toString().trim()
val orgPass = password?.text.toString().trim()
val confirmPass=confirmPassword?.text.toString().trim()
if (orgName.isEmpty()) {
name?.error = "Please provide organisation's name"
markButtonDisable(nextBtn)
}
if (orgMail.isEmpty()) {
mail?.error = "Mail cannot be empty"
markButtonDisable(nextBtn)
}
if (orgPhone.isEmpty()) {
phone?.error = "Enter your phone number"
markButtonDisable(nextBtn)
}
if (officeAdd.isEmpty()) {
add?.error = "Address cannot be empty"
markButtonDisable(nextBtn)
}
if (orgPinCode.isEmpty()) {
name?.error = "Name cannot be empty"
markButtonDisable(nextBtn)
}
if (orgPass.isEmpty()){
password?.error = "Password cannot be empty"
markButtonDisable(nextBtn)
}
if (!(orgMail.matches(emailPattern.toRegex()))) {
mail?.error = "Invalid email"
markButtonDisable(nextBtn)
}
if (!(isValidPassword(orgPass))) {
password?.error = "Password format is invalid"
markButtonDisable(nextBtn)
}
if(orgPass != confirmPass){
confirmPassword?.error = "Passwords doesn't match"
markButtonDisable(nextBtn)
}else{
communicator.passDataCom(orgName,orgMail,orgPhone,officeAdd,orgPinCode,orgPass)
activity?.supportFragmentManager?.beginTransaction()
?.replace(
R.id.fragment_container1,
NgoSignup2Fragment()
)?.addToBackStack(null)?.commit()
}
//this opens up the sign up 2 page
//Put the value
//Put the value
}
return v
}
private fun isValidPassword(password: String): Boolean {
val passwordREGEX = Pattern.compile(
"^" +
"(?=.*[0-9])" + //at least 1 digit
"(?=.*[a-z])" + //at least 1 lower case letter
"(?=.*[A-Z])" + //at least 1 upper case letter
"(?=.*[a-zA-Z])" + //any letter
"(?=.*[##$%^&+=])" + //at least 1 special character
"(?=\\S+$)" + //no white spaces
".{8,}" + //at least 8 characters
"$"
)
return passwordREGEX.matcher(password).matches()
}
private fun markButtonDisable(b:Button){
b.isEnabled =false
b.setBackgroundColor(resources.getColor(R.color.theme_button_disabled))
}}
my interface which i am using to pass data :
interface Communicator {
fun passDataCom(
orgName: String,
orgMail: String,
orgPhone: String,
officeAdd: String,
orgPin: String,
orgPass: String
)}
This is MainActivity where the string values are passed Till here all the variables values are correct
class MainActivity : AppCompatActivity(),Communicator {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*This part of the code is used to set the default theme as the theme was set to the splash screen before setting the main activity layout
remove the comment tag for adding the logic*/
setTheme(R.style.Theme_Samarpan)
setContentView(R.layout.activity_main)
addFragment()
}
private fun addFragment() {
val userSignInLayout= LoginFragment()
supportFragmentManager.beginTransaction().add(R.id.fragment_container1,userSignInLayout).commit()
}
override fun passDataCom(
orgName: String,
orgMail: String,
orgPhone: String,
officeAdd: String,
orgPin: String,
orgPass: String
) {
val bundle=Bundle()
bundle.putString("Name",orgName)
bundle.putString("Mail",orgMail)
bundle.putString("Phone",orgPhone)
bundle.putString("Address",officeAdd)
bundle.putString("PinCode",orgPin)
bundle.putString("Password",orgPass)
val transaction=this.supportFragmentManager.beginTransaction()
val ngoSignUp2 = NgoSignup2Fragment()
ngoSignUp2.arguments = bundle
transaction. Commit()
}}
This is the fragment where i want to send the values but i m getting null values to all the variables .
class NgoSignup2Fragment : Fragment(){
private var v : View?=null
private var btnNgoRegister: Button?=null
private var tilCategoryOthers:TextInputLayout?=null
private var etCategoryOthers:TextInputEditText?=null
private var orgName:String =""
private var orgMail:String =""
private var orgPhone:String =""
private var officeAdd:String =""
private var orgPin:String =""
private var orgPass:String =""
private var category:String=""
private lateinit var registerAuth: FirebaseAuth
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
v = layoutInflater.inflate(R.layout.ngo_signup2_fragment,container,false)
btnNgoRegister=v?.findViewById(R.id.btnNgoRegister)
tilCategoryOthers=v?.findViewById(R.id.til_category_others)
etCategoryOthers=v?.findViewById(R.id.et_category_others)
val organisationTypes = resources.getStringArray(R.array.organisation_type)
val arrayAdapter = ArrayAdapter(requireContext(),R.layout.dropdown_item,organisationTypes)
val autoCompleteTV= v?.findViewById<AutoCompleteTextView>(R.id.ngosignup_select_orgtype_items)
autoCompleteTV?.setAdapter(arrayAdapter)
category=autoCompleteTV?.text.toString().trim()
registerAuth= Firebase.auth
orgName= arguments?.getString("Name").toString().trim()
orgMail= arguments?.getString("Mail").toString().trim()
orgPhone=arguments?.getString("Phone").toString().trim()
officeAdd=arguments?.getString("Address").toString().trim()
orgPin=arguments?.getString("PinCode").toString().trim()
orgPass=arguments?.getString("Password").toString().trim()
btnNgoRegister?.setOnClickListener {
Toast.makeText(activity, orgName, Toast.LENGTH_SHORT).show()
if(category == "Others"){
//get the category from the user of the type he is from other than the list
btnNgoRegister?.isEnabled=false
tilCategoryOthers?.visibility=View.VISIBLE
category=etCategoryOthers?.text.toString()
btnNgoRegister?.isEnabled=true
}
val db = FirebaseFirestore.getInstance()
try{
registerAuth.createUserWithEmailAndPassword(orgMail,orgPass)
.addOnCompleteListener{ task->
if(task.isSuccessful){
val ngo: FirebaseUser? =registerAuth.currentUser
Toast.makeText(
activity,
"Thank You! for choosing us",
Toast.LENGTH_SHORT
).show()
val documentReference : DocumentReference =db.collection("users").document(
ngo?.uid ?: ""
)
val ngoInfo :MutableMap<String,Any> = HashMap()
ngoInfo["Full Name"]= orgName
ngoInfo["Email"]= orgMail
ngoInfo["PhoneNumber"]=orgPhone
ngoInfo["Address"]=officeAdd
ngoInfo["Pin Code"]=orgPin
ngoInfo["isDonor"]="0"
// add the value of the org type from the dropdown and upload document work
documentReference.set(ngoInfo).addOnSuccessListener {
Log.d(ContentValues.TAG, "User data for $orgName was collected successfully ")
}.addOnFailureListener{ e ->
Log.w(ContentValues.TAG, "Error adding data", e)
}
}else{
Toast.makeText(
activity,
task.exception!!.message.toString(),
Toast.LENGTH_SHORT
).show()
}
}
}
catch(e :Exception){
Toast.makeText(context, "Fields cannot be empty $e", Toast.LENGTH_SHORT).show()
}
}
return v
}}
I am using this command to get data from a Room database:
select * from location_search_results where searchQuery = "wilmington"
Here is what the database looks like:
And here are the search results:
I have verified that the name of the table is correct and everything, and there's no spelling errors that I can find, so why would this query not return any of the three rows that it should match?
EDIT for code:
The source code is publicly available here, I am working in the mvvm branch, so if you pull it, make sure you're there. Below are the relevant classes:
LocationSearchResponse.kt:
#Entity(tableName = "location_search_results")
class LocationSearchResponse(
#ColumnInfo(name = "type")
val type: String,
#TypeConverters(DataConverter::class)
#SerializedName("query")
val searchQuery: List<String>,
#TypeConverters(DataConverter::class)
val features: List<Feature>,
#ColumnInfo(name = "attribution")
val attribution: String
) {
#PrimaryKey(autoGenerate = true)
var id: Int = 0
}
LocationSearchRepositoryImpl.kt:
class LocationSearchRepositoryImpl (
private val locationResponseDao: LocationResponseDao,
private val locationNetworkDataSource: LocationNetworkDataSource
): LocationSearchRepository {
init {
locationNetworkDataSource.downloadedLocationSearchResults.observeForever { locationResults ->
persistFetchedLocations(locationResults)
}
}
// update search data in db if necessary, then return the data that was searched for.
override suspend fun searchForLocation(query: String): LiveData<out LocationSearchResponse> {
return withContext(Dispatchers.IO) {
initSearch(query)
return#withContext locationResponseDao.searchForLocation(query)
}
}
// if a fetch is necessary (query has not already been searched), fetch search results
private suspend fun initSearch(query: String) {
if (isFetchLocationResultsNeeded(query))
fetchLocationResults(query)
}
private fun isFetchLocationResultsNeeded(query: String) : Boolean {
// get the cached results. If it's null, return true because it needs to be updated
val cachedResults = locationResponseDao.searchForLocationNonLive(query.toLowerCase())
if (cachedResults == null) return true
// if the results are empty, it needs to be fetched, else it doesn't
return cachedResults.features.isEmpty()
}
private suspend fun fetchLocationResults(query: String) {
locationNetworkDataSource.fetchLocationSearchResults("mapbox.places", query)
}
private fun persistFetchedLocations(fetchedLocationResults: LocationSearchResponse) {
GlobalScope.launch(Dispatchers.IO) {
locationResponseDao.upsert(fetchedLocationResults)
}
}
}
LocationResponseDao.kt:
#Dao
interface LocationResponseDao {
// update or insert existing entry if there is a conflict when adding to db
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun upsert(locationResults: LocationSearchResponse)
#Query("select * from location_search_results WHERE searchQuery = :query")
fun searchForLocation(query: String): LiveData<LocationSearchResponse>
#Query("select * from location_search_results WHERE searchQuery = :query")
fun searchForLocationNonLive(query: String): LocationSearchResponse?
#Query("delete from location_search_results")
fun nukeTable()
}
and ChooseCityFragment.kt:
class ChooseCityFragment : ScopedFragment(), KodeinAware {
override val kodein by closestKodein()
private val locationViewModelFactory: LocationResponseViewModelFactory by instance()
private val weatherResponseViewModelFactory: WeatherResponseViewModelFactory by instance()
private lateinit var locationViewModel: LocationResponseViewModel
private lateinit var weatherViewModel: WeatherResponseViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
setupViews()
// Inflate the layout for this fragment
return inflater.inflate(R.layout.choose_city_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
locationViewModel = ViewModelProviders.of(this, locationViewModelFactory)
.get(LocationResponseViewModel::class.java)
weatherViewModel = ViewModelProviders.of(this, weatherResponseViewModelFactory)
.get(WeatherResponseViewModel::class.java)
updateToolbar()
}
fun updateToolbar() {
(activity as? AppCompatActivity)?.supportActionBar?.title = "Choose Location"
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = null
}
fun bindUI() = launch {
val locationResults = locationViewModel.locationResponse
val owner = viewLifecycleOwner
locationResults.observe(owner, Observer {
if (it == null) return#Observer
// TODO: set loading icon to GONE
initRecyclerView(it.features.toLocationSearchResultListItem())
})
}
fun setupViews() = launch {
search_button.setOnClickListener {
searchLocations()
search_results_rv.adapter?.notifyDataSetChanged()
}
}
// TODO: search text can not be more than 20 words or more than 256 characters. Need to account for this
fun searchLocations() = launch {
val searchText = search_box.text.toString()
if (searchText != "") {
locationViewModel.searchLocation(search_box.text.toString())
bindUI()
} else
Toast.makeText(context?.applicationContext, "Please enter a search term", Toast.LENGTH_SHORT).show()
}
private fun List<Feature>.toLocationSearchResultListItem() : List<LocationSearchResultListItem> {
return this.map {
LocationSearchResultListItem(it)
}
}
private fun initRecyclerView(items: List<LocationSearchResultListItem>) {
val groupAdapter = GroupAdapter<ViewHolder>().apply {
addAll(items)
}
groupAdapter.notifyDataSetChanged()
search_results_rv.apply {
layoutManager = LinearLayoutManager(this#ChooseCityFragment.context)
adapter = groupAdapter
}
groupAdapter.setOnItemClickListener { item, view ->
(item as? LocationSearchResultListItem)?.let {
refreshWeather(it.feature.coordinates[0], it.feature.coordinates[1])
}
}
}
private fun refreshWeather(latitude: Double, longitude: Double) = launch {
weatherViewModel.refreshWeatherWithCoordinates(latitude, longitude)
}
}
It turns out there was a space being added to the end of the searchQuery that I wasn't able to see. Once I figured out where my code was adding that space, I removed it and now everything looks good.
try something like this
it`s a dao interface example
use big letters in your query
#Query("SELECT * FROM person WHERE favoriteColor LIKE :color")
List<Person> getAllPeopleWithFavoriteColor(String color);
more info here
I'm using MVVM as architecture, also the repository pattern. I have a Web service, a room database also. Using coroutines block any button I click.
There's a list/detail implemented with a fragment and an activity respectively.
I can figure out what's wrong in the way I implemented the coroutines and Viewmodel.
class BuySharedViewModel(application: Application) : AndroidViewModel(application) {
private val repository: BuyRepository
var allBuys: LiveData<List<Buy>>
init {
val buyDao = KunukRoomDatabase.getDatabase(application, viewModelScope).buyDao()
val buyRemote = BuyRemote()
repository = BuyRepository.getInstance(buyDao , buyRemote)
//Use async because it return a result
viewModelScope.launch { getAllBuys() }
allBuys = buyDao.loadAllBuys()
}
private suspend fun getAllBuys() {
repository.getBuys()
}
}
Here's is the Repository, it take data from web service and add it to the room database, while ViewModel get's data from room database.
class BuyRepository (private val buyDao: BuyDao, private val buyRemote: BuyRemote) {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.Default + job)
companion object {
//For singleton instantiation
#Volatile private var instance: BuyRepository? = null
fun getInstance(buyDao: BuyDao, buyRemote: BuyRemote) =
instance ?: synchronized(this) {
instance ?: BuyRepository(buyDao, buyRemote)
.also { instance = it}
}
}
suspend fun getBuys(){
refresh()
}
private suspend fun refresh(){
try {
val list = scope.async { buyRemote.loadBuys() }
list.await().forEach { buy -> insert(buy) }
} catch (e: Throwable) {}
}
#WorkerThread
private fun insert(buy: Buy) {
buyDao.insertBuy(buy)
}
}
The fragment work, data are displayed, when i click on an item from that fragment(recyclerView) it work, the activity display details data. But none of the click on that activity works, like it doesn't detect the clicks. I guess it got something to do with the coroutines because when I comment out the code viewmodelScope.launch { getAllBuys()} from the BuySharedViewModel it works, because it load data from the previous call from room database, and the clicks works.
Here's the code in the detail view:
class BuyDetailActivity : AppCompatActivity() {
private lateinit var sharedViewModel: BuySharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lateinit var buy: Buy
sharedViewModel = ViewModelProviders.of(this).get(BuySharedViewModel::class.java)
val position = intent.getIntExtra("position", 0)
sharedViewModel.allBuys.observe(this, Observer<List<Buy>> { buys ->
buy = buys[position]
val binding: com.example.drake.kunuk.databinding.ActivityBuyDetailBinding =
DataBindingUtil.setContentView(this, com.example.drake.kunuk.R.layout.activity_buy_detail)
binding.buy = buy
val agentNumber = buy.agentNumber?:"+50937438713"
bnvContactAgent.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
com.example.drake.kunuk.R.id.action_call -> {
val callNumberUri = Uri.parse("tel:$agentNumber")
val callIntent = Intent(Intent.ACTION_DIAL, callNumberUri)
startActivity(callIntent)
}
com.example.drake.kunuk.R.id.action_sms -> {
val smsNumberUri = Uri.parse("sms:$agentNumber")
val smsIntent = Intent(Intent.ACTION_SENDTO, smsNumberUri)
startActivity(smsIntent)
}
com.example.drake.kunuk.R.id.action_email -> {
val uriText = "mailto:drakecolin#gmail.com" +
"?subject=" + Uri.encode("I'm interested in $agentNumber") +
"&body=" + Uri.encode("Hello, ")
val uri = Uri.parse(uriText)
val sendIntent = Intent(Intent.ACTION_SENDTO)
sendIntent.data = uri
startActivity(Intent.createChooser(sendIntent, "Send email"))
}
}
false
}
This is the code of my fragment:
class BuyFragment : Fragment() {
companion object {
fun newInstance() = BuyFragment()
}
private lateinit var viewModel: BuySharedViewModel
private val buyList = ArrayList<Buy>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Get a new or existing ViewModel from the ViewModelProvider.
viewModel = ViewModelProviders.of(this).get(BuySharedViewModel::class.java)
// Add an observer on the LiveData returned by loadAllBuys.
// The onChanged() method fires when the observed data changes and the activity is
// in the foreground.
viewModel.allBuys.observe(this, Observer<List<Buy>> { buys ->
// Update the cached copy of the words in the adapter.
buys?.let { (rvBuy.adapter as BuyAdapter).setBuys(it) }
progressBar.visibility = View.GONE
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.buy_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
rvBuy.layoutManager = LinearLayoutManager(context)
rvBuy.adapter = BuyAdapter(activity!!.applicationContext,
R.layout.buy_card, buyList)
progressBar.visibility = View.VISIBLE
}
}
This is the code for the BuyDao:
#Dao
interface BuyDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertBuy(vararg buys: Buy)
#Update
fun updateBuy(vararg buys: Buy)
#Delete
fun deleteBuys(vararg buys: Buy)
#Query("SELECT * FROM buys")
fun loadAllBuys(): LiveData<List<Buy>>
#Query("DELETE FROM buys")
suspend fun deleteAll()
}
viewModelScope by default uses Dispatchers.Main and it is blocking your UI.
Try this:
viewmodelScope.launch(Dispatchers.IO) { getAllBuys()}
Edit:
The problem is your setting listner on BottomNavigation when your livedata is updated which is causing this weird issue.
Replace your BuyDetailActivity code with this:
class BuyDetailActivity : AppCompatActivity() {
private lateinit var sharedViewModel: BuySharedViewModel
private var agentNumber = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityBuyDetailBinding =
DataBindingUtil.setContentView(this, R.layout.activity_buy_detail)
binding.buy = Buy()
lateinit var buy: Buy
sharedViewModel = ViewModelProviders.of(this).get(BuySharedViewModel::class.java)
val position = intent.getIntExtra("position", 0)
sharedViewModel.allBuys.observe(this, Observer<List<Buy>> { buys ->
buy = buys[position]
binding.buy = buy
binding.executePendingBindings()
agentNumber = buy.agentNumber
// set animation duration via code, but preferable in your layout files by using the animation_duration attribute
expandableTextView.setAnimationDuration(750L)
// set interpolators for both expanding and collapsing animations
expandableTextView.setInterpolator(OvershootInterpolator())
// or set them separately.
expandableTextView.expandInterpolator = OvershootInterpolator()
expandableTextView.collapseInterpolator = OvershootInterpolator()
// toggle the ExpandableTextView
buttonToggle.setOnClickListener {
buttonToggle.setText(if (expandableTextView.isExpanded) com.example.drake.kunuk.R.string.more else com.example.drake.kunuk.R.string.less)
expandableTextView.toggle()
}
// but, you can also do the checks yourself
buttonToggle.setOnClickListener {
if (expandableTextView.isExpanded) {
expandableTextView.collapse()
buttonToggle.setText(com.example.drake.kunuk.R.string.more)
} else {
expandableTextView.expand()
buttonToggle.setText(com.example.drake.kunuk.R.string.less)
}
}
//Open photoView activity when clicked
ivHouseDetail.setOnClickListener {
applicationContext
.startActivity(
Intent(
applicationContext,
ViewPagerActivity::class.java
)
.putExtra("imageList", buy.propertyImage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
})
findViewById<BottomNavigationView>(R.id.bnvContactAgent)?.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.action_call -> {
Log.e("BIRJU", "Action call")
val callNumberUri = Uri.parse("tel:$agentNumber")
val callIntent = Intent(Intent.ACTION_DIAL, callNumberUri)
startActivity(callIntent)
}
R.id.action_sms -> {
Log.e("BIRJU", "Action SMS")
val smsNumberUri = Uri.parse("sms:$agentNumber")
val smsIntent = Intent(Intent.ACTION_SENDTO, smsNumberUri)
startActivity(smsIntent)
}
R.id.action_email -> {
Log.e("BIRJU", "Action Email")
val uriText = "mailto:drakecolin#gmail.com" +
"?subject=" + Uri.encode("I'm interested in $agentNumber") +
"&body=" + Uri.encode("Hello, ")
val uri = Uri.parse(uriText)
val sendIntent = Intent(Intent.ACTION_SENDTO)
sendIntent.data = uri
startActivity(Intent.createChooser(sendIntent, "Send email"))
}
}
false
}
}
}
How can I pass the variable day by pressing a button to the apiInterface class?
The fragment FragJornadas, from where I want to pass the variable to #Get in Interface?
class FragJornadas : Fragment() {
var jornada = "1"
var dataList = ArrayList<TodasModel>()
lateinit var recyclerView: RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.jornadas_list, container, false)
val miTexto: TextView = view.findViewById(R.id.tv_Jornadas)
miTexto.text = (getString(R.string.num_jornada))
val numJor = intArrayOf(R.id.tv_01, R.id.tv_02, R.id.tv_03, R.id.tv_04, R.id.tv_05,
R.id.tv_06, R.id.tv_07, R.id.tv_08, R.id.tv_09, R.id.tv_10, R.id.tv_11, R.id.tv_12,
R.id.tv_13, R.id.tv_14, R.id.tv_15, R.id.tv_16, R.id.tv_17, R.id.tv_18, R.id.tv_19,
R.id.tv_20, R.id.tv_21, R.id.tv_22, R.id.tv_23, R.id.tv_24, R.id.tv_25, R.id.tv_26,
R.id.tv_27, R.id.tv_28, R.id.tv_29, R.id.tv_30)
val button = arrayOfNulls<Button>(numJor.size)
for(i in numJor.indices){
button[i] = view.findViewById(numJor[i]) as Button
val buttonValue = i+1
val buttonText = Integer.toString(buttonValue)
button[i]!!.setOnClickListener {
miTexto.text = getString(R.string.num_jornada) + " " + buttonText
jornada = buttonText
getData(jornada)
}
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val progressBar: ProgressBar = this.progressBar1
recyclerView = view.findViewById(R.id.recycler_view)
recyclerView.adapter= TodasAdapter(dataList,activity!!)
recyclerView.layoutManager=LinearLayoutManager(activity!!,LinearLayoutManager.VERTICAL,false)
Thread(Runnable {
activity!!.runOnUiThread {
progressBar.visibility = View.VISIBLE
}
try {
var i = 0
while(i < Int.MAX_VALUE){
i++
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
activity!!.runOnUiThread {
progressBar.visibility = View.GONE
}
}).start()
getData(jornada)
}
private fun getData(jornada: String) {
val call: Call<List<TodasModel>> = ApiFederacion.getClient.getTodasJuvenil(jornada)
call.enqueue(object : Callback<List<TodasModel>> {
override fun onResponse(call: Call<List<TodasModel>>?, response: Response<List<TodasModel>>?) {
dataList.addAll(response!!.body()!!)
recyclerView.adapter!!.notifyDataSetChanged()
}
override fun onFailure(call: Call<List<TodasModel>>?, t: Throwable?) {
//progerssProgressDialog.dismiss()
}
})
}
TodasAdapter
class TodasAdapter(private var actList: List<TodasModel>, private val context: Context) : RecyclerView.Adapter<TodasAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.actual_row, parent, false))
}
override fun getItemCount(): Int {
return actList.size
}
#SuppressLint("SetTextI18n", "SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val dataModel= actList.get(position)
holder.itemView.setOnClickListener(){
Toast.makeText(context, dataModel.nomLocal, Toast.LENGTH_LONG).show()
}
val parser = SimpleDateFormat("dd/MM/yyyy") //Formato de fecha obtenida
val formatter = SimpleDateFormat("EE dd 'de' MMMM 'del 'yyyy \n" + "' a las '") //Formato a mostrar
val output = formatter.format(parser.parse(dataModel.fecha + "/2019"))
holder.tv_Fecha.text = output + dataModel.hora
//holder.tv_Fecha.text = dataModel.fecha + "\n" + dataModel.hora
holder.tv_NomLocal.text = dataModel.nomLocal
holder.tv_ResultadoL.text = dataModel.resulLocal
holder.tv_Estado.text = " - " + dataModel.estadoPartido + " - "
holder.tv_ResultadoV.text = dataModel.resulVisitante
holder.tv_NomVisitante.text = dataModel.nomVisitante
Picasso.get()
.load("https://ffcv.es/ncompeticiones/" + dataModel.escudoLocal)
.fit()
//.resize(150, 150)
.into(holder.imageEscLocal)
Picasso.get()
.load("https://ffcv.es/ncompeticiones/" + dataModel.escudoVisitante)
.fit()
.into(holder.imageEscVisi)
}
class ViewHolder(itemLayoutView: View) : RecyclerView.ViewHolder(itemLayoutView) {
var tv_Fecha:TextView
var tv_NomLocal:TextView
var tv_ResultadoL:TextView
var tv_Estado:TextView
var tv_ResultadoV:TextView
var tv_NomVisitante:TextView
var imageEscLocal: ImageView
var imageEscVisi: ImageView
init {
tv_Fecha = itemLayoutView.findViewById(R.id.tv_Fecha)
tv_NomLocal = itemLayoutView.findViewById(R.id.tv_Equipo_Local)
tv_ResultadoL = itemLayoutView.findViewById(R.id.tv_Result_Local)
tv_Estado = itemLayoutView.findViewById(R.id.tv_Estado)
tv_ResultadoV = itemLayoutView.findViewById(R.id.tv_Result_Visitante)
tv_NomVisitante = itemLayoutView.findViewById(R.id.tv_Equipo_Visitante)
imageEscLocal = itemLayoutView.findViewById(R.id.iv_Local) as ImageView
imageEscVisi = itemLayoutView.findViewById(R.id.iv_Visi) as ImageView
}
}
}
And the ApiInterface class to receive it. Being the url I want to get is:
#GET("server.php?action=getResultados&cmp=328{jor}tmp=2018/2019") fun
getTodasJuvenil(
#Path("jor") jornada: String ): Call<List<TodasModel>>
The url I want to get is:
"server.php?action=getResultados&cmp=328&jor=1&tmp=2018/2019"
this is the error:
java.lang.IllegalArgumentException: URL query string
"action=getResultados&cmp=328{jor}&tmp=2018/2019" must not have
replace block. For dynamic query parameters
at com.myapplication.Jornadas.FragJornadas.getData(FragJornadas.kt:91)
at
com.myapplication.Jornadas.FragJornadas.onViewCreated(FragJornadas.kt:87)
Using #Path you're telling retrofit to replace that variable in the path of the url, but you want in the query string. The path is the bit after the domain and before the query string - in your case would be server.php and maybe some bits that come before, which I can't say without seeing the full url.
To add a parameter to the query string you want to use #Query and you don't want to specify it in the query string in the #GET annotation. So you could change things to:
#GET("server.php?action=getResultados&cmp=328&tmp=2018/2019") fun
getTodasJuvenil(
#Query("jor") jornada: String ): Call<List<TodasModel>>)
You've removed {jor} from the query string and replaced #Path with #Query.
Now, retrofit should add a query parameter with the desired jornada.
#Fred thanks for your answers, my mistake was not the previous one, I was not deleting the list, it was added at the end, the solution is:
dataList.clear()
override fun onResponse(call: Call<List<TodasModel>>?, response: Response<List<TodasModel>>?) {
dataList.clear()
dataList.addAll(response!!.body()!!)
recyclerView.adapter!!.notifyDataSetChanged()
}
How can i reference the SongName variable in my other object? I am building my first app with Kotlin so I am really beginner.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
SpotifyService.connect(this) {
spotifyAppRemote?.let {
it.playerApi.subscribeToPlayerState().setEventCallback {
val track: Track = it.track
Log.d("MainActivity", track.name + " by " + track.artist.name)
ALabel.text = track.name
Blabel.text = track.artist.name
var SongName = track.name
var SongArtist = track.artist.name
}
}
}
GeniusApi.PrintSomething()
}
}``` ```object GeniusApi {
val BASE_URL = "https://api.genius.com"
val SEARCH_URL = BASE_URL + "/search"
var DATA = SongName#MainActivity
fun PrintSomething() {
Log.e("GeniusApi", DATA)
}
}```
On your Kotlin file you will need to place any functions or variables inside a
Companion Object {
lateinit var myobject
}
And then reference it like
TheObject.Companion.myobject