Trying basic MVVM implementation based on https://github.com/mitchtabian/MVVMExample1

This commit is contained in:
Daniele 2021-09-19 09:51:54 +02:00
parent b9dbde7f7c
commit cf7f96efad
6 changed files with 128 additions and 170 deletions

View File

@ -82,17 +82,6 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
return geofavoriteListFiltered.get(position);
}
public void removeById(int id) {
for (Geofavorite g : geofavoriteList) {
if (g.getId() == id) {
geofavoriteList.remove(g);
geofavoriteListFiltered.remove(g);
break;
}
}
notifyDataSetChanged();
}
public int getSortRule() {
return sortRule;
}

View File

@ -25,6 +25,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatImageButton;
@ -35,6 +36,7 @@ import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
@ -61,8 +63,9 @@ import static android.view.View.VISIBLE;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.*;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_CREATED;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_TITLE;
import androidx.lifecycle.Observer;
public class MainActivity extends AppCompatActivity implements MainView, OnSortingOrderListener {
public class MainActivity extends AppCompatActivity implements OnSortingOrderListener {
private static final int INTENT_ADD = 100;
private static final int INTENT_EDIT = 200;
@ -84,9 +87,9 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
private StaggeredGridLayoutManager layoutManager;
private FloatingActionButton fab;
private MainPresenter presenter;
private GeofavoriteAdapter geofavoriteAdapter;
private ItemClickListener rvItemClickListener;
private MainActivityViewModel mMainActivityViewModel;
NavigationAdapter navigationCommonAdapter;
@ -95,6 +98,8 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
mMainActivityViewModel.init();
preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
int sortRule = preferences.getInt(getString(R.string.setting_sort_by), SORT_BY_CREATED);
@ -104,8 +109,6 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
layoutManager = new StaggeredGridLayoutManager(gridViewEnabled ? 2 : 1, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
presenter = new MainPresenter(this);
rvItemClickListener = new ItemClickListener() {
@Override
public void onItemClick(Geofavorite item) {
@ -133,7 +136,7 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
geofavoriteAdapter.setSortRule(sortRule);
swipeRefresh = findViewById(R.id.swipe_refresh);
swipeRefresh.setOnRefreshListener(() -> presenter.getGeofavorites());
swipeRefresh.setOnRefreshListener(() -> updateGeofavorites());
fab = findViewById(R.id.add);
fab.setOnClickListener(view -> addGeofavorite());
@ -190,7 +193,7 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
super.onStart();
// Update list
presenter.getGeofavorites();
mMainActivityViewModel.getGeofavorites().observe(this, this);
}
private void setupNavigationMenu() {
@ -239,9 +242,9 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == INTENT_ADD && resultCode == RESULT_OK) {
presenter.getGeofavorites();
mMainActivityViewModel.getGeofavorites().observe(this, this);
} else if (requestCode == INTENT_EDIT && resultCode == RESULT_OK) {
presenter.getGeofavorites();
mMainActivityViewModel.getGeofavorites().observe(this, this);
}
}
@ -260,35 +263,12 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
startActivity(intent);
}
@Override
public void showLoading() {
swipeRefresh.setRefreshing(true);
}
@Override
public void hideLoading() {
swipeRefresh.setRefreshing(false);
}
@Override
public void onGetResult(List<Geofavorite> geofavorite_list) {
geofavoriteAdapter.setGeofavoriteList(geofavorite_list);
}
@Override
public void onGeofavoriteDeleted(int id) {
// Update list
runOnUiThread(() -> {
geofavoriteAdapter.removeById(id);
Toast.makeText(MainActivity.this, R.string.list_geofavorite_deleted, Toast.LENGTH_LONG).show();
});
}
@Override
public void onErrorLoading(String message) {
Toast.makeText(MainActivity.this, R.string.list_geofavorite_connection_error, Toast.LENGTH_LONG).show();
Log.e(TAG, "Unable to obtain geofavorites list: " + message);
}
// @Override
// public void onErrorLoading(String message) {
// Toast.makeText(MainActivity.this, R.string.list_geofavorite_connection_error, Toast.LENGTH_LONG).show();
// Log.e(TAG, "Unable to obtain geofavorites list: " + message);
// }
@Override
public void onSortingOrderChosen(int sortSelection) {
@ -328,7 +308,7 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
.setTitle(R.string.dialog_delete_title)
.setPositiveButton(R.string.dialog_delete_delete, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
presenter.deleteGeofavorite(item.getId());
// TODO presenter.deleteGeofavorite(item.getId());
dialog.dismiss();
// Callback is onGeofavoriteDeleted
}
@ -348,4 +328,26 @@ public class MainActivity extends AppCompatActivity implements MainView, OnSorti
startActivity(i);
}
private void updateGeofavorites() {
mMainActivityViewModel.getGeofavorites().observe(this, new Observer<List<Geofavorite>>() {
@Override
public void onChanged(List<Geofavorite> geofavorites) {
geofavoriteAdapter.setGeofavoriteList(geofavorites);
}
});
// TODO: è possibile registrare un solo listener?
mMainActivityViewModel.getIsUpdating().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean aBoolean) {
if(aBoolean){
swipeRefresh.setRefreshing(true);
}
else{
swipeRefresh.setRefreshing(false);
}
}
});
}
}

View File

@ -0,0 +1,33 @@
package it.danieleverducci.nextcloudmaps.activity.main;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import java.util.List;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.repository.GeofavoriteRepository;
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<List<Geofavorite>> mGeofavorites;
private GeofavoriteRepository mRepo;
private MutableLiveData<Boolean> mIsUpdating = new MutableLiveData<>();
public void init() {
if (mGeofavorites != null)
return;
mRepo = GeofavoriteRepository.getInstance();
mGeofavorites = mRepo.getGeofavorites();
}
public LiveData<List<Geofavorite>> getGeofavorites(){
return mGeofavorites;
}
public LiveData<Boolean> getIsUpdating(){
return mIsUpdating;
}
}

View File

@ -1,89 +0,0 @@
/*
* Nextcloud Maps Geofavorites for Android
*
* @copyright Copyright (c) 2020 John Doe <john@doe.com>
* @author John Doe <john@doe.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package it.danieleverducci.nextcloudmaps.activity.main;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;
import it.danieleverducci.nextcloudmaps.api.ApiProvider;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainPresenter {
private MainView view;
public MainPresenter(MainView view) {
this.view = view;
}
public void getGeofavorites() {
view.showLoading();
Call<List<Geofavorite>> call = ApiProvider.getAPI().getGeofavorites();
call.enqueue(new Callback<List<Geofavorite>>() {
@Override
public void onResponse(@NonNull Call<List<Geofavorite>> call, @NonNull Response<List<Geofavorite>> response) {
((AppCompatActivity) view).runOnUiThread(() -> {
view.hideLoading();
if (response.isSuccessful() && response.body() != null) {
view.onGetResult(response.body());
} else {
((AppCompatActivity) view).runOnUiThread(() -> {
view.hideLoading();
view.onErrorLoading(response.raw().message());
});
}
});
}
@Override
public void onFailure(@NonNull Call<List<Geofavorite>> call, @NonNull Throwable t) {
((AppCompatActivity) view).runOnUiThread(() -> {
view.hideLoading();
view.onErrorLoading(t.getLocalizedMessage());
});
}
});
}
public void deleteGeofavorite(int id) {
view.showLoading();
Call<Geofavorite> call = ApiProvider.getAPI().deleteGeofavorite(id);
call.enqueue(new Callback<Geofavorite>() {
@Override
public void onResponse(Call<Geofavorite> call, Response<Geofavorite> response) {
view.hideLoading();
view.onGeofavoriteDeleted(id);
}
@Override
public void onFailure(Call<Geofavorite> call, Throwable t) {
view.hideLoading();
view.onErrorLoading(t.getLocalizedMessage());
}
});
}
}

View File

@ -1,33 +0,0 @@
/*
* Nextcloud Maps Geofavorites for Android
*
* @copyright Copyright (c) 2020 John Doe <john@doe.com>
* @author John Doe <john@doe.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package it.danieleverducci.nextcloudmaps.activity.main;
import java.util.List;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public interface MainView {
void showLoading();
void hideLoading();
void onGetResult(List<Geofavorite> geofavorites);
void onGeofavoriteDeleted(int id);
void onErrorLoading(String message);
}

View File

@ -0,0 +1,56 @@
package it.danieleverducci.nextcloudmaps.repository;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.MutableLiveData;
import java.util.ArrayList;
import java.util.List;
import it.danieleverducci.nextcloudmaps.api.ApiProvider;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Singleton pattern
*/
public class GeofavoriteRepository {
private static GeofavoriteRepository instance;
private ArrayList<Geofavorite> dataSet = new ArrayList<>();
public static GeofavoriteRepository getInstance() {
if(instance == null){
instance = new GeofavoriteRepository();
}
return instance;
}
public MutableLiveData<List<Geofavorite>> getGeofavorites(){
// Obtain geofavorites
Call<List<Geofavorite>> call = ApiProvider.getAPI().getGeofavorites();
call.enqueue(new Callback<List<Geofavorite>>() {
@Override
public void onResponse(@NonNull Call<List<Geofavorite>> call, @NonNull Response<List<Geofavorite>> response) {
if (response.isSuccessful() && response.body() != null) {
dataSet.addAll(response.body());
} else {
onFailure(call, new Throwable("Dataset is empty"));
}
}
@Override
public void onFailure(@NonNull Call<List<Geofavorite>> call, @NonNull Throwable t) {
// TODO
}
});
MutableLiveData<List<Geofavorite>> data = new MutableLiveData<>();
data.setValue(dataSet);
return data;
}
}