mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Fix ConcurrentModificationException on saving a book
This commit is contained in:
parent
7de43bc074
commit
0967e2981a
@ -17,7 +17,11 @@ import io.reactivex.Single;
|
||||
public interface DataSource {
|
||||
Single<List<LibraryNetworkEntity.Book>> getLanguageCategorizedBooks();
|
||||
|
||||
void saveBooks(List<LibraryNetworkEntity.Book> book);
|
||||
Completable saveBook(LibraryNetworkEntity.Book book);
|
||||
|
||||
Completable saveBooks(List<LibraryNetworkEntity.Book> book);
|
||||
|
||||
Completable deleteBook(LibraryNetworkEntity.Book book);
|
||||
|
||||
Completable saveLanguages(List<Language> languages);
|
||||
|
||||
|
@ -83,8 +83,21 @@ public class Repository implements DataSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveBooks(List<LibraryNetworkEntity.Book> books) {
|
||||
bookDao.saveBooks((ArrayList<LibraryNetworkEntity.Book>) books);
|
||||
public Completable saveBooks(List<LibraryNetworkEntity.Book> books) {
|
||||
return Completable.fromAction(() -> bookDao.saveBooks((ArrayList<LibraryNetworkEntity.Book>) books))
|
||||
.subscribeOn(io);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable saveBook(LibraryNetworkEntity.Book book) {
|
||||
return Completable.fromAction(() -> bookDao.saveBook(book))
|
||||
.subscribeOn(io);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteBook(LibraryNetworkEntity.Book book) {
|
||||
return Completable.fromAction(() -> bookDao.deleteBook(book.getId()))
|
||||
.subscribeOn(io);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,7 +38,7 @@ import android.widget.Toast;
|
||||
|
||||
import org.kiwix.kiwixmobile.KiwixApplication;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
import org.kiwix.kiwixmobile.data.local.dao.BookDao;
|
||||
import org.kiwix.kiwixmobile.data.DataSource;
|
||||
import org.kiwix.kiwixmobile.data.remote.KiwixService;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
import org.kiwix.kiwixmobile.main.MainActivity;
|
||||
@ -61,8 +61,11 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.CompletableObserver;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
@ -77,15 +80,6 @@ import static org.kiwix.kiwixmobile.utils.files.FileUtils.getCurrentSize;
|
||||
|
||||
public class DownloadService extends Service {
|
||||
|
||||
@Inject KiwixService kiwixService;
|
||||
@Inject OkHttpClient httpClient;
|
||||
@Inject NotificationManager notificationManager;
|
||||
|
||||
private static String SD_CARD;
|
||||
// 1024 / 100
|
||||
private static final double BOOK_SIZE_OFFSET = 10.24;
|
||||
private static final String KIWIX_TAG = "kiwixdownloadservice";
|
||||
public static String KIWIX_ROOT;
|
||||
public static final int PLAY = 1;
|
||||
public static final int PAUSE = 2;
|
||||
public static final int FINISH = 3;
|
||||
@ -94,22 +88,33 @@ public class DownloadService extends Service {
|
||||
public static final String ACTION_STOP = "STOP";
|
||||
public static final String ACTION_NO_WIFI = "NO_WIFI";
|
||||
public static final String NOTIFICATION_ID = "NOTIFICATION_ID";
|
||||
public static final Object pauseLock = new Object();
|
||||
// 1024 / 100
|
||||
private static final double BOOK_SIZE_OFFSET = 10.24;
|
||||
private static final String KIWIX_TAG = "kiwixdownloadservice";
|
||||
public static String KIWIX_ROOT;
|
||||
public static ArrayList<String> notifications = new ArrayList<>();
|
||||
private static String SD_CARD;
|
||||
private static DownloadFragment downloadFragment;
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
public String notificationTitle;
|
||||
|
||||
private SparseArray<NotificationCompat.Builder> notification = new SparseArray<>();
|
||||
public SparseIntArray downloadStatus = new SparseIntArray();
|
||||
public SparseIntArray downloadProgress = new SparseIntArray();
|
||||
public SparseIntArray timeRemaining = new SparseIntArray();
|
||||
public static final Object pauseLock = new Object();
|
||||
private static DownloadFragment downloadFragment;
|
||||
@Inject
|
||||
KiwixService kiwixService;
|
||||
@Inject
|
||||
OkHttpClient httpClient;
|
||||
@Inject
|
||||
NotificationManager notificationManager;
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Inject
|
||||
SharedPreferenceUtil sharedPreferenceUtil;
|
||||
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
DataSource dataSource;
|
||||
private SparseArray<NotificationCompat.Builder> notification = new SparseArray<>();
|
||||
|
||||
public static void setDownloadFragment(DownloadFragment dFragment) {
|
||||
downloadFragment = dFragment;
|
||||
@ -167,7 +172,7 @@ public class DownloadService extends Service {
|
||||
LibraryNetworkEntity.Book book = (LibraryNetworkEntity.Book) intent.getSerializableExtra(EXTRA_BOOK);
|
||||
int notificationID = book.getId().hashCode();
|
||||
|
||||
if ( downloadStatus.get(notificationID, -1) == PAUSE || downloadStatus.get(notificationID, -1) == PLAY ) {
|
||||
if (downloadStatus.get(notificationID, -1) == PAUSE || downloadStatus.get(notificationID, -1) == PLAY) {
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@ -177,7 +182,7 @@ public class DownloadService extends Service {
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity
|
||||
(getBaseContext(), notificationID,
|
||||
target, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
target, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
Intent pauseIntent = new Intent(this, this.getClass()).setAction(ACTION_PAUSE).putExtra(NOTIFICATION_ID, notificationID);
|
||||
Intent stopIntent = new Intent(this, this.getClass()).setAction(ACTION_STOP).putExtra(NOTIFICATION_ID, notificationID);
|
||||
@ -187,10 +192,10 @@ public class DownloadService extends Service {
|
||||
NotificationCompat.Action pause = new NotificationCompat.Action(R.drawable.ic_pause_black_24dp, getString(R.string.download_pause), pausePending);
|
||||
NotificationCompat.Action stop = new NotificationCompat.Action(R.drawable.ic_stop_black_24dp, getString(R.string.download_stop), stopPending);
|
||||
|
||||
if(flags == START_FLAG_REDELIVERY && book.file == null) {
|
||||
if (flags == START_FLAG_REDELIVERY && book.file == null) {
|
||||
return START_NOT_STICKY;
|
||||
} else {
|
||||
notification.put(notificationID , new NotificationCompat.Builder(this, ONGOING_DOWNLOAD_CHANNEL_ID)
|
||||
notification.put(notificationID, new NotificationCompat.Builder(this, ONGOING_DOWNLOAD_CHANNEL_ID)
|
||||
.setContentTitle(getResources().getString(R.string.zim_file_downloading) + " " + notificationTitle)
|
||||
.setProgress(100, 0, false)
|
||||
.setSmallIcon(R.drawable.kiwix_notification)
|
||||
@ -199,7 +204,7 @@ public class DownloadService extends Service {
|
||||
.addAction(pause)
|
||||
.addAction(stop)
|
||||
.setOngoing(true));
|
||||
|
||||
|
||||
notificationManager.notify(notificationID, notification.get(notificationID).build());
|
||||
downloadStatus.put(notificationID, PLAY);
|
||||
LibraryFragment.downloadingBooks.remove(book);
|
||||
@ -229,7 +234,7 @@ public class DownloadService extends Service {
|
||||
notificationManager.cancel(notificationID);
|
||||
}
|
||||
|
||||
public String checkWritable(String path){
|
||||
public String checkWritable(String path) {
|
||||
try {
|
||||
File f = new File(path);
|
||||
f.mkdir();
|
||||
@ -238,13 +243,13 @@ public class DownloadService extends Service {
|
||||
}
|
||||
Toast.makeText(this, getResources().getString(R.string.path_not_writable), Toast.LENGTH_LONG).show();
|
||||
return Environment.getExternalStorageDirectory().getPath();
|
||||
} catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this, getResources().getString(R.string.path_not_writable), Toast.LENGTH_LONG).show();
|
||||
return Environment.getExternalStorageDirectory().getPath();
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleDownload (int notificationID) {
|
||||
public void toggleDownload(int notificationID) {
|
||||
if (downloadStatus.get(notificationID) == PAUSE) {
|
||||
playDownload(notificationID);
|
||||
} else {
|
||||
@ -255,7 +260,7 @@ public class DownloadService extends Service {
|
||||
public void pauseDownload(int notificationID) {
|
||||
Log.i(KIWIX_TAG, "Pausing ZIM Download for notificationID: " + notificationID);
|
||||
downloadStatus.put(notificationID, PAUSE);
|
||||
notification.get(notificationID).mActions.get(0).title = getString(R.string.download_play);
|
||||
notification.get(notificationID).mActions.get(0).title = getString(R.string.download_play);
|
||||
notification.get(notificationID).mActions.get(0).icon = R.drawable.ic_play_arrow_black_24dp;
|
||||
notification.get(notificationID).setContentText(getString(R.string.download_paused));
|
||||
notificationManager.notify(notificationID, notification.get(notificationID).build());
|
||||
@ -303,36 +308,70 @@ public class DownloadService extends Service {
|
||||
.flatMap(pair -> Observable.fromIterable(ChunkUtils.getChunks(pair.first, pair.second, notificationID)))
|
||||
.concatMap(this::downloadChunk)
|
||||
.distinctUntilChanged().doOnComplete(() -> updateDownloadFragmentComplete(notificationID))
|
||||
.subscribe(progress -> {
|
||||
if (progress == 100) {
|
||||
notification.get(notificationID).setOngoing(false);
|
||||
notification.get(notificationID).setContentTitle(notificationTitle + " " + getResources().getString(R.string.zim_file_downloaded));
|
||||
notification.get(notificationID).setContentText(getString(R.string.zim_file_downloaded));
|
||||
final Intent target = new Intent(this, MainActivity.class);
|
||||
target.putExtra(EXTRA_ZIM_FILE, KIWIX_ROOT + StorageUtils.getFileNameFromUrl(book.getUrl()));
|
||||
target.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity
|
||||
(getBaseContext(), 0,
|
||||
target, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
book.downloaded = true;
|
||||
bookDao.deleteBook(book.id);
|
||||
notification.get(notificationID).setContentIntent(pendingIntent);
|
||||
notification.get(notificationID).mActions.clear();
|
||||
TestingUtils.unbindResource(DownloadService.class);
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
notification.get(notificationID).setProgress(100, progress, false);
|
||||
if (progress != 100 && timeRemaining.get(notificationID) != -1)
|
||||
notification.get(notificationID).setContentText(DownloadFragment.toHumanReadableTime(timeRemaining.get(notificationID)));
|
||||
notificationManager.notify(notificationID, notification.get(notificationID).build());
|
||||
if (progress == 0 || progress == 100) {
|
||||
// Tells android to not kill the service
|
||||
updateForeground();
|
||||
|
||||
@Override
|
||||
public void onNext(Integer progress) {
|
||||
if (progress == 100) {
|
||||
notification.get(notificationID).setOngoing(false);
|
||||
notification.get(notificationID).setContentTitle(notificationTitle + " " + getResources().getString(R.string.zim_file_downloaded));
|
||||
notification.get(notificationID).setContentText(getString(R.string.zim_file_downloaded));
|
||||
final Intent target = new Intent(DownloadService.this, MainActivity.class);
|
||||
target.putExtra(EXTRA_ZIM_FILE, KIWIX_ROOT + StorageUtils.getFileNameFromUrl(book.getUrl()));
|
||||
target.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity
|
||||
(getBaseContext(), 0,
|
||||
target, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
book.downloaded = true;
|
||||
dataSource.deleteBook(book)
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e("DownloadService", "Unable to delete book", e);
|
||||
}
|
||||
});
|
||||
notification.get(notificationID).setContentIntent(pendingIntent);
|
||||
notification.get(notificationID).mActions.clear();
|
||||
TestingUtils.unbindResource(DownloadService.class);
|
||||
}
|
||||
notification.get(notificationID).setProgress(100, progress, false);
|
||||
if (progress != 100 && timeRemaining.get(notificationID) != -1)
|
||||
notification.get(notificationID).setContentText(DownloadFragment.toHumanReadableTime(timeRemaining.get(notificationID)));
|
||||
notificationManager.notify(notificationID, notification.get(notificationID).build());
|
||||
if (progress == 0 || progress == 100) {
|
||||
// Tells android to not kill the service
|
||||
updateForeground();
|
||||
}
|
||||
updateDownloadFragmentProgress(progress, notificationID);
|
||||
if (progress == 100) {
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
updateDownloadFragmentProgress(progress, notificationID);
|
||||
if (progress == 100) {
|
||||
stopSelf();
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
|
||||
}
|
||||
}, Throwable::printStackTrace);
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateDownloadFragmentProgress(int progress, int notificationID) {
|
||||
@ -358,15 +397,15 @@ public class DownloadService extends Service {
|
||||
private void updateForeground() {
|
||||
// Allow notification to be dismissible while ensuring integrity of service if active downloads
|
||||
stopForeground(true);
|
||||
for(int i = 0; i < downloadStatus.size(); i++) {
|
||||
if (downloadStatus.get(i) == PLAY && downloadStatus.get(i) == PAUSE ){
|
||||
startForeground( downloadStatus.keyAt(i), notification.get(downloadStatus.keyAt(i)).build());
|
||||
for (int i = 0; i < downloadStatus.size(); i++) {
|
||||
if (downloadStatus.get(i) == PLAY && downloadStatus.get(i) == PAUSE) {
|
||||
startForeground(downloadStatus.keyAt(i), notification.get(downloadStatus.keyAt(i)).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Observable<Pair<String, Long>> getMetaLinkContentLength(String url) {
|
||||
Log.d("KiwixDownloadSSL","url=" + url);
|
||||
Log.d("KiwixDownloadSSL", "url=" + url);
|
||||
final String urlToUse = UseHttpOnAndroidVersion4(url);
|
||||
return Observable.create(subscriber -> {
|
||||
try {
|
||||
@ -436,7 +475,23 @@ public class DownloadService extends Service {
|
||||
.get(chunk.getNotificationID());
|
||||
book.remoteUrl = book.getUrl();
|
||||
book.file = fullFile;
|
||||
bookDao.saveBook(book);
|
||||
dataSource.saveBook(book)
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e("DownloadService", "Unable to save book", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
downloadStatus.put(chunk.getNotificationID(), PLAY);
|
||||
downloadProgress.put(chunk.getNotificationID(), 0);
|
||||
@ -515,7 +570,7 @@ public class DownloadService extends Service {
|
||||
output.write(buffer, 0, read);
|
||||
int progress = (int) ((100 * downloaded) / chunk.getContentLength());
|
||||
downloadProgress.put(chunk.getNotificationID(), progress);
|
||||
if (progress == 100){
|
||||
if (progress == 100) {
|
||||
downloadStatus.put(chunk.getNotificationID(), FINISH);
|
||||
}
|
||||
subscriber.onNext(progress);
|
||||
@ -564,7 +619,7 @@ public class DownloadService extends Service {
|
||||
* Creates and registers notification channel with system for notifications of
|
||||
* type: download in progress.
|
||||
*/
|
||||
private void createOngoingDownloadChannel () {
|
||||
private void createOngoingDownloadChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CharSequence name = getString(R.string.ongoing_download_channel_name);
|
||||
String description = getString(R.string.ongoing_download_channel_desc);
|
||||
@ -578,7 +633,10 @@ public class DownloadService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used for the client Binder. Because we know this service always
|
||||
@ -590,10 +648,4 @@ public class DownloadService extends Service {
|
||||
return DownloadService.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import io.reactivex.disposables.Disposable;
|
||||
@PerActivity
|
||||
class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {
|
||||
|
||||
private static final String TAG = "MainPresenter";
|
||||
private final DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
@ -47,15 +48,30 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.d("MainPresenter", e.toString());
|
||||
Log.e(TAG, "Unable to load books", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveBooks(List<LibraryNetworkEntity.Book> book) {
|
||||
dataSource.saveBooks(book);
|
||||
showHome();
|
||||
dataSource.saveBooks(book)
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
showHome();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "Unable to save books", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,7 +90,7 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e("MainPresenter", e.toString());
|
||||
Log.e(TAG, "Unable to save history", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -82,7 +98,7 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
|
||||
@Override
|
||||
public void loadCurrentZimBookmarksUrl() {
|
||||
compositeDisposable.add(dataSource.getCurrentZimBookmarksUrl()
|
||||
.subscribe(view::refreshBookmarksUrl, e -> Log.e("MainPresenter", e.toString())));
|
||||
.subscribe(view::refreshBookmarksUrl, e -> Log.e(TAG, "Unable to load current ZIM urls", e)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,7 +117,7 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e("MainPresenter", e.toString());
|
||||
Log.e(TAG, "Unable to save bookmark", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -122,7 +138,7 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e("MainPresenter", e.toString());
|
||||
Log.e(TAG, "Unable to delete bookmark", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
@ -68,11 +69,18 @@ import static org.kiwix.kiwixmobile.utils.NetworkUtils.parseURL;
|
||||
import static org.kiwix.kiwixmobile.utils.StyleUtils.dialogStyle;
|
||||
|
||||
public class ZimFileSelectFragment extends BaseFragment
|
||||
implements OnItemClickListener, AdapterView.OnItemLongClickListener, ZimFileSelectViewCallback{
|
||||
implements OnItemClickListener, AdapterView.OnItemLongClickListener, ZimFileSelectViewCallback {
|
||||
|
||||
public RelativeLayout llLayout;
|
||||
public SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
||||
@Inject
|
||||
ZimFileSelectPresenter presenter;
|
||||
@Inject
|
||||
BookUtils bookUtils;
|
||||
@Inject
|
||||
SharedPreferenceUtil sharedPreferenceUtil;
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
private ZimManageActivity zimManageActivity;
|
||||
private RescanDataAdapter mRescanAdapter;
|
||||
private ArrayList<LibraryNetworkEntity.Book> mFiles;
|
||||
@ -80,20 +88,14 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
private TextView mFileMessage;
|
||||
private boolean mHasRefresh;
|
||||
|
||||
@Inject ZimFileSelectPresenter presenter;
|
||||
@Inject BookUtils bookUtils;
|
||||
@Inject SharedPreferenceUtil sharedPreferenceUtil;
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
KiwixApplication.getApplicationComponent().inject(this);
|
||||
zimManageActivity = (ZimManageActivity) super.getActivity();
|
||||
presenter.attachView(this);
|
||||
// Replace LinearLayout by the type of the root element of the layout you're trying to load
|
||||
llLayout = (RelativeLayout) inflater.inflate(R.layout.zim_list, container, false);
|
||||
new LanguageUtils(super.getActivity()).changeFont(super.getActivity().getLayoutInflater(), sharedPreferenceUtil);
|
||||
new LanguageUtils(zimManageActivity).changeFont(zimManageActivity.getLayoutInflater(), sharedPreferenceUtil);
|
||||
|
||||
mFileMessage = llLayout.findViewById(R.id.file_management_no_files);
|
||||
mZimFileList = llLayout.findViewById(R.id.zimfilelist);
|
||||
@ -154,26 +156,19 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
if (book != null) {
|
||||
mFiles.add(book);
|
||||
mRescanAdapter.notifyDataSetChanged();
|
||||
bookDao.saveBooks(mFiles);
|
||||
presenter.saveBooks(mFiles);
|
||||
checkEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private class FileComparator implements Comparator<LibraryNetworkEntity.Book> {
|
||||
@Override
|
||||
public int compare(LibraryNetworkEntity.Book b1, LibraryNetworkEntity.Book b2) {
|
||||
return b1.getTitle().compareTo(b2.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPermissions(){
|
||||
if (ContextCompat.checkSelfPermission(super.getActivity(),
|
||||
public void checkPermissions() {
|
||||
if (ContextCompat.checkSelfPermission(zimManageActivity,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED && Build.VERSION.SDK_INT > 18) {
|
||||
Toast.makeText(super.getActivity(), getResources().getString(R.string.request_storage), Toast.LENGTH_LONG)
|
||||
.show();
|
||||
requestPermissions( new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
REQUEST_STORAGE_PERMISSION);
|
||||
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
REQUEST_STORAGE_PERMISSION);
|
||||
} else {
|
||||
getFiles();
|
||||
}
|
||||
@ -225,7 +220,7 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
// Save the current list of books
|
||||
zimManageActivity.runOnUiThread(() -> {
|
||||
mRescanAdapter.notifyDataSetChanged();
|
||||
bookDao.saveBooks(mFiles);
|
||||
presenter.saveBooks(mFiles);
|
||||
checkEmpty();
|
||||
TestingUtils.unbindResource(ZimFileSelectFragment.class);
|
||||
|
||||
@ -238,12 +233,12 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
String permissions[], int[] grantResults) {
|
||||
@NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_STORAGE_PERMISSION: {
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
getFiles();
|
||||
getFiles();
|
||||
} else if (grantResults.length != 0) {
|
||||
zimManageActivity.finish();
|
||||
}
|
||||
@ -298,7 +293,7 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
if (file.exists()) {
|
||||
return false;
|
||||
}
|
||||
bookDao.deleteBook(mFiles.get(position).getId());
|
||||
presenter.deleteBook(mFiles.get(position));
|
||||
mFiles.remove(position);
|
||||
mRescanAdapter.notifyDataSetChanged();
|
||||
checkEmpty();
|
||||
@ -308,93 +303,101 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkEmpty(){
|
||||
if (mZimFileList.getCount() == 0){
|
||||
public void checkEmpty() {
|
||||
if (mZimFileList.getCount() == 0) {
|
||||
mFileMessage.setVisibility(View.VISIBLE);
|
||||
} else
|
||||
mFileMessage.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private class FileComparator implements Comparator<LibraryNetworkEntity.Book> {
|
||||
@Override
|
||||
public int compare(LibraryNetworkEntity.Book b1, LibraryNetworkEntity.Book b2) {
|
||||
return b1.getTitle().compareTo(b2.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
// The Adapter for the ListView for when the ListView is populated with the rescanned files
|
||||
private class RescanDataAdapter extends ArrayAdapter<LibraryNetworkEntity.Book> {
|
||||
|
||||
public RescanDataAdapter(Context context, int textViewResourceId, List<LibraryNetworkEntity.Book> objects) {
|
||||
RescanDataAdapter(Context context, int textViewResourceId, List<LibraryNetworkEntity.Book> objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||
|
||||
ViewHolder holder;
|
||||
LibraryNetworkEntity.Book book = getItem(position);
|
||||
if (convertView == null) {
|
||||
convertView = View.inflate(zimManageActivity, R.layout.library_item, null);
|
||||
holder = new ViewHolder();
|
||||
holder.title = convertView.findViewById(R.id.title);
|
||||
holder.description = convertView.findViewById(R.id.description);
|
||||
holder.language = convertView.findViewById(R.id.language);
|
||||
holder.creator = convertView.findViewById(R.id.creator);
|
||||
holder.publisher = convertView.findViewById(R.id.publisher);
|
||||
holder.date = convertView.findViewById(R.id.date);
|
||||
holder.size = convertView.findViewById(R.id.size);
|
||||
holder.fileName = convertView.findViewById(R.id.fileName);
|
||||
holder.favicon = convertView.findViewById(R.id.favicon);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
if (convertView == null) {
|
||||
convertView = View.inflate(zimManageActivity, R.layout.library_item, null);
|
||||
holder = new ViewHolder();
|
||||
holder.title = convertView.findViewById(R.id.title);
|
||||
holder.description = convertView.findViewById(R.id.description);
|
||||
holder.language = convertView.findViewById(R.id.language);
|
||||
holder.creator = convertView.findViewById(R.id.creator);
|
||||
holder.publisher = convertView.findViewById(R.id.publisher);
|
||||
holder.date = convertView.findViewById(R.id.date);
|
||||
holder.size = convertView.findViewById(R.id.size);
|
||||
holder.fileName = convertView.findViewById(R.id.fileName);
|
||||
holder.favicon = convertView.findViewById(R.id.favicon);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
if (book == null) {
|
||||
return convertView;
|
||||
}
|
||||
if (book == null) {
|
||||
return convertView;
|
||||
}
|
||||
|
||||
holder.title.setText(book.getTitle());
|
||||
holder.description.setText(book.getDescription());
|
||||
holder.language.setText(bookUtils.getLanguage(book.getLanguage()));
|
||||
holder.creator.setText(book.getCreator());
|
||||
holder.publisher.setText(book.getPublisher());
|
||||
holder.date.setText(book.getDate());
|
||||
holder.size.setText(LibraryAdapter.createGbString(book.getSize()));
|
||||
holder.fileName.setText(parseURL(getActivity(), book.file.getPath()));
|
||||
holder.favicon.setImageBitmap(LibraryAdapter.createBitmapFromEncodedString(book.getFavicon(), zimManageActivity));
|
||||
holder.title.setText(book.getTitle());
|
||||
holder.description.setText(book.getDescription());
|
||||
holder.language.setText(bookUtils.getLanguage(book.getLanguage()));
|
||||
holder.creator.setText(book.getCreator());
|
||||
holder.publisher.setText(book.getPublisher());
|
||||
holder.date.setText(book.getDate());
|
||||
holder.size.setText(LibraryAdapter.createGbString(book.getSize()));
|
||||
holder.fileName.setText(parseURL(getActivity(), book.file.getPath()));
|
||||
holder.favicon.setImageBitmap(LibraryAdapter.createBitmapFromEncodedString(book.getFavicon(), zimManageActivity));
|
||||
|
||||
|
||||
//// Check if no value is empty. Set the view to View.GONE, if it is. To View.VISIBLE, if not.
|
||||
if (book.getTitle() == null || book.getTitle().isEmpty()) {
|
||||
holder.title.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.title.setVisibility(View.VISIBLE);
|
||||
}
|
||||
//// Check if no value is empty. Set the view to View.GONE, if it is. To View.VISIBLE, if not.
|
||||
if (book.getTitle() == null || book.getTitle().isEmpty()) {
|
||||
holder.title.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.title.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (book.getDescription() == null || book.getDescription().isEmpty()) {
|
||||
holder.description.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.description.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (book.getDescription() == null || book.getDescription().isEmpty()) {
|
||||
holder.description.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.description.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (book.getCreator() == null || book.getCreator().isEmpty()) {
|
||||
holder.creator.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.creator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (book.getCreator() == null || book.getCreator().isEmpty()) {
|
||||
holder.creator.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.creator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (book.getPublisher() == null || book.getPublisher().isEmpty()) {
|
||||
holder.publisher.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.publisher.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (book.getPublisher() == null || book.getPublisher().isEmpty()) {
|
||||
holder.publisher.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.publisher.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (book.getDate() == null || book.getDate().isEmpty()) {
|
||||
holder.date.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.date.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (book.getDate() == null || book.getDate().isEmpty()) {
|
||||
holder.date.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.date.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (book.getSize() == null || book.getSize().isEmpty()) {
|
||||
holder.size.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.size.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (book.getSize() == null || book.getSize().isEmpty()) {
|
||||
holder.size.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.size.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
|
||||
|
@ -17,7 +17,10 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.zim_manager.fileselect_view;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.kiwix.kiwixmobile.base.BasePresenter;
|
||||
import org.kiwix.kiwixmobile.data.DataSource;
|
||||
import org.kiwix.kiwixmobile.data.local.dao.BookDao;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
|
||||
@ -25,16 +28,23 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.CompletableObserver;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Created by EladKeyshawn on 06/04/2017.
|
||||
*/
|
||||
public class ZimFileSelectPresenter extends BasePresenter<ZimFileSelectViewCallback> {
|
||||
|
||||
private static final String TAG = "ZimFileSelectPresenter";
|
||||
private final DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
|
||||
@Inject
|
||||
ZimFileSelectPresenter() {
|
||||
ZimFileSelectPresenter(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -47,4 +57,43 @@ public class ZimFileSelectPresenter extends BasePresenter<ZimFileSelectViewCallb
|
||||
view.showFiles(books);
|
||||
}
|
||||
|
||||
void saveBooks(ArrayList<LibraryNetworkEntity.Book> books) {
|
||||
dataSource.saveBooks(books)
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "Unable to save books", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteBook(LibraryNetworkEntity.Book book) {
|
||||
dataSource.deleteBook(book)
|
||||
.subscribe(new CompletableObserver() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "Unable to delete book", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user