kotlin- change decimal places on multiple fragments from one fragment - android

for my app i read in multiple values from Bluetooth connected sensors. One fragment allows you to edit the sensors and another fragment shows all values in a tableView.
On a third settings fragment, i want to be able to change the decimal places the values on all fragments appear.
i know to change the decimal format i use the following code.
var form = DecimalFormat("#,###.##") // number format
and to add this format to the values do the following
form.format(temperature)
currently i have a radio group, with each radio button set to change the how many decimal places in the variable form.
how do i make this change appear across all fragments not just the setting fragments? will i need a shared view model?

Shared ViewModel is good fit for this problem, simply create a ViewModel with form property and in every fragment get an instance of ViewModel associated with activity as
private val viewModel: SharedViewModel by activityViewModels()
Now you can update the form property on radio change as
radioGroup.setOnCheckedChangeListener { group, checkedId ->
val format = when(checkedId){
R.id.radio_two -> TWO_DECIMAL_PLACES
R.id.radio_three -> THREE_DECIMAL_PLACES
else -> DEFAULT_FORMAT
}
viewModel.form = DecimalFormat(format)
}
After this simply use value of this property before showing data

Related

How to assign a class type to arraylist of type Any?

I have lateinit arraylist of type Any in service. The scenario I've is that lists of three different types are coming from three different fragments. I have to assign it a type of my choice based on intent. How can I do the same? or how can I meet my required scenario which is how to assign different types to a same arraylist based on type of list received
You mean something like (if all items are the same within a list)
if(list[0] is Subtype1)
val specificList = list.map{item -> item as Subtype1}
specificList should then have type List<Subtype1>
I didn't test this and you need to handle edge cases like empty lists, maybe try/catch for the map etc but this should be a start. you can also use a when instead of if, if you need to switch between multiple types

How can I have 2 different fragment, implementing same methods without writing the code twice?

I have a fragment screen where there is a form that is used to create Questions and Answers for my app. For this fragment, I use data binding, then I created many functions to validate the form, and check other stuffs.
Now, I'm creating a different fragment screen, where I'll be able to edit this Questions and Answers that were created, and for this, I want to use the same functions that were used when I created on the other fragment, for example to validate the fields that the user is editing.
I thought about implementing an Interface, and put these common functions there, so I could use it on both fragments. However, in these functions I use DataBinding, and I don't know how I can use it on the interface, so it would get the correct XML variables regarding to one fragment, or the other one.
On the screenshot bellow, it shows that I'm trying to use the binding, however I can't specify which one I'm using, otherwise the code will work only for a fragment, and not for both. Consequently, I tried to declare as DataBindingUtil but it didn't work.
Screenshot interface
If you want to go with this approach you could add the views as fields in the interface:
interface IQuestionForm {
var newQuestionTextInput: EditText
var answer1TextField: EditText
fun validateAllParametersToCreateNewQuestion(){
var allTextInputSet = true
if (newQuestionTextInput.text.isNullOrEmpty()){
newQuestionTextInput.error = "You have to enter the question"
allTextInputSet = false
}
if (answer1TextField.text.isNullOrEmpty()){
answer1TextField.error = "You have to enter an answer"
allTextInputSet = false
}
....
}
}
Then initialise those fields after creating the binding in the fragment.

How to Enable/Disable a button based on all editetext is not empty using viewmodel and databinding in kotlin android

I need to create a Login Activity in an Android app using Data Binding with ViewModel using Kotlin. I want to enable/disable a Button based on the content of an EditText field. The expected behavior that I'm trying to achieve is the button should get enabled only when none of theEditText fields is empty.
Step 1: In ViewModel declare
var isEnabled : ObservableBoolean? = null and initialize it in init block.
Step 2: Set value of isEnabled in your Text Change Listener like
isEnabled?.set(!isLoginFormValid())
Step 3: bind variable in xml file like
android:enabled="#{viewmodel.isEnabled}"
Add a boolean MediatorLiveData in your ViewModel and bind this to the enabled attribute of the button.
You should have MutableLiveData fields that's two-way bound to your EditTexts. Add these as MutableLiveData as sources to the boolean MediatorLiveData so that it can observe changes to the EditTexts as user enters values.
Add whatever logic in the MediatorLiveData observers to set it's value to true/false depending on whatever logic you want (e.g. values of the EditTexts should not be null or empty)
you can put validations in the on click method of the login button.like:-
if(edittext_one!=null){then do the code here for the onclick }
like this you can put as much validations as you want on the edittext using if else statements.i hope this helps

Android Studio autocomplete wrap object in another object

So is my existing code:
fun getAllPeople(): List<People> {
return peopleDao.getAll()
...
}
and I want to wrap the List<People> in a LiveData object.
When I start typing in the front, autocomplete gives me the suggestion for LiveData here,
but then when I hit enter it completes to this.
I know I can then type < and move to the end and type >.
But isn't there an easy way to wrap something with another object correctly?
You can do this for your current selection with a custom live template:
Go to Settings -> Editor -> Live Templates
Under Android, add a new template (Alt+Insert or the green 'plus' button on the right)
Give an abbreviation and a description to your template
Set the template text to LiveData<$SELECTION$>
Set the applicable contexts to Java and Kotlin
Click Apply
Now when you select your List<People> and use "Surround with Live Template" (Ctrl+Alt+J on Windows/Linux, Cmd+Alt+J on Mac by default), you can choose your custom template from the list and watch as the selected declaration becomes LiveData<List<People>>.
Tip: You can also use the "Extend Selection" shortcut to more easily select the declaration (Ctrl+W on Win/Linux, Alt+Up on Mac by default).

Selection of fragment View depending on selected item ViewModel type

Target MvvmCross, Android
Objective: A screen (ViewModel/View) where the user can select an animal group (Amphibians, Birds, Fish, Invertebrates, Mammals, Reptiles). When a group has been selected, a Fragment Views will will display information for that animal group. The fields and layout differ per animal group (e.g. fish don't have wings).
Although for this question I have chosen for animal group (which is pretty static), want the list animal groups to be flexible.
Simplified app structure:
MyApp.Core
ViewModels
MainViewModel
IAnimalGroupViewModel
AmphibiansViewModel
BirdsBViewModel
FishViewModel
MyApp.Droid
Layout
MainView
AmphibiansFragment
BirdsFragment
FishFragment
Views
MainView
AmphibiansFragment
BirdsFragment
FishFragment
The MainView.axml layout file will contain (a placeholder for) the fragment of the displayed animal group.
In WPF or WP8 app I could make use of a ContentPresenter and a Style to automatically display the selected ViewModel with its View.
How could I achieve something like that in Droid?
I could use a Switch/Case in the MainView.cs that sets the Fragment according to the type of the selected ViewGroup. But that means I have to modify the MainView every time I add a new View.
Any suggestions/ideas?
Currently MvvmCross doesn't provide any kind of automatic navigation mechanism for Fragments in the same way that it does for Activities.
However, within your use case, if you wanted to use a navigation approach, then you could automatically build a similar type of automated lookup/navigation mechanism.
To do this, the easiest developer root would probably be to use reflection to find a lookup dictionary for all the fragments
var fragments = from type in this.GetType().Assembly.GetTypes()
where typeof(IAnimalGroupView)..sAssignableFrom(type)
where type.Name.EndsWith("Fragment")
select type;
var lookup = fragments.ToDictionary(
x => x.Name.Substring(0, x.Name.Length - "Fragment".Length)
+ "ViewModel",
x => x);
With this in place, you could then create the fragments when they are needed - e.g.
assuming that you convert the Selection event via an ICommand on the ViewModel into a ShowViewModel<TViewModel> call
and assuming that you have a Custom Mvx presenter which intercepts these ShowViewModel requests and passes them to the activity (similar to the Fragment sample) - e.g.
public class CustomPresenter
: MvxAndroidViewPresenter
{
// how this gets set/cleared is up to you - possibly from `OnResume`/`OnPause` calls within your activities.
public IAnimalHostActivity AnimalHost { get; set; }
public override void Show(MvxViewModelRequest request)
{
if (AnimalHost != null && AnimalHost.Show(request))
return;
base.Show(request);
}
}
then your activity could implement Show using something like:
if (!lookup.ContainsKey(request.ViewModelType.Name))
return false;
var fragmentType = lookup[request.ViewModelType.Name];
var fragment = (IMvxFragmentView)Activator.Create(fragmentType);
fragment.LoadViewModelFrom(request);
var t = SupportFragmentManager.BeginTransaction();
t.Replace(Resource.Id.my_selected_fragment_holder, fragment);
t.Commit();
return true;
Notes:
if you aren't using ShowViewModel here then obviously this same approach could be adjusted... but this answer had to propose something...
in a larger multipage app, you would probably look to make this IAnimalHostActivity mechanism much more generic and use it in several places.

Categories

Resources