Add folder list, folder update and deletion

This commit is contained in:
Shinokuni 2019-07-14 12:24:19 +02:00
parent b05fbbe080
commit 9097c1d660
14 changed files with 398 additions and 69 deletions

View File

@ -1,8 +1,10 @@
package com.readrops.app.activities;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -10,12 +12,21 @@ import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager.widget.ViewPager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R;
import com.readrops.app.database.entities.Account;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.databinding.ActivityManageFeedsFoldersBinding;
import com.readrops.app.fragments.FeedsFragment;
import com.readrops.app.fragments.FoldersFragment;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableCompletableObserver;
import io.reactivex.schedulers.Schedulers;
public class ManageFeedsFoldersActivity extends AppCompatActivity {
@ -23,6 +34,7 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
private ActivityManageFeedsFoldersBinding binding;
private FeedsFoldersPageAdapter pageAdapter;
private ManageFeedsFoldersViewModel viewModel;
private Account account;
@ -33,12 +45,35 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
binding = DataBindingUtil.setContentView(this, R.layout.activity_manage_feeds_folders);
setSupportActionBar(binding.manageFeedsFoldersToolbar);
binding.manageFeedsFoldersToolbar.setTitleTextColor(Color.WHITE);
binding.manageFeedsFoldersTablayout.setTabTextColors(Color.WHITE, Color.WHITE);
account = getIntent().getParcelableExtra(ACCOUNT);
pageAdapter = new FeedsFoldersPageAdapter(getSupportFragmentManager());
binding.manageFeedsFoldersViewpager.setAdapter(pageAdapter);
binding.manageFeedsFoldersTablayout.setupWithViewPager(binding.manageFeedsFoldersViewpager);
viewModel = ViewModelProviders.of(this).get(ManageFeedsFoldersViewModel.class);
viewModel.setAccount(account);
binding.manageFeedsFoldersViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
binding.manageFeedsFoldersTablayout.getTabAt(position).select();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@ -55,7 +90,7 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
finish();
return true;
case R.id.add_folder:
//addFolder();
addFolder();
return true;
}
return super.onOptionsItemSelected(item);
@ -67,11 +102,36 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
super.onBackPressed();
}
private void addFolder() {
new MaterialDialog.Builder(ManageFeedsFoldersActivity.this)
.title(R.string.add_folder)
.positiveText(R.string.validate)
.input(R.string.folder, 0, (dialog, input) -> {
Folder folder = new Folder(input.toString());
folder.setAccountId(account.getId());
viewModel.addFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
Toast.makeText(getApplicationContext(), "folder inserted", Toast.LENGTH_LONG).show();
}
@Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
});
})
.show();
}
public class FeedsFoldersPageAdapter extends FragmentPagerAdapter {
private FeedsFoldersPageAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
@ -84,14 +144,12 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getApplicationContext().getString(R.string.feeds_and_folders);
return getApplicationContext().getString(R.string.feeds);
case 1:
return getApplicationContext().getString(R.string.folder);
return getApplicationContext().getString(R.string.folders);
default:
return null;
}
}
@Override

View File

@ -5,6 +5,7 @@ import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import com.readrops.app.database.entities.Folder;
@ -25,6 +26,9 @@ public interface FolderDao {
@Insert
long[] insert(List<Folder> folders);
@Update
void update(Folder folder);
@Delete
void delete(Folder folder);

View File

@ -24,10 +24,9 @@ import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R;
import com.readrops.app.activities.AccountSettingsActivity;
import com.readrops.app.database.entities.Account;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.database.pojo.FeedWithFolder;
import com.readrops.app.databinding.FragmentFeedsBinding;
import com.readrops.app.viewmodels.ManageFeedsViewModel;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import com.readrops.app.views.EditFeedDialog;
import com.readrops.app.views.FeedsAdapter;
@ -42,7 +41,7 @@ import static com.readrops.app.activities.ManageFeedsFoldersActivity.ACCOUNT;
public class FeedsFragment extends Fragment {
private FeedsAdapter adapter;
private ManageFeedsViewModel viewModel;
private ManageFeedsFoldersViewModel viewModel;
private Account account;
private FragmentFeedsBinding binding;
@ -67,7 +66,7 @@ public class FeedsFragment extends Fragment {
account = getArguments().getParcelable(ACCOUNT);
viewModel = ViewModelProviders.of(this).get(ManageFeedsViewModel.class);
viewModel = ViewModelProviders.of(this).get(ManageFeedsFoldersViewModel.class);
viewModel.setAccount(account);
viewModel.getFeedsWithFolder().observe(this, feedWithFolders -> adapter.submitList(feedWithFolders));
@ -106,10 +105,10 @@ public class FeedsFragment extends Fragment {
binding.feedsRecyclerview.setAdapter(adapter);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int swipeFlags = ItemTouchHelper.RIGHT;
return makeMovementFlags(0, swipeFlags);
}
@ -121,7 +120,7 @@ public class FeedsFragment extends Fragment {
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
deleteFolder(adapter.getItemAt(viewHolder.getAdapterPosition()).getFeed().getId(),
deleteFeed(adapter.getItemAt(viewHolder.getAdapterPosition()).getFeed().getId(),
viewHolder.getAdapterPosition());
}
@ -134,7 +133,7 @@ public class FeedsFragment extends Fragment {
}).attachToRecyclerView(binding.feedsRecyclerview);
}
private void deleteFolder(int feedId, int position) {
private void deleteFeed(int feedId, int position) {
new MaterialDialog.Builder(getContext())
.title(getString(R.string.delete_feed))
.positiveText(getString(R.string.validate))
@ -168,31 +167,4 @@ public class FeedsFragment extends Fragment {
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.add(editFeedDialog, "").commit();
}
private void addFolder() {
new MaterialDialog.Builder(getActivity())
.title(R.string.add_folder)
.positiveText(R.string.validate)
.input(R.string.folder, 0, (dialog, input) -> {
Folder folder = new Folder(input.toString());
folder.setAccountId(account.getId());
viewModel.addFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
Toast.makeText(getContext(), "folder inserted", Toast.LENGTH_LONG).show();
}
@Override
public void onError(Throwable e) {
Toast.makeText(getContext(), "error on folder insertion", Toast.LENGTH_LONG).show();
}
});
})
.show();
}
}

View File

@ -5,14 +5,38 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R;
import com.readrops.app.activities.ManageFeedsFoldersActivity;
import com.readrops.app.database.entities.Account;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.databinding.FragmentFoldersBinding;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import com.readrops.app.views.FoldersAdapter;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableCompletableObserver;
import io.reactivex.schedulers.Schedulers;
public class FoldersFragment extends Fragment {
private FoldersAdapter adapter;
private FragmentFoldersBinding binding;
private ManageFeedsFoldersViewModel viewModel;
private Account account;
public FoldersFragment() {
// Required empty public constructor
}
@ -21,6 +45,7 @@ public class FoldersFragment extends Fragment {
FoldersFragment fragment = new FoldersFragment();
Bundle args = new Bundle();
args.putParcelable(ManageFeedsFoldersActivity.ACCOUNT, account);
fragment.setArguments(args);
return fragment;
@ -30,13 +55,89 @@ public class FoldersFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
account = getArguments().getParcelable(ManageFeedsFoldersActivity.ACCOUNT);
adapter = new FoldersAdapter(this::editFolder);
viewModel = ViewModelProviders.of(this).get(ManageFeedsFoldersViewModel.class);
viewModel.setAccount(account);
viewModel.getFolders().observe(this, folders -> adapter.submitList(folders));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_folders, container, false);
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_folders, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.foldersList.setLayoutManager(new LinearLayoutManager(getContext()));
binding.foldersList.setAdapter(adapter);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
deleteFolder(adapter.getFolder(viewHolder.getAdapterPosition()), viewHolder.getAdapterPosition());
}
}).attachToRecyclerView(binding.foldersList);
}
private void editFolder(Folder folder) {
new MaterialDialog.Builder(getActivity())
.title(R.string.edit_folder)
.positiveText(R.string.validate)
.input(getString(R.string.folder), folder.getName(), false, (dialog, input) -> {
folder.setName(input.toString());
viewModel.updateFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}
});
})
.show();
}
private void deleteFolder(Folder folder, int position) {
new MaterialDialog.Builder(getActivity())
.title(R.string.delete_folder)
.negativeText(R.string.cancel)
.positiveText(R.string.validate)
.onPositive((dialog, which) -> viewModel.deleteFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}))
.onNegative((dialog, which) -> adapter.notifyItemChanged(position))
.show();
}
}

View File

@ -46,22 +46,13 @@ public abstract class ARepository {
public abstract Completable deleteFeed(int feedId);
public abstract Completable addFolder(Folder folder);
public abstract Completable addFolder(Folder folder, Account account);
public Completable deleteFolder(Folder folder) {
return Completable.create(emitter -> {
database.folderDao().delete(folder);
emitter.onComplete();
});
}
public abstract Completable updateFolder(Folder folder, Account account);
public Completable changeFeedFolder(Feed feed, Folder newFolder) {
return Completable.create(emitter -> {
database.feedDao().updateFeedFolder(feed.getId(), newFolder.getId());
emitter.onComplete();
});
public abstract Completable deleteFolder(Folder folder);
}
public abstract Completable changeFeedFolder(Feed feed, Folder newFolder);
public Single<Integer> getFeedCount(int accountId) {
return Single.create(emitter -> emitter.onSuccess(database.feedDao().getFeedCount(accountId)));

View File

@ -162,13 +162,37 @@ public class LocalFeedRepository extends ARepository {
}
@Override
public Completable addFolder(Folder folder) {
public Completable addFolder(Folder folder, Account account) {
return Completable.create(emitter -> {
database.folderDao().insert(folder);
emitter.onComplete();
});
}
@Override
public Completable updateFolder(Folder folder, Account account) {
return Completable.create(emitter -> {
database.folderDao().update(folder);
emitter.onComplete();
});
}
@Override
public Completable deleteFolder(Folder folder) {
return Completable.create(emitter -> {
database.folderDao().delete(folder);
emitter.onComplete();
});
}
@Override
public Completable changeFeedFolder(Feed feed, Folder newFolder) {
return Completable.create(emitter -> {
database.feedDao().updateFeedFolder(feed.getId(), newFolder.getId());
emitter.onComplete();
});
}
private void insertNewItems(AFeed feed, RSSQuery.RSSType type) throws ParseException {
Feed dbFeed = null;
List<Item> items = null;

View File

@ -167,7 +167,37 @@ public class NextNewsRepository extends ARepository {
}
@Override
public Completable addFolder(Folder folder) {
public Completable addFolder(Folder folder, Account account) {
return Completable.create(emitter -> {
database.folderDao().insert(folder);
emitter.onComplete();
//TODO : remote insert
});
}
@Override
public Completable updateFolder(Folder folder, Account account) {
return Completable.create(emitter -> {
database.folderDao().update(folder);
emitter.onComplete();
//TODO : remote update
});
}
@Override
public Completable deleteFolder(Folder folder) {
return Completable.create(emitter -> {
database.folderDao().delete(folder);
emitter.onComplete();
//TODO : remote update
});
}
@Override
public Completable changeFeedFolder(Feed feed, Folder newFolder) {
return null;
}

View File

@ -17,7 +17,7 @@ import java.util.List;
import io.reactivex.Completable;
public class ManageFeedsViewModel extends AndroidViewModel {
public class ManageFeedsFoldersViewModel extends AndroidViewModel {
private Database db;
private LiveData<List<FeedWithFolder>> feedsWithFolder;
@ -26,7 +26,7 @@ public class ManageFeedsViewModel extends AndroidViewModel {
private Account account;
public ManageFeedsViewModel(@NonNull Application application) {
public ManageFeedsFoldersViewModel(@NonNull Application application) {
super(application);
db = Database.getInstance(application);
@ -68,7 +68,15 @@ public class ManageFeedsViewModel extends AndroidViewModel {
}
public Completable addFolder(Folder folder) {
return repository.addFolder(folder);
return repository.addFolder(folder, account);
}
public Completable updateFolder(Folder folder) {
return repository.updateFolder(folder, account);
}
public Completable deleteFolder(Folder folder) {
return repository.deleteFolder(folder);
}
public Completable deleteFeed(int feedId) {

View File

@ -20,7 +20,7 @@ import com.readrops.app.database.entities.Account;
import com.readrops.app.database.entities.Feed;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.database.pojo.FeedWithFolder;
import com.readrops.app.viewmodels.ManageFeedsViewModel;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import java.util.ArrayList;
import java.util.Map;
@ -36,12 +36,12 @@ public class EditFeedDialog extends DialogFragment implements AdapterView.OnItem
private FeedWithFolder feedWithFolder;
private Account account;
private ManageFeedsViewModel viewModel;
private ManageFeedsFoldersViewModel viewModel;
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
viewModel = ViewModelProviders.of(getActivity()).get(ManageFeedsViewModel.class);
viewModel = ViewModelProviders.of(getActivity()).get(ManageFeedsFoldersViewModel.class);
feedWithFolder = getArguments().getParcelable("feedWithFolder");
account = getArguments().getParcelable(ManageFeedsFoldersActivity.ACCOUNT);

View File

@ -0,0 +1,96 @@
package com.readrops.app.views;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import com.readrops.app.R;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.databinding.FolderLayoutBinding;
import java.util.List;
public class FoldersAdapter extends ListAdapter<Folder, FoldersAdapter.FolderViewHolder> {
private ManageFoldersListener listener;
public FoldersAdapter(ManageFoldersListener listener) {
super(DIFF_CALLBACK);
this.listener = listener;
}
private static final DiffUtil.ItemCallback<Folder> DIFF_CALLBACK = new DiffUtil.ItemCallback<Folder>() {
@Override
public boolean areItemsTheSame(@NonNull Folder oldItem, @NonNull Folder newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull Folder oldItem, @NonNull Folder newItem) {
return TextUtils.equals(oldItem.getName(), newItem.getName());
}
@Nullable
@Override
public Object getChangePayload(@NonNull Folder oldItem, @NonNull Folder newItem) {
return newItem;
}
};
@NonNull
@Override
public FolderViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
FolderLayoutBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.folder_layout, parent, false);
return new FolderViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull FolderViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.size() > 0) {
Folder folder = (Folder) payloads.get(0);
holder.binding.folderName.setText(folder.getName());
} else
onBindViewHolder(holder, position);
}
@Override
public void onBindViewHolder(@NonNull FolderViewHolder holder, int position) {
Folder folder = getItem(position);
holder.binding.folderName.setText(folder.getName());
holder.itemView.setOnClickListener(v -> listener.onClick(folder));
}
public Folder getFolder(int position) {
return getItem(position);
}
public interface ManageFoldersListener {
void onClick(Folder folder);
}
public class FolderViewHolder extends RecyclerView.ViewHolder {
private FolderLayoutBinding binding;
public FolderViewHolder(FolderLayoutBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="6dp"
android:clickable="true"
android:focusable="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:padding="8dp">
<TextView
android:id="@+id/folder_name"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Dossier 1" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>

View File

@ -1,8 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.FoldersFragment">
</FrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/folders_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -62,5 +62,9 @@
<string name="feeds_and_folders">Flux et dossiers</string>
<string name="account">Compte</string>
<string name="manage_feeds_folders">Gérer les flux et dossiers</string>
<string name="folders">Dossiers</string>
<string name="feeds">Flux</string>
<string name="edit_folder">Modifier le dossier</string>
<string name="delete_folder">Supprimer le dossier ?</string>
</resources>

View File

@ -67,4 +67,8 @@
<string name="feeds_and_folders">Feeds and folders</string>
<string name="account">Account</string>
<string name="manage_feeds_folders">Manage feeds and folders</string>
<string name="folders">Folders</string>
<string name="feeds">Feeds</string>
<string name="edit_folder">Edit folder</string>
<string name="delete_folder">Delete folder ?</string>
</resources>