class FirebaseHelper {
companion object {
private var mAuth: FirebaseAuth? = null
fun getInstance(): FirebaseAuth? {
if(mAuth == null ){
mAuth == FirebaseAuth.getInstance()
}
return mAuth;
}
fun getCurrentUser(): FirebaseUser?{
return getInstance()?.currentUser
}
}
}
Here FirebaseAuth.getInstance() always return null and I don't get why. If I use it on an activity like
mAuth = FirebaseAuth.getInstance()
it return the firebase instance. I don't get what is the difference. I tried to not make the FirebaseHelper.getInstance() method static, but it also didn't work.
Any hints?
class FirebaseHelper {
companion object {
private var mAuth: FirebaseAuth? = null
fun getInstance(): FirebaseAuth? {
if(mAuth == null ){
// here you should use "=" instead of "=="
mAuth == FirebaseAuth.getInstance()
}
return mAuth;
}
fun getCurrentUser(): FirebaseUser?{
return getInstance()?.currentUser
}
}
}
Related
I'm working on a Xamarin forms app using Prism. I'm trying to manipulate(Sort, filter, etc..) and display grouped data using Dynamic data. I'm following this
https://www.xamboy.com/2021/01/20/using-dynamic-data-in-xamarin-forms-part-1/
My issue is that my Readonlyobservablecollection _getUsers is not getting populated please see below:
private SourceCache<User, string> _sourceCache = new SourceCache<User, string>(x =>x.Id);
private ReadOnlyObservableCollection<ObservableGroupedCollection<string,User, string>> _getUsers;
public ReadOnlyObservableCollection<ObservableGroupedCollection<string, User, string>> GetUser { get; set; }
public string Gender { get { return _gender; } set { SetProperty(ref _gender, value); OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(Gender))); } }
private string _gender;
private async Task GetUsers()
{
try
{
var users = await _apiService.GetUsers();
_sourceCache.AddOrUpdate(users);
Func<User, bool> searchFilter(string text) => user =>
{
return string.IsNullOrWhiteSpace(text) || user.PhoneNumber.ToLower().Contains(text.ToLower()) || user.UserName.ToLower().Contains(text.ToLower()) || user.Name.ToLower().Contains(text.ToLower());
};
Func<User, bool> genderFilter(string gender) => user =>
{
return gender == "All" || user.Gender == gender;
};
Func<User, bool> statusFilter(string status) => user =>
{
if(status == "Live")
{
return user.Active == true;
}
if (status == "Suspended")
{
return user.Active == false;
}
return status == "None" || user.Payment.StatusMessage.Replace(" ","") == status;
};
var genderPredicate = this.WhenAnyValue(x => x.Gender)
.Select(genderFilter);
var filterPredicate = this.WhenAnyValue(x => x.SearchText)
.Select(searchFilter);
var statusPredicate = this.WhenAnyValue(x => x.Status)
.Select(statusFilter);
var sortPredicate = this.WhenAnyValue(x => x.SortBy)
.Select(x => SortExpressionComparer<User>.Ascending(a => a.Name));
_cleanUp = _sourceCache.Connect()
.Filter(genderPredicate)
.Group(x => x.Race)
.Transform(g => new ObservableGroupedCollection<string, User, string>(g, genderPredicate, sortPredicate))
.Bind(out _getUsers)
.DisposeMany()
.Subscribe();
Gender = "All";
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(Gender)));
}
catch (Refit.ApiException ex)
{
if(ex.StatusCode != System.Net.HttpStatusCode.NotFound)
{
await HandleExceptionAsync(ex);
}
}
catch (Exception ex)
{
await HandleExceptionAsync(ex);
}
}
The generic class
public class ObservableGroupedCollection<TGroupKey, TObject, TKey> : ObservableCollectionExtended<TObject>, IDisposable
{
public TGroupKey Key { get; }
public ObservableGroupedCollection(IGroup<TObject, TKey, TGroupKey> group, IObservable<Func<TObject, bool>> filter, IObservable<IComparer<TObject>> comparer)
{
this.Key = group.Key;
//load and sort the grouped list
var dataLoader = group.Cache.Connect()
.Filter(filter)
.Sort(comparer)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(this) //make the reset threshold large because xamarin is slow when reset is called (or at least I think it is #erlend, please enlighten me )
.Subscribe();
_cleanUp = new CompositeDisposable(dataLoader);
}
public void Dispose()
{
_cleanUp.Dispose();
}
private readonly IDisposable _cleanUp;
}
I'm really struggling with this. Please if anyone can help, I'd really appreciate it.
You can use this to populate _getUsers.
public ReadOnlyObservableCollection<ObservableGroupedCollection<string, User, string>> GetUser {
get
{
return _getUsers;
}
set
{
if (_getUsers != value)
{
_getUsers = value;
OnPropertyChanged(nameof(GetUser));
}
}
}
I'm using retrofit to login to my API, but if, for example, I insert a wrong password and try to login again, the service is not called again.
It seems that the second call gets "stuck" in the repository, never reaches the service.
This is my first android app and i'm struggling with this situation.
Tks in advance for any help you can provide on this.
This is the code for my app.
DI
class Fiscalizacao : Application(), KodeinAware {
override val kodein = Kodein.lazy {
import(androidModule(this#Fiscalizacao))
bind() from singleton {
Autenticacao(
instance()
)
}
bind<IAutenticacaoDataSource>() with singleton {
AutenticacaoDataSourceImpl(
instance()
)
}
bind<IAuthenticationRepository>() with singleton {
AuthenticationRepositoryImpl(
instance()
)
}
bind() from provider { AutenticacaoViewModelFactory(instance(), instance()) }
}
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
Service
interface Autenticacao {
#POST("auth")
fun authAsync(#Body user: RequestBody): Deferred<AutenticacaoResponseResource>
companion object {
operator fun invoke(connectivityInterceptor: IConnectivityInterceptor): Autenticacao {
val okHttpClient = OkHttpClient.Builder()
.build()
return Retrofit
.Builder()
.client(okHttpClient)
.baseUrl("http://10.110.100.216/identity/")
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Autenticacao::class.java)
}
}
}
DataSource
class AutenticacaoDataSourceImpl(
private val autenticacao: Autenticacao
) :
IAutenticacaoDataSource {
private val _authResponse = MutableLiveData<AutenticacaoResponseResource>()
override val authResponse: LiveData<AutenticacaoResponseResource>
get() = _authResponse
override suspend fun auth(user: CredentialsResource?): LiveData<AutenticacaoResponseResource> {
try {
val userJsonObject = JsonObject()
userJsonObject.addProperty(Parameters.USERNAME.value, user?.utilizador)
userJsonObject.addProperty(Parameters.PASSWORD.value, user?.password)
val result = autenticacao
.authAsync(
userJsonObject.toString()
.toRequestBody(contentType = "application/json; charset=utf8".toMediaTypeOrNull())
)
.await()
_authResponse.postValue(result)
} catch (e: Exception) {
Log.e(e.cause.toString(), e.message, e)
}
return authResponse
}
}
Repository
class AuthenticationRepositoryImpl(
private val autenticacaoDataSource: IAutenticacaoDataSource
) : IAuthenticationRepository {
override suspend fun auth(user: CredentialsResource?): LiveData<AutenticacaoResponseResource> {
return withContext(Dispatchers.IO) {
return#withContext autenticacaoDataSource.auth(user)
}
}
}
ViewModel
class AutenticacaoViewModel(
private val authenticationRepository: IAuthenticationRepository,
) : ViewModel() {
lateinit var user:CredentialsResource
val login by lazyDeferred {
authenticationRepository.auth(user)
}
}
View Model Factory
class AutenticacaoViewModelFactory(private val authenticationRepository: IAuthenticationRepository, ) :
ViewModelProvider.NewInstanceFactory() {
#Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return AutenticacaoViewModel(authenticationRepository) as T
}
}
Coroutines
fun <T> lazyDeferred(block: suspend CoroutineScope.() -> T): Lazy<Deferred<T>>{
return lazy {
GlobalScope.async(start = CoroutineStart.LAZY) {
block.invoke(this)
}
}
}
class AutenticacaoFragment : ScopedFragment(), KodeinAware {
override val kodein by closestKodein()
private val authViewModelFactory: AutenticacaoViewModelFactory by instance()
private lateinit var viewModel: AutenticacaoViewModel
val gson = Gson()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding: AutenticacaoFragmentBinding =
DataBindingUtil.inflate(inflater, R.layout.autenticacao_fragment, container, false)
binding.model =
AppGlobalObject
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this, authViewModelFactory)
.get(AutenticacaoViewModel::class.java)
mAutenticacao.setOnClickListener(listenerService)
}
private val listenerService =
View.OnClickListener {
when (it.id) {
R.id.mAutenticacao -> {
login(this.requireContext())
}
}
}
private fun login(context: Context) = launch {
viewModel.user = gson.fromJson(
gson.toJson(AppGlobalObject.autenticacao.user),
CredentialsResource::class.java
)
val result = viewModel.login.await()
result.observe(viewLifecycleOwner, Observer { response ->
if (response == null) return#Observer
val login = Utilities().validateStatusCodeOK(response.error)
when {
login -> {
Utilities().setLoginStatus(login, context)
}
else -> {
mPassword.error = "Erro no Login"
}
}
})
}
I have a number of controllers of this form:
public IActionResult GetSomething(int id, DateTime from) {
...
}
The id and from parameters are given on the query as query parameters. If id is not supplied, the ModelValid state is set to false. But if from is not supplied, ModelValid is true and from is set to 1900-01-01 00:00:00 (DateTime.Min).
How do I make ModelState false if a wanted DateTime parameter isn't supplied?
I decided to go for implementing a DateTime model binder. The following code will not set IsValid=true on ModelState if the DateTime argument is missing. DateTime? (nullable DateTime) is handled fine, but again, if the query parameter is missing, IsValid is set to false instead of setting the parameter to a default value.
First the DateTimeModelBinderProvider:
public class DateTimeModelBinderProvider : IModelBinderProvider
{
/// <inheritdoc />
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.Metadata.IsComplexType)
{
// We can handle DateTime and nullable DateTime
if ((context.Metadata.ModelType == typeof(DateTime)) ||
(context.Metadata.IsNullableValueType && context.Metadata.UnderlyingOrModelType == typeof(DateTime)))
return new DateTimeModelBinder(context.Metadata.ModelType);
}
return null;
}
}
Next the DateTimeModelBinder. Most of the code is copied verbatim from github. Some of it could be left out, but it works as it is:
public class DateTimeModelBinder : IModelBinder
{
private readonly TypeConverter _typeConverter;
public DateTimeModelBinder(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
_typeConverter = TypeDescriptor.GetConverter(type);
}
/// <inheritdoc />
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
{
// Do not accept an empty value provider result as being ok for DateTime (is ok for DateTime?)
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
// no entry
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
try
{
var value = valueProviderResult.FirstValue;
object model = null;
if (!string.IsNullOrWhiteSpace(value))
{
model = new DateTimeConverter().ConvertFrom(
context: null,
culture: valueProviderResult.Culture,
value: value);
}
if (bindingContext.ModelType == typeof(string))
{
var modelAsString = model as string;
if (bindingContext.ModelMetadata.ConvertEmptyStringToNull &&
string.IsNullOrEmpty(modelAsString))
{
model = null;
}
}
// When converting newModel a null value may indicate a failed conversion for an otherwise required
// model (can't set a ValueType to null). This detects if a null model value is acceptable given the
// current bindingContext. If not, an error is logged.
if (model == null && !bindingContext.ModelMetadata.IsReferenceOrNullableType)
{
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
return Task.CompletedTask;
}
else
{
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
catch (Exception exception)
{
var isFormatException = exception is FormatException;
if (!isFormatException && exception.InnerException != null)
{
// TypeConverter throws System.Exception wrapping the FormatException,
// so we capture the inner exception.
exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException;
}
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
exception,
bindingContext.ModelMetadata);
// Were able to find a converter for the type but conversion failed.
return Task.CompletedTask;
}
}
}
Also remember to activate it. I insert it at the start of the provider list to ensure my DateTime provider is used in preference of the default handler:
var mvc = services.AddMvc(config => {
config.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
});
You can solve this issue by creating a model that has a validation attribute for the 'From' property.
I havent tested out the code. But code should be like:
public class Model
{
public int Id { get; set; }
[DateTimeShouldHaveValue]
public DateTime From { get; set; }
}
public class DateTimeShouldHaveValueAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return false;
var dateTimeTmp = value.ToString();
DateTime dateTime;
DateTime.TryParse(dateTimeTmp, out dateTime);
if (dateTime == DateTime.MinValue)
return false;
return true;
}
}
public IActionResult GetSomething(Model model)
{
}
I got the following function
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
return result.put(new MyClass("someString"), "someOtherString"));
}
The implementation of MyClass looks like the following:
public class MyClass{
String string;
public MyClass(String string) {
this.string = string;
}
public void setString(String string) {
this.string = string;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((string== null) ? 0 : string.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
if (string== null) {
if (other.string!= null) {
return false;
}
} else if (!string.equals(other.string)) {
return false;
}
return true;
}
}
In my test I am doing the following:
#Test
public void test() {
Map<MyClass, String> outcome = classUnderTest.someFunction();
assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
}
But this test fails, because actual is null.
If I try the following:
assertThat(outcome.keySet(), hasItem(MY_CLASS));
this also fails, telling me, that these are different intantiations. I even tried to debug my test, but it never reaches the equals method. Can you tell me what is happening here?
Are you sure, that your method doesn't modify the objecT? I think, that someFunction replaces the string in MyClass. That causes that your object of MyClass return another hashCode.
A HashMap works like that:
put:
compute hashCode of the key. Store value under that hashCode
get:
compute hashCode of the key. Search for a value with that hashCode. If there is a value, then maybe call equals.
So: never use mutable values as key! Otherwise, you may lose your data (or make it difficult to resolve)
Just try to execute this test, it should be green
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class SomeTest {
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
result.put(new MyClass("someString"), "someOtherString");
return result;
}
#Test
public void test() {
Map<MyClass, String> outcome = someFunction();
assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
}
public static class MyClass {
String string;
public MyClass(String string) {
this.string = string;
}
public void setString(String string) {
this.string = string;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((string == null) ? 0 : string.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
if (string == null) {
if (other.string != null) {
return false;
}
} else if (!string.equals(other.string)) {
return false;
}
return true;
}
}
}
but if you modify MyClass object after it was added to Map, the test became red:
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
MyClass key = new MyClass("someOldString");
result.put(key, "someOtherString");
key.setString("someString");
return result;
}
In your function you are returning null
From the JavaDoc for HashMap:
public V put(K key, V value)
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
Specified by:
put in interface Map<K,V>
Overrides:
put in class AbstractMap<K,V>
Parameters:
key - key with which the specified value is to be associated
value - value to be associated with the specified key
Returns:
the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
put() returns what used to be there, not what you just put there
I am using .Net 4.5 and Entity Framework 6 to create a REST Web API.
In my Update methods I need to attach the object recieved in the web api, back to the dbcontext. I have achieved this using the code below. What I want to do now, is to make this code reusable so that I can call AttachToContext for any object in the model.
I understand that I have to use generic type T and TEntity, but I cannot find any suitable examples.
//Repository.cs
public void UpdateOrderItem(OrderItem orderItem)
{
try
{
AttachToContext(orderItem);
_context.SaveChanges();
}
catch (Exception e)
{
}
}
private void AttachToContext(OrderItem orderItem)
{
var entry = _context.Entry<OrderItem>(orderItem);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity(orderItem.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, orderItem);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private OrderItem FindExistingEntity(int id)
{
var set = _context.Set<OrderItem>();
return set.Find(id);
}
private void UpdateEntityValues(OrderItem existing, OrderItem updated)
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
private bool EntityExists(object entity)
{
return entity != null;
}
Your AttachToContext has dependency to primary key property, orderItem.Id, to change it into dynamic, you can introduce an interface and implement to all entities you have or just passing the id as parameters.
Interface
public interface IEntity
{
public int Id { get; set; }
}
public class OrderItem : IEntity
{
// body
}
Then modify the AttachToContext as follow.
private void AttachToContext<T>(T entity) where T : class, IEntity
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(entity.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(int id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem);.
Passing The Keys
private void AttachToContext<T>(T entity, params object[] id) where T : class
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(object[] id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem, orderItem.Id);.
Another alternative would be using object set to get the primary key properties, then using reflection to get the value. To get the primary key properties has been explained in this post.