mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
LibraryFragment converted to Kotlin and observing reactive streams
This commit is contained in:
parent
61697b502c
commit
41a753a1e6
3
.gitignore
vendored
3
.gitignore
vendored
@ -53,4 +53,5 @@ glassify
|
||||
.project
|
||||
.classpath
|
||||
|
||||
.vscode
|
||||
.vscode
|
||||
captures/
|
||||
|
@ -51,7 +51,6 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
|
||||
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
|
||||
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
|
||||
import static com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton;
|
||||
import static com.schibsted.spain.barista.interaction.BaristaSwipeRefreshInteractions.refresh;
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
@ -115,13 +114,13 @@ public class DownloadTest {
|
||||
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
|
||||
|
||||
try {
|
||||
onData(withContent("ray_charles")).inAdapterView(withId(R.id.library_list));
|
||||
onData(withContent("ray_charles")).inAdapterView(withId(R.id.libraryList));
|
||||
} catch (Exception e) {
|
||||
fail("Couldn't find downloaded file 'ray_charles'\n\nOriginal Exception:\n" +
|
||||
e.getLocalizedMessage() + "\n\n" );
|
||||
}
|
||||
|
||||
deleteZimIfExists("ray_charles", R.id.library_list);
|
||||
deleteZimIfExists("ray_charles", R.id.libraryList);
|
||||
|
||||
assertDisplayed(R.string.local_zims);
|
||||
clickOn(R.string.local_zims);
|
||||
|
@ -137,7 +137,7 @@ public class NetworkTest {
|
||||
"Permission dialog was not shown, we probably already have required permissions");
|
||||
}
|
||||
|
||||
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.library_list)).perform(click());
|
||||
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.libraryList)).perform(click());
|
||||
|
||||
try {
|
||||
onView(withId(android.R.id.button1)).perform(click());
|
||||
|
@ -482,7 +482,7 @@ public class KiwixMobileActivity extends BaseActivity implements WebViewCallback
|
||||
}
|
||||
if (i.hasExtra(EXTRA_ZIM_FILE)) {
|
||||
File file = new File(getFileName(i.getStringExtra(EXTRA_ZIM_FILE)));
|
||||
LibraryFragment.mService.cancelNotification(i.getIntExtra(EXTRA_NOTIFICATION_ID, 0));
|
||||
//LibraryFragment.mService.cancelNotification(i.getIntExtra(EXTRA_NOTIFICATION_ID, 0));
|
||||
Uri uri = Uri.fromFile(file);
|
||||
|
||||
finish();
|
||||
|
@ -50,8 +50,14 @@ public class DownloadDao {
|
||||
}
|
||||
|
||||
public void insert(final DownloadModel downloadModel) {
|
||||
kiwixDatabase.persistWithOnConflict(databaseEntity(downloadModel),
|
||||
TableStatement.ConflictAlgorithm.REPLACE);
|
||||
if (doesNotAlreadyExist(downloadModel)) {
|
||||
kiwixDatabase.persistWithOnConflict(databaseEntity(downloadModel),
|
||||
TableStatement.ConflictAlgorithm.REPLACE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doesNotAlreadyExist(DownloadModel downloadModel) {
|
||||
return kiwixDatabase.count(DownloadDatabaseEntity.class, DownloadDatabaseEntity.BOOK_ID.eq(downloadModel.getBookId())) == 0;
|
||||
}
|
||||
|
||||
public void delete(@NotNull Long... downloadIds) {
|
||||
|
@ -19,50 +19,62 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.database;
|
||||
|
||||
import com.yahoo.squidb.data.SimpleDataChangedNotifier;
|
||||
import com.yahoo.squidb.data.SquidCursor;
|
||||
import com.yahoo.squidb.sql.Query;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import org.kiwix.kiwixmobile.database.entity.NetworkLanguageDatabaseEntity;
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter.Language;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.processors.PublishProcessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import org.kiwix.kiwixmobile.database.entity.NetworkLanguageDatabaseEntity;
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language;
|
||||
|
||||
public class NetworkLanguageDao {
|
||||
private KiwixDatabase mDb;
|
||||
private final PublishProcessor<List<Language>> languageProcessor =
|
||||
PublishProcessor.create();
|
||||
|
||||
@Inject
|
||||
public NetworkLanguageDao(KiwixDatabase kiwikDatabase) {
|
||||
this.mDb = kiwikDatabase;
|
||||
mDb.registerDataChangedNotifier(
|
||||
new SimpleDataChangedNotifier(NetworkLanguageDatabaseEntity.TABLE) {
|
||||
@Override
|
||||
protected void onDataChanged() {
|
||||
languageProcessor.onNext(getActiveLanguages());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ArrayList<LibraryAdapter.Language> getFilteredLanguages() {
|
||||
SquidCursor<NetworkLanguageDatabaseEntity> languageCursor = mDb.query(
|
||||
public Flowable<List<Language>> activeLanguages() {
|
||||
return languageProcessor.startWith(getActiveLanguages()).distinctUntilChanged();
|
||||
}
|
||||
|
||||
public List<Language> getActiveLanguages() {
|
||||
ArrayList<Language> result = new ArrayList<>();
|
||||
try (SquidCursor<NetworkLanguageDatabaseEntity> languageCursor = mDb.query(
|
||||
NetworkLanguageDatabaseEntity.class,
|
||||
Query.select());
|
||||
ArrayList<LibraryAdapter.Language> result = new ArrayList<>();
|
||||
try {
|
||||
Query.select().where(NetworkLanguageDatabaseEntity.ENABLED.eq(true)))) {
|
||||
while (languageCursor.moveToNext()) {
|
||||
String languageCode = languageCursor.get(NetworkLanguageDatabaseEntity.LANGUAGE_I_S_O_3);
|
||||
boolean enabled = languageCursor.get(NetworkLanguageDatabaseEntity.ENABLED);
|
||||
result.add(new LibraryAdapter.Language(languageCode, enabled));
|
||||
result.add(new Language(languageCode, enabled));
|
||||
}
|
||||
} finally {
|
||||
languageCursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void saveFilteredLanguages(List<Language> languages){
|
||||
public void saveFilteredLanguages(List<Language> languages) {
|
||||
mDb.deleteAll(NetworkLanguageDatabaseEntity.class);
|
||||
Collections.sort(languages, (language, t1) -> language.language.compareTo(t1.language));
|
||||
for (LibraryAdapter.Language language : languages){
|
||||
NetworkLanguageDatabaseEntity networkLanguageDatabaseEntity = new NetworkLanguageDatabaseEntity();
|
||||
networkLanguageDatabaseEntity.setLanguageISO3(language.languageCode);
|
||||
networkLanguageDatabaseEntity.setIsEnabled(language.active);
|
||||
Collections.sort(languages,
|
||||
(language, t1) -> language.getLanguage().compareTo(t1.getLanguage()));
|
||||
for (Language language : languages) {
|
||||
NetworkLanguageDatabaseEntity networkLanguageDatabaseEntity =
|
||||
new NetworkLanguageDatabaseEntity();
|
||||
networkLanguageDatabaseEntity.setLanguageISO3(language.getLanguageCode());
|
||||
networkLanguageDatabaseEntity.setIsEnabled(language.getActive());
|
||||
mDb.persist(networkLanguageDatabaseEntity);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import org.kiwix.kiwixmobile.di.modules.ApplicationModule;
|
||||
import org.kiwix.kiwixmobile.di.modules.JNIModule;
|
||||
import org.kiwix.kiwixmobile.di.modules.NetworkModule;
|
||||
import org.kiwix.kiwixmobile.downloader.DownloadService;
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.settings.KiwixSettingsActivity;
|
||||
import org.kiwix.kiwixmobile.views.AutoCompleteAdapter;
|
||||
import org.kiwix.kiwixmobile.views.web.KiwixWebView;
|
||||
@ -56,8 +56,6 @@ public interface ApplicationComponent {
|
||||
|
||||
void inject(ZimContentProvider zimContentProvider);
|
||||
|
||||
void inject(LibraryAdapter libraryAdapter);
|
||||
|
||||
void inject(KiwixWebView kiwixWebView);
|
||||
|
||||
void inject(KiwixSettingsActivity.PrefsFragment prefsFragment);
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.di.modules;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.DownloadManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
@ -32,6 +33,10 @@ import org.kiwix.kiwixmobile.utils.BookUtils;
|
||||
})
|
||||
public class ApplicationModule {
|
||||
|
||||
@Provides @Singleton Application provideApplication(Context context) {
|
||||
return (Application) context;
|
||||
}
|
||||
|
||||
@Provides @Singleton NotificationManager provideNotificationManager(Context context) {
|
||||
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ public class DownloadService extends Service {
|
||||
|
||||
notificationManager.notify(notificationID, notification.get(notificationID).build());
|
||||
downloadStatus.put(notificationID, PLAY);
|
||||
LibraryFragment.downloadingBooks.remove(book);
|
||||
//LibraryFragment.downloadingBooks.remove(book);
|
||||
String url = intent.getExtras().getString(DownloadIntent.DOWNLOAD_URL_PARAMETER);
|
||||
downloadBook(url, notificationID, book);
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package org.kiwix.kiwixmobile.extensions
|
||||
|
||||
import android.net.ConnectivityManager
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState.CONNECTED
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState.NOT_CONNECTED
|
||||
|
||||
val ConnectivityManager.networkState: NetworkState
|
||||
get() = if (activeNetworkInfo?.isConnected == true)
|
||||
CONNECTED
|
||||
else
|
||||
NOT_CONNECTED
|
@ -1,7 +1,9 @@
|
||||
package org.kiwix.kiwixmobile.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.content.IntentFilter
|
||||
import android.widget.Toast
|
||||
import org.kiwix.kiwixmobile.zim_manager.BaseBroadcastReceiver
|
||||
|
||||
fun Context?.toast(
|
||||
stringId: Int,
|
||||
@ -11,4 +13,17 @@ fun Context?.toast(
|
||||
Toast.makeText(this, stringId, length)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context?.toast(
|
||||
text: String,
|
||||
length: Int = Toast.LENGTH_LONG
|
||||
) {
|
||||
this?.let {
|
||||
Toast.makeText(this, text, length)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.registerReceiver(baseBroadcastReceiver: BaseBroadcastReceiver) =
|
||||
registerReceiver(baseBroadcastReceiver, IntentFilter(baseBroadcastReceiver.action))
|
||||
|
@ -0,0 +1,12 @@
|
||||
package org.kiwix.kiwixmobile.extensions
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
|
||||
fun TextView.setTextAndVisibility(nullableText: String?) =
|
||||
if (nullableText != null && nullableText.isNotEmpty()) {
|
||||
text = nullableText
|
||||
visibility = View.VISIBLE
|
||||
} else {
|
||||
visibility = View.GONE
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package org.kiwix.kiwixmobile.extensions
|
||||
|
||||
import android.graphics.Color
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.view.View
|
||||
|
||||
fun View.snack(
|
||||
stringId: Int,
|
||||
actionStringId: Int,
|
||||
actionClick: () -> Unit,
|
||||
actionTextColor: Int = Color.WHITE
|
||||
) {
|
||||
Snackbar.make(
|
||||
this, stringId, Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(actionStringId) {
|
||||
actionClick.invoke()
|
||||
}
|
||||
.setActionTextColor(actionTextColor)
|
||||
.show()
|
||||
}
|
@ -1,473 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.library;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.Base64;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import org.kiwix.kiwixmobile.KiwixApplication;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
import org.kiwix.kiwixmobile.database.BookDao;
|
||||
import org.kiwix.kiwixmobile.database.NetworkLanguageDao;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils;
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.LibraryFragment;
|
||||
|
||||
import static org.kiwix.kiwixmobile.utils.NetworkUtils.parseURL;
|
||||
|
||||
public class LibraryAdapter extends BaseAdapter {
|
||||
private static final int LIST_ITEM_TYPE_BOOK = 0;
|
||||
private static final int LIST_ITEM_TYPE_DIVIDER = 1;
|
||||
|
||||
private ImmutableList<Book> allBooks;
|
||||
private List<ListItem> listItems = new ArrayList<>();
|
||||
private final Context context;
|
||||
public Map<String, Integer> languageCounts = new HashMap<>();
|
||||
public List<Language> languages = new ArrayList<>();
|
||||
private final LayoutInflater layoutInflater;
|
||||
private final BookFilter bookFilter = new BookFilter();
|
||||
private Disposable saveNetworkLanguageDisposable;
|
||||
@Inject BookUtils bookUtils;
|
||||
@Inject
|
||||
NetworkLanguageDao networkLanguageDao;
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
|
||||
//TODO: restore functionality of commented out code
|
||||
public LibraryAdapter(Context context) {
|
||||
super();
|
||||
KiwixApplication.getApplicationComponent().inject(this);
|
||||
this.context = context;
|
||||
layoutInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public void setAllBooks(List<Book> books) {
|
||||
allBooks = ImmutableList.copyOf(books);
|
||||
updateLanguageCounts();
|
||||
updateLanguages();
|
||||
}
|
||||
|
||||
public boolean isDivider(int position) {
|
||||
return listItems.get(position).type == LIST_ITEM_TYPE_DIVIDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return listItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int i) {
|
||||
return listItems.get(i).data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ViewHolder holder;
|
||||
if (position >= listItems.size()) {
|
||||
return convertView;
|
||||
}
|
||||
ListItem item = listItems.get(position);
|
||||
|
||||
if (item.type == LIST_ITEM_TYPE_BOOK) {
|
||||
if (convertView != null && convertView.findViewById(R.id.title) != null) {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
} else {
|
||||
convertView = layoutInflater.inflate(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);
|
||||
}
|
||||
|
||||
Book book = (Book) listItems.get(position).data;
|
||||
|
||||
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(createGbString(book.getSize()));
|
||||
holder.fileName.setText(parseURL(context, book.getUrl()));
|
||||
holder.favicon.setImageBitmap(createBitmapFromEncodedString(book.getFavicon(), context));
|
||||
|
||||
// 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.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.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);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
} else {
|
||||
if (convertView != null && convertView.findViewById(R.id.divider_text) != null) {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
} else {
|
||||
convertView = layoutInflater.inflate(R.layout.library_divider, null);
|
||||
holder = new ViewHolder();
|
||||
holder.title = convertView.findViewById(R.id.divider_text);
|
||||
convertView.setTag(holder);
|
||||
}
|
||||
|
||||
String dividerText = (String) listItems.get(position).data;
|
||||
|
||||
holder.title.setText(dividerText);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean languageActive(Book book) {
|
||||
return Observable.fromIterable(languages)
|
||||
.filter(language -> language.languageCode.equals(book.getLanguage()))
|
||||
.firstElement()
|
||||
.map(language -> language.active)
|
||||
.blockingGet(false);
|
||||
}
|
||||
|
||||
private Observable<Book> getMatches(Book b, String s) {
|
||||
StringBuilder text = new StringBuilder();
|
||||
text.append(b.getTitle()).append("|").append(b.getDescription()).append("|")
|
||||
.append(parseURL(context, b.getUrl())).append("|");
|
||||
if (bookUtils.localeMap.containsKey(b.getLanguage())) {
|
||||
text.append(bookUtils.localeMap.get(b.getLanguage()).getDisplayLanguage()).append("|");
|
||||
}
|
||||
String[] words = s.toLowerCase().split("\\s+");
|
||||
b.searchMatches = Observable.fromArray(words)
|
||||
.filter(text.toString().toLowerCase()::contains)
|
||||
.count()
|
||||
.blockingGet()
|
||||
.intValue();
|
||||
if (b.searchMatches > 0) {
|
||||
return Observable.just(b);
|
||||
} else {
|
||||
return Observable.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private class BookFilter extends Filter {
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence s) {
|
||||
List<Book> books = bookDao.getBooks();
|
||||
listItems.clear();
|
||||
if (s.length() == 0) {
|
||||
List<Book> selectedLanguages = Observable.fromIterable(allBooks)
|
||||
.filter(LibraryAdapter.this::languageActive)
|
||||
.filter(book -> !books.contains(book))
|
||||
// .filter(book -> !DownloadFragment.mDownloads.values().contains(book))
|
||||
.filter(book -> !LibraryFragment.downloadingBooks.contains(book))
|
||||
.filter(book -> !book.url.contains("/stack_exchange/")) // Temp filter see #694
|
||||
.toList()
|
||||
.blockingGet();
|
||||
|
||||
List<Book> unselectedLanguages = Observable.fromIterable(allBooks)
|
||||
.filter(book -> !languageActive(book))
|
||||
.filter(book -> !books.contains(book))
|
||||
// .filter(book -> !DownloadFragment.mDownloads.values().contains(book))
|
||||
.filter(book -> !LibraryFragment.downloadingBooks.contains(book))
|
||||
.filter(book -> !book.url.contains("/stack_exchange/")) // Temp filter see #694
|
||||
.toList()
|
||||
.blockingGet();
|
||||
|
||||
listItems.add(new ListItem(context.getResources().getString(R.string.your_languages), LIST_ITEM_TYPE_DIVIDER));
|
||||
addBooks(selectedLanguages);
|
||||
listItems.add(new ListItem(context.getResources().getString(R.string.other_languages), LIST_ITEM_TYPE_DIVIDER));
|
||||
addBooks(unselectedLanguages);
|
||||
} else {
|
||||
List<Book> selectedLanguages = Observable.fromIterable(allBooks)
|
||||
.filter(LibraryAdapter.this::languageActive)
|
||||
.filter(book -> !books.contains(book))
|
||||
// .filter(book -> !DownloadFragment.mDownloads.values().contains(book))
|
||||
.filter(book -> !LibraryFragment.downloadingBooks.contains(book))
|
||||
.filter(book -> !book.url.contains("/stack_exchange/")) // Temp filter see #694
|
||||
.flatMap(book -> getMatches(book, s.toString()))
|
||||
.toList()
|
||||
.blockingGet();
|
||||
|
||||
Collections.sort(selectedLanguages, new BookMatchComparator());
|
||||
|
||||
List<Book> unselectedLanguages = Observable.fromIterable(allBooks)
|
||||
.filter(book -> !languageActive(book))
|
||||
.filter(book -> !books.contains(book))
|
||||
// .filter(book -> !DownloadFragment.mDownloads.values().contains(book))
|
||||
.filter(book -> !LibraryFragment.downloadingBooks.contains(book))
|
||||
.filter(book -> !book.url.contains("/stack_exchange/")) // Temp filter see #694
|
||||
.flatMap(book -> getMatches(book, s.toString()))
|
||||
.toList()
|
||||
.blockingGet();
|
||||
|
||||
Collections.sort(unselectedLanguages, new BookMatchComparator());
|
||||
|
||||
listItems.add(new ListItem("In your language:", LIST_ITEM_TYPE_DIVIDER));
|
||||
addBooks(selectedLanguages);
|
||||
listItems.add(new ListItem("In other languages:", LIST_ITEM_TYPE_DIVIDER));
|
||||
addBooks(unselectedLanguages);
|
||||
}
|
||||
|
||||
FilterResults results = new FilterResults();
|
||||
results.values = listItems;
|
||||
results.count = listItems.size();
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
List<ListItem> filtered = (List<ListItem>) results.values;
|
||||
if (filtered != null) {
|
||||
if (filtered.isEmpty()) {
|
||||
addBooks(allBooks);
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return bookFilter;
|
||||
}
|
||||
|
||||
public void updateNetworkLanguages() {
|
||||
saveNetworkLanguages();
|
||||
}
|
||||
|
||||
private void updateLanguageCounts() {
|
||||
languageCounts.clear();
|
||||
for (Book book : allBooks) {
|
||||
Integer cnt = languageCounts.get(book.getLanguage());
|
||||
if (cnt == null) {
|
||||
languageCounts.put(book.getLanguage(), 1);
|
||||
} else {
|
||||
languageCounts.put(book.getLanguage(), cnt + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLanguages() {
|
||||
// Load previously stored languages and extract which ones were enabled. The new book list might
|
||||
// have new languages, or be missing some old ones so we want to refresh it, but retain user's
|
||||
// selections.
|
||||
Set<String> enabled_languages = new HashSet<>();
|
||||
for (Language language : networkLanguageDao.getFilteredLanguages()) {
|
||||
if (language.active) {
|
||||
enabled_languages.add(language.languageCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate languages with all available locales, which appear in the current list of all books.
|
||||
this.languages = new ArrayList<>();
|
||||
for (String iso_language : Locale.getISOLanguages()) {
|
||||
Locale locale = new Locale(iso_language);
|
||||
if (languageCounts.get(locale.getISO3Language()) != null) {
|
||||
// Enable this language either if it was enabled previously, or if it is the device language.
|
||||
if (enabled_languages.contains(locale.getISO3Language()) ||
|
||||
context.getResources().getConfiguration().locale.getISO3Language().equals(locale.getISO3Language())) {
|
||||
this.languages.add(new Language(locale, true));
|
||||
} else {
|
||||
this.languages.add(new Language(locale, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveNetworkLanguages();
|
||||
}
|
||||
|
||||
private void addBooks(List<Book> books) {
|
||||
for (Book book : books) {
|
||||
listItems.add(new ListItem(book, LIST_ITEM_TYPE_BOOK));
|
||||
}
|
||||
}
|
||||
|
||||
// Create a string that represents the size of the zim file in a human readable way
|
||||
public static String createGbString(String megaByte) {
|
||||
|
||||
int size = 0;
|
||||
try {
|
||||
size = Integer.parseInt(megaByte);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (size <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final String[] units = new String[]{"KB", "MB", "GB", "TB"};
|
||||
int conversion = (int) (Math.log10(size) / Math.log10(1024));
|
||||
return new DecimalFormat("#,##0.#")
|
||||
.format(size / Math.pow(1024, conversion))
|
||||
+ " "
|
||||
+ units[conversion];
|
||||
}
|
||||
|
||||
// Decode and create a Bitmap from the 64-Bit encoded favicon string
|
||||
public static Bitmap createBitmapFromEncodedString(String encodedString, Context context) {
|
||||
|
||||
try {
|
||||
byte[] decodedString = Base64.decode(encodedString, Base64.DEFAULT);
|
||||
return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return BitmapFactory.decodeResource(context.getResources(), R.mipmap.kiwix_icon);
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
|
||||
TextView title;
|
||||
|
||||
TextView description;
|
||||
|
||||
TextView language;
|
||||
|
||||
TextView creator;
|
||||
|
||||
TextView publisher;
|
||||
|
||||
TextView date;
|
||||
|
||||
TextView size;
|
||||
|
||||
TextView fileName;
|
||||
|
||||
ImageView favicon;
|
||||
}
|
||||
|
||||
private class ListItem {
|
||||
public Object data;
|
||||
public int type;
|
||||
|
||||
public ListItem(Object data, int type) {
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private class BookMatchComparator implements Comparator<Book> {
|
||||
public int compare(Book book1, Book book2) {
|
||||
return book2.searchMatches - book1.searchMatches;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Language {
|
||||
public String language;
|
||||
public String languageLocalized;
|
||||
public String languageCode;
|
||||
public String languageCodeISO2;
|
||||
public Boolean active;
|
||||
|
||||
Language(Locale locale, Boolean active) {
|
||||
this.language = locale.getDisplayLanguage();
|
||||
this.languageLocalized = locale.getDisplayLanguage(locale);
|
||||
this.languageCode = locale.getISO3Language();
|
||||
this.languageCodeISO2 = locale.getLanguage();
|
||||
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public Language(String languageCode, Boolean active) {
|
||||
this(new Locale(languageCode), active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return ((Language) obj).language.equals(language) &&
|
||||
((Language) obj).active.equals(active);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveNetworkLanguages() {
|
||||
if (saveNetworkLanguageDisposable != null && !saveNetworkLanguageDisposable.isDisposed()) {
|
||||
saveNetworkLanguageDisposable.dispose();
|
||||
}
|
||||
saveNetworkLanguageDisposable = Completable.fromAction(() -> networkLanguageDao.saveFilteredLanguages(languages))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe();
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ import org.simpleframework.xml.Root;
|
||||
public class LibraryNetworkEntity {
|
||||
|
||||
@ElementList(name = "book", inline = true, required = false)
|
||||
private LinkedList<Book> book;
|
||||
public LinkedList<Book> book;
|
||||
|
||||
@Attribute(name = "version", required = false)
|
||||
private String version;
|
||||
|
@ -17,12 +17,12 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.network;
|
||||
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
import org.kiwix.kiwixmobile.library.entity.MetaLinkNetworkEntity;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
import org.kiwix.kiwixmobile.library.entity.MetaLinkNetworkEntity;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
|
||||
@ -30,7 +30,7 @@ import retrofit2.http.GET;
|
||||
import retrofit2.http.Url;
|
||||
|
||||
public interface KiwixService {
|
||||
@GET("/library/library_zim.xml") Observable<LibraryNetworkEntity> getLibrary();
|
||||
@GET("/library/library_zim.xml") Flowable<LibraryNetworkEntity> getLibrary();
|
||||
|
||||
@GET Observable<MetaLinkNetworkEntity> getMetaLinks(@Url String url);
|
||||
|
||||
|
@ -16,7 +16,7 @@ sealed class KiwixDialog(
|
||||
open class YesNoDialog(
|
||||
title: Int,
|
||||
message: Int
|
||||
) : KiwixDialog(title, message, R.string.yes, R.string.no){
|
||||
) : KiwixDialog(title, message, R.string.yes, R.string.no) {
|
||||
object NoWifi : YesNoDialog(
|
||||
R.string.wifi_only_title, R.string.wifi_only_msg
|
||||
)
|
||||
@ -25,9 +25,8 @@ sealed class KiwixDialog(
|
||||
R.string.confirm_stop_download_title, R.string.confirm_stop_download_msg
|
||||
)
|
||||
|
||||
|
||||
object WifiOnly : YesNoDialog(
|
||||
R.string.wifi_only_title, R.string.wifi_only_msg
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Typeface;
|
||||
@ -33,7 +32,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language;
|
||||
import org.kiwix.kiwixmobile.utils.files.FileUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -45,7 +44,6 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import static org.kiwix.kiwixmobile.utils.Constants.PREF_LANG;
|
||||
import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
|
||||
|
||||
public class LanguageUtils {
|
||||
@ -239,11 +237,11 @@ public class LanguageUtils {
|
||||
return values;
|
||||
}
|
||||
|
||||
public List<LibraryAdapter.Language> getLanguageList() {
|
||||
List<LibraryAdapter.Language> values = new ArrayList<>();
|
||||
public List<Language> getLanguageList() {
|
||||
List<Language> values = new ArrayList<>();
|
||||
|
||||
for (LanguageContainer value : mLanguageList) {
|
||||
values.add(new LibraryAdapter.Language(value.getLanguageCode(), false));
|
||||
values.add(new Language(value.getLanguageCode(), false));
|
||||
}
|
||||
|
||||
return values;
|
||||
|
@ -27,6 +27,7 @@ import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.kiwix.kiwixmobile.ZimContentProvider;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
|
||||
@ -109,11 +110,13 @@ public class FileSearch {
|
||||
FilenameFilter[] filter = new FilenameFilter[zimFiles.length];
|
||||
|
||||
// Search all external directories that we can find.
|
||||
String[] tempRoots = new String[StorageDeviceUtils.getStorageDevices(context, false).size() + 2];
|
||||
final ArrayList<StorageDevice> storageDevices =
|
||||
StorageDeviceUtils.getStorageDevices(context, false);
|
||||
String[] tempRoots = new String[storageDevices.size() + 2];
|
||||
int j = 0;
|
||||
tempRoots[j++] = "/mnt";
|
||||
tempRoots[j++] = defaultPath;
|
||||
for (StorageDevice storageDevice : StorageDeviceUtils.getStorageDevices(context, false)) {
|
||||
for (StorageDevice storageDevice : storageDevices) {
|
||||
tempRoots[j++] = storageDevice.getName();
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language;
|
||||
import org.kiwix.kiwixmobile.utils.LanguageUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -46,7 +46,7 @@ public class LanguageSelectDialog extends AlertDialog {
|
||||
}
|
||||
|
||||
public static class Builder extends AlertDialog.Builder {
|
||||
private List<LibraryAdapter.Language> languages;
|
||||
private List<Language> languages;
|
||||
private Map<String, Integer> languageCounts;
|
||||
private boolean singleSelect = false;
|
||||
private String selectedLanguage;
|
||||
@ -60,7 +60,7 @@ public class LanguageSelectDialog extends AlertDialog {
|
||||
super(context, themeResId);
|
||||
}
|
||||
|
||||
public Builder setLanguages(List<LibraryAdapter.Language> languages) {
|
||||
public Builder setLanguages(List<Language> languages) {
|
||||
this.languages = languages;
|
||||
return this;
|
||||
}
|
||||
@ -114,13 +114,13 @@ public class LanguageSelectDialog extends AlertDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private static class LanguageArrayAdapter extends ArrayAdapter<LibraryAdapter.Language> {
|
||||
private static class LanguageArrayAdapter extends ArrayAdapter<Language> {
|
||||
private Map<String, Integer> languageCounts;
|
||||
private Context context;
|
||||
private boolean singleSelect;
|
||||
private String selectedLanguage;
|
||||
|
||||
public LanguageArrayAdapter(Context context, int textViewResourceId, List<LibraryAdapter.Language> languages,
|
||||
public LanguageArrayAdapter(Context context, int textViewResourceId, List<Language> languages,
|
||||
Map<String, Integer> languageCounts, boolean singleSelect, String selectedLanguage) {
|
||||
super(context, textViewResourceId, languages);
|
||||
this.languageCounts = languageCounts;
|
||||
@ -150,36 +150,36 @@ public class LanguageSelectDialog extends AlertDialog {
|
||||
// Set event listeners first, since updating the default values can trigger them.
|
||||
holder.row.setOnClickListener((view) -> holder.checkBox.toggle());
|
||||
holder.checkBox
|
||||
.setOnCheckedChangeListener((compoundButton, b) -> getItem(position).active = b);
|
||||
.setOnCheckedChangeListener((compoundButton, b) -> getItem(position).setActive(b));
|
||||
|
||||
LibraryAdapter.Language language = getItem(position);
|
||||
holder.language.setText(language.language);
|
||||
Language language = getItem(position);
|
||||
holder.language.setText(language.getLanguage());
|
||||
holder.languageLocalized.setText(context.getString(R.string.language_localized,
|
||||
language.languageLocalized));
|
||||
language.getLanguageLocalized()));
|
||||
holder.languageLocalized.setTypeface(Typeface.createFromAsset(context.getAssets(),
|
||||
LanguageUtils.getTypeface(language.languageCode)));
|
||||
LanguageUtils.getTypeface(language.getLanguageCode())));
|
||||
|
||||
if (languageCounts != null) {
|
||||
holder.languageEntriesCount.setText(context.getString(R.string.language_count,
|
||||
languageCounts.get(language.languageCode)));
|
||||
languageCounts.get(language.getLanguageCode())));
|
||||
} else {
|
||||
holder.languageEntriesCount.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!singleSelect) {
|
||||
holder.checkBox.setChecked(language.active);
|
||||
holder.checkBox.setChecked(language.getActive());
|
||||
} else {
|
||||
holder.checkBox.setClickable(false);
|
||||
holder.checkBox.setFocusable(false);
|
||||
|
||||
if (getSelectedLanguage().equalsIgnoreCase(language.languageCodeISO2)) {
|
||||
if (getSelectedLanguage().equalsIgnoreCase(language.getLanguageCodeISO2())) {
|
||||
holder.checkBox.setChecked(true);
|
||||
} else {
|
||||
holder.checkBox.setChecked(false);
|
||||
}
|
||||
|
||||
convertView.setOnClickListener((v -> {
|
||||
setSelectedLanguage(language.languageCodeISO2);
|
||||
setSelectedLanguage(language.getLanguageCodeISO2());
|
||||
notifyDataSetChanged();
|
||||
}));
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
abstract class BaseBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
abstract val action:String
|
||||
|
||||
override fun onReceive(
|
||||
context: Context,
|
||||
intent: Intent?
|
||||
) {
|
||||
if (intent?.action == action) {
|
||||
onIntentWithActionReceived(context, intent)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun onIntentWithActionReceived(
|
||||
context: Context,
|
||||
intent: Intent
|
||||
)
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.ConnectivityManager
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import org.kiwix.kiwixmobile.extensions.networkState
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConnectivityBroadcastReceiver @Inject constructor(private val connectivityManager: ConnectivityManager) :
|
||||
BaseBroadcastReceiver() {
|
||||
|
||||
override val action: String = ConnectivityManager.CONNECTIVITY_ACTION
|
||||
|
||||
private val _networkStates =
|
||||
PublishProcessor.create<NetworkState>()
|
||||
val networkStates = _networkStates.startWith(connectivityManager.networkState)
|
||||
|
||||
override fun onIntentWithActionReceived(
|
||||
context: Context,
|
||||
intent: Intent
|
||||
) {
|
||||
_networkStates.onNext(connectivityManager.networkState)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager
|
||||
|
||||
enum class NetworkState {
|
||||
CONNECTED,
|
||||
NOT_CONNECTED
|
||||
}
|
@ -33,7 +33,6 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
import java.io.File;
|
||||
import javax.inject.Inject;
|
||||
import org.kiwix.kiwixmobile.KiwixMobileActivity;
|
||||
@ -217,9 +216,9 @@ public class ZimManageActivity extends BaseActivity implements ZimManageViewCall
|
||||
public boolean onQueryTextChange(String s) {
|
||||
searchQuery = s;
|
||||
|
||||
if (mSectionsPagerAdapter.libraryFragment.libraryAdapter != null) {
|
||||
mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter().filter(searchQuery);
|
||||
}
|
||||
//if (mSectionsPagerAdapter.libraryFragment.libraryAdapter != null) {
|
||||
// mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter().filter(searchQuery);
|
||||
//}
|
||||
mViewPager.setCurrentItem(1);
|
||||
return true;
|
||||
}
|
||||
@ -235,11 +234,11 @@ public class ZimManageActivity extends BaseActivity implements ZimManageViewCall
|
||||
switch (item.getItemId()) {
|
||||
case R.id.select_language:
|
||||
if (mViewPager.getCurrentItem() == 1) {
|
||||
if(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languages.size() == 0) {
|
||||
Toast.makeText(this, R.string.wait_for_load, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
showLanguageSelect();
|
||||
}
|
||||
//if(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languages.size() == 0) {
|
||||
// Toast.makeText(this, R.string.wait_for_load, Toast.LENGTH_LONG).show();
|
||||
//} else {
|
||||
// showLanguageSelect();
|
||||
//}
|
||||
}
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
@ -262,11 +261,11 @@ public class ZimManageActivity extends BaseActivity implements ZimManageViewCall
|
||||
|
||||
private void showLanguageSelect() {
|
||||
new LanguageSelectDialog.Builder(this, dialogStyle())
|
||||
.setLanguages(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languages)
|
||||
.setLanguageCounts(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languageCounts)
|
||||
//.setLanguages(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languages)
|
||||
//.setLanguageCounts(mSectionsPagerAdapter.libraryFragment.libraryAdapter.languageCounts)
|
||||
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
|
||||
mSectionsPagerAdapter.libraryFragment.libraryAdapter.updateNetworkLanguages();
|
||||
mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter().filter(searchQuery);
|
||||
//mSectionsPagerAdapter.libraryFragment.libraryAdapter.updateNetworkLanguages();
|
||||
//mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter().filter(searchQuery);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
@ -1,22 +1,35 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager
|
||||
|
||||
import android.app.Application
|
||||
import android.arch.lifecycle.MutableLiveData
|
||||
import android.arch.lifecycle.ViewModel
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.functions.Function4
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.kiwix.kiwixmobile.R.string
|
||||
import org.kiwix.kiwixmobile.database.BookDao
|
||||
import org.kiwix.kiwixmobile.database.DownloadDao
|
||||
import org.kiwix.kiwixmobile.database.NetworkLanguageDao
|
||||
import org.kiwix.kiwixmobile.downloader.Downloader
|
||||
import org.kiwix.kiwixmobile.downloader.model.DownloadItem
|
||||
import org.kiwix.kiwixmobile.downloader.model.DownloadModel
|
||||
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Successful
|
||||
import org.kiwix.kiwixmobile.downloader.model.DownloadStatus
|
||||
import org.kiwix.kiwixmobile.extensions.registerReceiver
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.network.KiwixService
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.StorageObserver
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
|
||||
import java.util.LinkedList
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -40,30 +53,160 @@ import javax.inject.Inject
|
||||
class ZimManageViewModel @Inject constructor(
|
||||
private val downloadDao: DownloadDao,
|
||||
private val bookDao: BookDao,
|
||||
private val languageDao: NetworkLanguageDao,
|
||||
private val downloader: Downloader,
|
||||
private val storageObserver: StorageObserver
|
||||
private val storageObserver: StorageObserver,
|
||||
private val kiwixService: KiwixService,
|
||||
private val context: Application,
|
||||
private val connectivityBroadcastReceiver: ConnectivityBroadcastReceiver
|
||||
) : ViewModel() {
|
||||
|
||||
val libraryItems: MutableLiveData<List<LibraryListItem>> = MutableLiveData()
|
||||
val downloadItems: MutableLiveData<List<DownloadItem>> = MutableLiveData()
|
||||
val bookItems: MutableLiveData<List<Book>> = MutableLiveData()
|
||||
val checkFileSystem = PublishProcessor.create<Unit>()
|
||||
val deviceListIsRefreshing = MutableLiveData<Boolean>()
|
||||
val libraryListIsRefreshing = MutableLiveData<Boolean>()
|
||||
val networkStates = MutableLiveData<NetworkState>()
|
||||
|
||||
val requestFileSystemCheck = PublishProcessor.create<Unit>()
|
||||
val requestDownloadLibrary = PublishProcessor.create<Unit>()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
val downloadStatuses = downloadStatuses()
|
||||
val booksFromDao = books()
|
||||
compositeDisposable.addAll(
|
||||
compositeDisposable.addAll(*disposables())
|
||||
requestDownloadLibrary.onNext(Unit)
|
||||
context.registerReceiver(connectivityBroadcastReceiver)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
compositeDisposable.clear()
|
||||
context.unregisterReceiver(connectivityBroadcastReceiver)
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
private fun disposables(): Array<Disposable> {
|
||||
val downloads: Flowable<MutableList<DownloadModel>> = downloadDao.downloads()
|
||||
val downloadStatuses = downloadStatuses(downloads)
|
||||
val booksFromDao: Flowable<List<Book>> = books()
|
||||
val library = libraryFromNetwork()
|
||||
return arrayOf(
|
||||
updateDownloadItems(downloadStatuses),
|
||||
removeCompletedDownloadsFromDb(downloadStatuses),
|
||||
updateBookItems(booksFromDao),
|
||||
checkFileSystemForBooksOnRequest(booksFromDao)
|
||||
checkFileSystemForBooksOnRequest(booksFromDao),
|
||||
updateLibraryItems(booksFromDao, downloads, library),
|
||||
updateActiveLanguages(library),
|
||||
updateNetworkStates()
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkFileSystemForBooksOnRequest(booksFromDao: Flowable<List<Book>>): Disposable? {
|
||||
return checkFileSystem
|
||||
private fun updateNetworkStates() =
|
||||
connectivityBroadcastReceiver.networkStates.subscribe(
|
||||
networkStates::postValue, Throwable::printStackTrace
|
||||
)
|
||||
|
||||
private fun libraryFromNetwork() =
|
||||
Flowable.combineLatest(
|
||||
requestDownloadLibrary,
|
||||
connectivityBroadcastReceiver.networkStates.filter(
|
||||
NetworkState.CONNECTED::equals
|
||||
),
|
||||
BiFunction<Unit, NetworkState, Unit> { _, _ -> Unit }
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnNext { libraryListIsRefreshing.postValue(true) }
|
||||
.switchMap { kiwixService.library }
|
||||
.doOnError(Throwable::printStackTrace)
|
||||
.onErrorResumeNext(Flowable.just(LibraryNetworkEntity().apply { book = LinkedList() }))
|
||||
.doOnNext { libraryListIsRefreshing.postValue(false) }
|
||||
|
||||
private fun updateLibraryItems(
|
||||
booksFromDao: Flowable<List<Book>>,
|
||||
downloads: Flowable<MutableList<DownloadModel>>,
|
||||
library: Flowable<LibraryNetworkEntity>?
|
||||
) = Flowable.combineLatest(
|
||||
booksFromDao,
|
||||
downloads,
|
||||
languageDao.activeLanguages().filter { it.isNotEmpty() },
|
||||
library,
|
||||
Function4(this::combineLibrarySources)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(
|
||||
libraryItems::postValue,
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
|
||||
private fun updateActiveLanguages(library: Flowable<LibraryNetworkEntity>) = library
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { it.books }
|
||||
.withLatestFrom(
|
||||
languageDao.activeLanguages(),
|
||||
BiFunction(this::combineToLanguageList)
|
||||
)
|
||||
.subscribe(
|
||||
languageDao::saveFilteredLanguages,
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
|
||||
private fun combineToLanguageList(
|
||||
booksFromNetwork: List<Book>,
|
||||
activeLanguages: List<Language>
|
||||
): List<Language> {
|
||||
val languagesFromNetwork = booksFromNetwork.distinctBy { it.language }
|
||||
.map { it.language }
|
||||
return Locale.getISOLanguages()
|
||||
.map { Locale(it) }
|
||||
.filter { languagesFromNetwork.contains(it.isO3Language) }
|
||||
.map { locale ->
|
||||
Language(
|
||||
locale.isO3Language,
|
||||
languageWasPreviouslyActiveOrIsPrimaryLanguage(activeLanguages, locale)
|
||||
)
|
||||
}
|
||||
.ifEmpty { listOf(Language(context.resources.configuration.locale.isO3Language, true)) }
|
||||
}
|
||||
|
||||
private fun languageWasPreviouslyActiveOrIsPrimaryLanguage(
|
||||
activeLanguages: List<Language>,
|
||||
locale: Locale
|
||||
) = activeLanguages.firstOrNull { it.languageCode == locale.isO3Language }?.let { true }
|
||||
?: isPrimaryLocale(locale)
|
||||
|
||||
private fun isPrimaryLocale(locale: Locale) =
|
||||
context.resources.configuration.locale.isO3Language == locale.isO3Language
|
||||
|
||||
private fun combineLibrarySources(
|
||||
booksOnFileSystem: List<Book>,
|
||||
activeDownloads: List<DownloadModel>,
|
||||
activeLanguages: List<Language>,
|
||||
libraryNetworkEntity: LibraryNetworkEntity
|
||||
): List<LibraryListItem> {
|
||||
val downloadedBooksIds = booksOnFileSystem.map { it.id }
|
||||
val downloadingBookIds = activeDownloads.map { it.bookId }
|
||||
val activeLanguageCodes = activeLanguages.map { it.languageCode }
|
||||
val booksUnfilteredByLanguage = libraryNetworkEntity.books
|
||||
.filterNot { downloadedBooksIds.contains(it.id) }
|
||||
.filterNot { downloadingBookIds.contains(it.id) }
|
||||
.filterNot { it.url.contains("/stack_exchange/") }// Temp filter see #694
|
||||
return listOf(
|
||||
DividerItem(Long.MAX_VALUE, context.getString(string.your_languages)),
|
||||
*toBookItems(
|
||||
booksUnfilteredByLanguage.filter { activeLanguageCodes.contains(it.language) }
|
||||
),
|
||||
DividerItem(Long.MIN_VALUE, context.getString(string.other_languages)),
|
||||
*toBookItems(
|
||||
booksUnfilteredByLanguage.filterNot { activeLanguageCodes.contains(it.language) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun toBookItems(books: List<Book>) =
|
||||
books.map { BookItem(it) }.toTypedArray()
|
||||
|
||||
private fun checkFileSystemForBooksOnRequest(booksFromDao: Flowable<List<Book>>) =
|
||||
requestFileSystemCheck
|
||||
.doOnNext { deviceListIsRefreshing.postValue(true) }
|
||||
.switchMap {
|
||||
updateBookDaoFromFilesystem(booksFromDao)
|
||||
@ -73,20 +216,24 @@ class ZimManageViewModel @Inject constructor(
|
||||
bookDao::saveBooks,
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
}
|
||||
|
||||
private fun books() = bookDao.books()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { it.sortedBy { book -> book.title } }
|
||||
|
||||
private fun updateBookDaoFromFilesystem(booksFromDao: Flowable<List<Book>>) =
|
||||
storageObserver.booksOnFileSystem.withLatestFrom(
|
||||
booksFromDao,
|
||||
BiFunction<Collection<Book>, List<Book>, List<Book>> { booksFileSystem, booksDao ->
|
||||
booksFileSystem.minus(
|
||||
booksDao
|
||||
)
|
||||
})
|
||||
storageObserver.booksOnFileSystem
|
||||
.withLatestFrom(
|
||||
booksFromDao,
|
||||
BiFunction(this::removeBooksAlreadyInDao)
|
||||
)
|
||||
|
||||
private fun removeBooksAlreadyInDao(
|
||||
booksFromFileSystem: Collection<Book>,
|
||||
booksFromDao: List<Book>
|
||||
) = booksFromFileSystem.minus(
|
||||
booksFromDao
|
||||
)
|
||||
|
||||
private fun updateBookItems(booksFromDao: Flowable<List<Book>>) =
|
||||
booksFromDao
|
||||
@ -113,17 +260,13 @@ class ZimManageViewModel @Inject constructor(
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
|
||||
private fun downloadStatuses() = Flowable.combineLatest(
|
||||
downloadDao.downloads(),
|
||||
Flowable.interval(1, SECONDS),
|
||||
BiFunction { downloadModels: List<DownloadModel>, _: Long -> downloadModels }
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map(downloader::queryStatus)
|
||||
.distinctUntilChanged()
|
||||
|
||||
override fun onCleared() {
|
||||
compositeDisposable.clear()
|
||||
super.onCleared()
|
||||
}
|
||||
private fun downloadStatuses(downloads: Flowable<MutableList<DownloadModel>>) =
|
||||
Flowable.combineLatest(
|
||||
downloads,
|
||||
Flowable.interval(1, SECONDS),
|
||||
BiFunction { downloadModels: List<DownloadModel>, _: Long -> downloadModels }
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map(downloader::queryStatus)
|
||||
.distinctUntilChanged()
|
||||
}
|
@ -8,11 +8,11 @@ import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||
|
||||
// The Adapter for the ListView for when the ListView is populated with the rescanned files
|
||||
public class RescanDataAdapter(
|
||||
val bookUtils: BookUtils,
|
||||
val onItemClick: (Book) -> Unit,
|
||||
val onItemLongClick: (Book) -> Unit
|
||||
) : RecyclerView.Adapter<RescanViewHolder>() {
|
||||
class BooksAdapter(
|
||||
private val bookUtils: BookUtils,
|
||||
private val onItemClick: (Book) -> Unit,
|
||||
private val onItemLongClick: (Book) -> Unit
|
||||
) : RecyclerView.Adapter<BooksViewHolder>() {
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
@ -29,12 +29,12 @@ public class RescanDataAdapter(
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
) = RescanViewHolder(parent.inflate(layout.library_item, false), bookUtils)
|
||||
) = BooksViewHolder(parent.inflate(layout.library_item, false), bookUtils)
|
||||
|
||||
override fun getItemCount() = itemList.size
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: RescanViewHolder,
|
||||
holder: BooksViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
holder.bind(itemList[position], onItemClick, onItemLongClick)
|
@ -2,9 +2,7 @@ package org.kiwix.kiwixmobile.zim_manager.fileselect_view
|
||||
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.TextView
|
||||
import butterknife.internal.DebouncingOnClickListener
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.library_item.creator
|
||||
import kotlinx.android.synthetic.main.library_item.date
|
||||
@ -18,13 +16,15 @@ import kotlinx.android.synthetic.main.library_item.title
|
||||
import org.kiwix.kiwixmobile.KiwixApplication
|
||||
import org.kiwix.kiwixmobile.downloader.model.Base64String
|
||||
import org.kiwix.kiwixmobile.extensions.setBitmap
|
||||
import org.kiwix.kiwixmobile.extensions.setTextAndVisibility
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.utils.NetworkUtils
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.MegaByte
|
||||
|
||||
class RescanViewHolder(
|
||||
class BooksViewHolder(
|
||||
override val containerView: View,
|
||||
val bookUtils: BookUtils
|
||||
private val bookUtils: BookUtils
|
||||
) : ViewHolder(containerView),
|
||||
LayoutContainer {
|
||||
fun bind(
|
||||
@ -37,7 +37,7 @@ class RescanViewHolder(
|
||||
creator.setTextAndVisibility(book.creator)
|
||||
publisher.setTextAndVisibility(book.publisher)
|
||||
date.setTextAndVisibility(book.date)
|
||||
size.setTextAndVisibility(book.size)
|
||||
size.setTextAndVisibility(MegaByte(book.size).humanReadable)
|
||||
language.text = bookUtils.getLanguage(book.getLanguage())
|
||||
fileName.text = NetworkUtils.parseURL(
|
||||
KiwixApplication.getInstance(), book.file.path
|
||||
@ -52,13 +52,6 @@ class RescanViewHolder(
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
private fun TextView.setTextAndVisibility(title: String?) =
|
||||
if (title != null && title.isNotEmpty()) {
|
||||
text = title
|
||||
visibility = VISIBLE
|
||||
} else {
|
||||
visibility = GONE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -10,15 +10,15 @@ import org.kiwix.kiwixmobile.utils.files.FileSearch.ResultListener
|
||||
import javax.inject.Inject
|
||||
|
||||
class StorageObserver @Inject constructor(
|
||||
val context: Context,
|
||||
val sharedPreferenceUtil: SharedPreferenceUtil
|
||||
private val context: Context,
|
||||
private val sharedPreferenceUtil: SharedPreferenceUtil
|
||||
) {
|
||||
|
||||
private val _booksOnFileSystem = PublishProcessor.create<Collection<Book>>()
|
||||
val booksOnFileSystem = _booksOnFileSystem.distinctUntilChanged()
|
||||
.doOnSubscribe { scanFiles() }
|
||||
|
||||
fun scanFiles() {
|
||||
private fun scanFiles() {
|
||||
FileSearch(context, object : ResultListener {
|
||||
val foundBooks = mutableSetOf<Book>()
|
||||
override fun onBookFound(book: Book) {
|
||||
|
@ -63,8 +63,8 @@ class ZimFileSelectFragment : BaseFragment() {
|
||||
|
||||
private lateinit var zimManageViewModel: ZimManageViewModel
|
||||
|
||||
private val rescanAdapter: RescanDataAdapter by lazy {
|
||||
RescanDataAdapter(
|
||||
private val booksAdapter: BooksAdapter by lazy {
|
||||
BooksAdapter(
|
||||
bookUtils, this::open, this::tryToDelete
|
||||
)
|
||||
}
|
||||
@ -92,12 +92,12 @@ class ZimFileSelectFragment : BaseFragment() {
|
||||
.get(ZimManageViewModel::class.java)
|
||||
zim_swiperefresh.setOnRefreshListener(this::requestFileSystemCheck)
|
||||
zimfilelist.run {
|
||||
adapter = rescanAdapter
|
||||
adapter = booksAdapter
|
||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
setHasFixedSize(true)
|
||||
}
|
||||
zimManageViewModel.bookItems.observe(this, Observer {
|
||||
rescanAdapter.itemList = it!!
|
||||
booksAdapter.itemList = it!!
|
||||
checkEmpty(it)
|
||||
})
|
||||
zimManageViewModel.deviceListIsRefreshing.observe(this, Observer {
|
||||
@ -151,7 +151,7 @@ class ZimFileSelectFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
private fun requestFileSystemCheck() {
|
||||
zimManageViewModel.checkFileSystem.onNext(Unit)
|
||||
zimManageViewModel.requestFileSystemCheck.onNext(Unit)
|
||||
}
|
||||
|
||||
private fun open(it: Book) {
|
||||
|
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (C) 2018 Kiwix <android.kiwix.org>
|
||||
*
|
||||
* 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 org.kiwix.kiwixmobile.zim_manager.library_view;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import eu.mhutti1.utils.storage.StorageDevice;
|
||||
import eu.mhutti1.utils.storage.support.StorageSelectDialog;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.kiwix.kiwixmobile.KiwixMobileActivity;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
import org.kiwix.kiwixmobile.base.BaseFragment;
|
||||
import org.kiwix.kiwixmobile.di.components.ActivityComponent;
|
||||
import org.kiwix.kiwixmobile.di.components.ApplicationComponent;
|
||||
import org.kiwix.kiwixmobile.downloader.DownloadService;
|
||||
import org.kiwix.kiwixmobile.downloader.Downloader;
|
||||
import org.kiwix.kiwixmobile.library.LibraryAdapter;
|
||||
import org.kiwix.kiwixmobile.utils.NetworkUtils;
|
||||
import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil;
|
||||
import org.kiwix.kiwixmobile.utils.StyleUtils;
|
||||
import org.kiwix.kiwixmobile.utils.TestingUtils;
|
||||
import org.kiwix.kiwixmobile.zim_manager.ZimManageActivity;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
|
||||
|
||||
public class LibraryFragment extends BaseFragment
|
||||
implements AdapterView.OnItemClickListener, StorageSelectDialog.OnSelectListener, LibraryViewCallback {
|
||||
|
||||
@BindView(R.id.library_list)
|
||||
ListView libraryList;
|
||||
|
||||
@BindView(R.id.network_permission_text)
|
||||
TextView networkText;
|
||||
@BindView(R.id.network_permission_button)
|
||||
Button permissionButton;
|
||||
|
||||
public LinearLayout llLayout;
|
||||
|
||||
@BindView(R.id.library_swiperefresh)
|
||||
SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
||||
private ArrayList<Book> books = new ArrayList<>();
|
||||
|
||||
public static DownloadService mService = new DownloadService();
|
||||
public LibraryAdapter libraryAdapter;
|
||||
|
||||
@Inject
|
||||
ConnectivityManager conMan;
|
||||
|
||||
@Inject
|
||||
Downloader downloader;
|
||||
|
||||
private ZimManageActivity faActivity;
|
||||
|
||||
public static NetworkBroadcastReceiver networkBroadcastReceiver;
|
||||
|
||||
public static List<Book> downloadingBooks = new ArrayList<>();
|
||||
|
||||
public static boolean isReceiverRegistered = false;
|
||||
|
||||
@Inject
|
||||
LibraryPresenter presenter;
|
||||
|
||||
@Inject
|
||||
SharedPreferenceUtil sharedPreferenceUtil;
|
||||
|
||||
@Override
|
||||
public void inject(@NotNull ActivityComponent activityComponent) {
|
||||
activityComponent.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
TestingUtils.bindResource(LibraryFragment.class);
|
||||
llLayout = (LinearLayout) inflater.inflate(R.layout.activity_library, container, false);
|
||||
ButterKnife.bind(this, llLayout);
|
||||
presenter.attachView(this);
|
||||
|
||||
networkText = llLayout.findViewById(R.id.network_text);
|
||||
|
||||
faActivity = (ZimManageActivity) super.getActivity();
|
||||
swipeRefreshLayout.setOnRefreshListener(() -> refreshFragment());
|
||||
libraryAdapter = new LibraryAdapter(super.getContext());
|
||||
libraryList.setAdapter(libraryAdapter);
|
||||
|
||||
|
||||
|
||||
NetworkInfo network = conMan.getActiveNetworkInfo();
|
||||
if (network == null || !network.isConnected()) {
|
||||
displayNoNetworkConnection();
|
||||
}
|
||||
|
||||
networkBroadcastReceiver = new NetworkBroadcastReceiver();
|
||||
faActivity.registerReceiver(networkBroadcastReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
isReceiverRegistered = true;
|
||||
|
||||
presenter.loadRunningDownloadsFromDb();
|
||||
return llLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (isReceiverRegistered) {
|
||||
faActivity.unregisterReceiver(networkBroadcastReceiver);
|
||||
isReceiverRegistered = false;
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBooks(LinkedList<Book> books) {
|
||||
if (books == null) {
|
||||
displayNoItemsAvailable();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i("kiwix-showBooks", "Contains:" + books.size());
|
||||
libraryAdapter.setAllBooks(books);
|
||||
if (faActivity.searchView != null) {
|
||||
libraryAdapter.getFilter().filter(
|
||||
faActivity.searchView.getQuery(),
|
||||
i -> stopScanningContent());
|
||||
} else {
|
||||
libraryAdapter.getFilter().filter("", i -> stopScanningContent());
|
||||
}
|
||||
libraryAdapter.notifyDataSetChanged();
|
||||
libraryList.setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayNoNetworkConnection() {
|
||||
if (books.size() != 0) {
|
||||
Toast.makeText(super.getActivity(), R.string.no_network_connection, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
networkText.setText(R.string.no_network_connection);
|
||||
networkText.setVisibility(View.VISIBLE);
|
||||
permissionButton.setVisibility(GONE);
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
swipeRefreshLayout.setEnabled(false);
|
||||
libraryList.setVisibility(View.INVISIBLE);
|
||||
TestingUtils.unbindResource(LibraryFragment.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayNoItemsFound() {
|
||||
networkText.setText(R.string.no_items_msg);
|
||||
networkText.setVisibility(View.VISIBLE);
|
||||
permissionButton.setVisibility(GONE);
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
TestingUtils.unbindResource(LibraryFragment.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayNoItemsAvailable() {
|
||||
if (books.size() != 0) {
|
||||
Toast.makeText(super.getActivity(), R.string.no_items_available, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
networkText.setText(R.string.no_items_available);
|
||||
networkText.setVisibility(View.VISIBLE);
|
||||
permissionButton.setVisibility(View.GONE);
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
TestingUtils.unbindResource(LibraryFragment.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayScanningContent() {
|
||||
if (!swipeRefreshLayout.isRefreshing()) {
|
||||
networkText.setVisibility(GONE);
|
||||
permissionButton.setVisibility(GONE);
|
||||
swipeRefreshLayout.setEnabled(true);
|
||||
swipeRefreshLayout.setRefreshing(true);
|
||||
TestingUtils.bindResource(LibraryFragment.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stopScanningContent() {
|
||||
networkText.setVisibility(GONE);
|
||||
permissionButton.setVisibility(GONE);
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
TestingUtils.unbindResource(LibraryFragment.class);
|
||||
}
|
||||
|
||||
public void refreshFragment() {
|
||||
NetworkInfo network = conMan.getActiveNetworkInfo();
|
||||
if (network == null || !network.isConnected()) {
|
||||
Toast.makeText(super.getActivity(), R.string.no_network_connection, Toast.LENGTH_LONG).show();
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
return;
|
||||
}
|
||||
networkBroadcastReceiver.onReceive(super.getActivity(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (!libraryAdapter.isDivider(position)) {
|
||||
if (getSpaceAvailable()
|
||||
< Long.parseLong(((Book) (parent.getAdapter().getItem(position))).getSize()) * 1024f) {
|
||||
Toast.makeText(super.getActivity(), getString(R.string.download_no_space)
|
||||
+ "\n" + getString(R.string.space_available) + " "
|
||||
+ LibraryUtils.bytesToHuman(getSpaceAvailable()), Toast.LENGTH_LONG).show();
|
||||
Snackbar snackbar = Snackbar.make(libraryList,
|
||||
getString(R.string.download_change_storage),
|
||||
Snackbar.LENGTH_LONG)
|
||||
.setAction(getString(R.string.open), v -> {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
StorageSelectDialog dialogFragment = new StorageSelectDialog();
|
||||
Bundle b = new Bundle();
|
||||
b.putString(StorageSelectDialog.STORAGE_DIALOG_INTERNAL, getResources().getString(R.string.internal_storage));
|
||||
b.putString(StorageSelectDialog.STORAGE_DIALOG_EXTERNAL, getResources().getString(R.string.external_storage));
|
||||
b.putInt(StorageSelectDialog.STORAGE_DIALOG_THEME, StyleUtils.dialogStyle());
|
||||
dialogFragment.setArguments(b);
|
||||
dialogFragment.setOnSelectListener(this);
|
||||
dialogFragment.show(fm, getResources().getString(R.string.pref_storage));
|
||||
});
|
||||
snackbar.setActionTextColor(Color.WHITE);
|
||||
snackbar.show();
|
||||
return;
|
||||
}
|
||||
|
||||
// if (DownloadFragment.mDownloadFiles
|
||||
// .containsValue(KIWIX_ROOT + StorageUtils.getFileNameFromUrl(((Book) parent.getAdapter()
|
||||
// .getItem(position)).getUrl()))) {
|
||||
// Toast.makeText(super.getActivity(), getString(R.string.zim_already_downloading), Toast.LENGTH_LONG)
|
||||
// .show();
|
||||
// } else {
|
||||
//
|
||||
// NetworkInfo network = conMan.getActiveNetworkInfo();
|
||||
// if (network == null || !network.isConnected()) {
|
||||
// Toast.makeText(super.getActivity(), getString(R.string.no_network_connection), Toast.LENGTH_LONG)
|
||||
// .show();
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (KiwixMobileActivity.wifiOnly && !NetworkUtils.isWiFi(getContext())) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.wifi_only_title)
|
||||
.setMessage(R.string.wifi_only_msg)
|
||||
.setPositiveButton(R.string.yes, (dialog, i) -> {
|
||||
sharedPreferenceUtil.putPrefWifiOnly(false);
|
||||
KiwixMobileActivity.wifiOnly = false;
|
||||
downloadFile((Book) parent.getAdapter().getItem(position));
|
||||
})
|
||||
.setNegativeButton(R.string.no, (dialog, i) -> {
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
downloadFile((Book) parent.getAdapter().getItem(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadFile(Book book) {
|
||||
downloader.download(book);
|
||||
// downloadingBooks.add(book);
|
||||
// if (libraryAdapter != null && faActivity != null && faActivity.searchView != null) {
|
||||
// libraryAdapter.getFilter().filter(faActivity.searchView.getQuery());
|
||||
// }
|
||||
// Toast.makeText(super.getActivity(), getString(R.string.download_started_library), Toast.LENGTH_LONG)
|
||||
// .show();
|
||||
//
|
||||
// ZimManageActivity manage = (ZimManageActivity) super.getActivity();
|
||||
// manage.displayDownloadInterface();
|
||||
}
|
||||
|
||||
public long getSpaceAvailable() {
|
||||
return new File(sharedPreferenceUtil.getPrefStorage()).getFreeSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectionCallback(StorageDevice storageDevice) {
|
||||
sharedPreferenceUtil.putPrefStorage(storageDevice.getName());
|
||||
if (storageDevice.isInternal()) {
|
||||
sharedPreferenceUtil.putPrefStorageTitle(getResources().getString(R.string.internal_storage));
|
||||
} else {
|
||||
sharedPreferenceUtil.putPrefStorageTitle(getResources().getString(R.string.external_storage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class NetworkBroadcastReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
NetworkInfo network = conMan.getActiveNetworkInfo();
|
||||
|
||||
if (network == null || !network.isConnected()) {
|
||||
displayNoNetworkConnection();
|
||||
}
|
||||
|
||||
if ((books == null || books.isEmpty()) && network != null && network.isConnected()) {
|
||||
presenter.loadBooks();
|
||||
permissionButton.setVisibility(GONE);
|
||||
networkText.setVisibility(GONE);
|
||||
libraryList.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (C) 2018 Kiwix <android.kiwix.org>
|
||||
*
|
||||
* 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 org.kiwix.kiwixmobile.zim_manager.library_view
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.arch.lifecycle.ViewModelProvider
|
||||
import android.arch.lifecycle.ViewModelProviders
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import eu.mhutti1.utils.storage.StorageDevice
|
||||
import eu.mhutti1.utils.storage.support.StorageSelectDialog
|
||||
import kotlinx.android.synthetic.main.activity_library.libraryErrorText
|
||||
import kotlinx.android.synthetic.main.activity_library.libraryList
|
||||
import kotlinx.android.synthetic.main.activity_library.librarySwipeRefresh
|
||||
import org.kiwix.kiwixmobile.KiwixMobileActivity
|
||||
import org.kiwix.kiwixmobile.R
|
||||
import org.kiwix.kiwixmobile.R.string
|
||||
import org.kiwix.kiwixmobile.base.BaseFragment
|
||||
import org.kiwix.kiwixmobile.di.components.ActivityComponent
|
||||
import org.kiwix.kiwixmobile.downloader.Downloader
|
||||
import org.kiwix.kiwixmobile.extensions.snack
|
||||
import org.kiwix.kiwixmobile.extensions.toast
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.utils.DialogShower
|
||||
import org.kiwix.kiwixmobile.utils.KiwixDialog.YesNoDialog.WifiOnly
|
||||
import org.kiwix.kiwixmobile.utils.NetworkUtils
|
||||
import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil
|
||||
import org.kiwix.kiwixmobile.utils.StyleUtils
|
||||
import org.kiwix.kiwixmobile.utils.TestingUtils
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState.CONNECTED
|
||||
import org.kiwix.kiwixmobile.zim_manager.NetworkState.NOT_CONNECTED
|
||||
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryAdapter
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryDelegate.BookDelegate
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryDelegate.DividerDelegate
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class LibraryFragment : BaseFragment() {
|
||||
|
||||
@Inject lateinit var conMan: ConnectivityManager
|
||||
@Inject lateinit var downloader: Downloader
|
||||
@Inject lateinit var sharedPreferenceUtil: SharedPreferenceUtil
|
||||
@Inject lateinit var dialogShower: DialogShower
|
||||
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||
@Inject lateinit var bookUtils: BookUtils
|
||||
private lateinit var zimManageViewModel: ZimManageViewModel
|
||||
|
||||
private val libraryAdapter: LibraryAdapter by lazy {
|
||||
LibraryAdapter(
|
||||
delegates = *arrayOf(BookDelegate(bookUtils, this::onBookItemClick), DividerDelegate)
|
||||
)
|
||||
}
|
||||
|
||||
private val spaceAvailable: Long
|
||||
get() = File(sharedPreferenceUtil.prefStorage).freeSpace
|
||||
|
||||
private val noWifiWithWifiOnlyPreferenceSet
|
||||
get() = sharedPreferenceUtil.prefWifiOnly && !NetworkUtils.isWiFi(context!!)
|
||||
|
||||
private val isNotConnected get() = conMan.activeNetworkInfo?.isConnected?.not() ?: true
|
||||
|
||||
override fun inject(activityComponent: ActivityComponent) {
|
||||
activityComponent.inject(this)
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
zimManageViewModel = ViewModelProviders.of(activity!!, viewModelFactory)
|
||||
.get(ZimManageViewModel::class.java)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
TestingUtils.bindResource(LibraryFragment::class.java)
|
||||
return inflater.inflate(R.layout.activity_library, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
librarySwipeRefresh.setOnRefreshListener { refreshFragment() }
|
||||
libraryList.run {
|
||||
adapter = libraryAdapter
|
||||
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
setHasFixedSize(true)
|
||||
}
|
||||
zimManageViewModel.libraryItems.observe(this, Observer(this::onLibraryItemsChange))
|
||||
zimManageViewModel.libraryListIsRefreshing.observe(
|
||||
this, Observer(this::onRefreshStateChange)
|
||||
)
|
||||
zimManageViewModel.networkStates.observe(this, Observer(this::onNetworkStateChange))
|
||||
}
|
||||
|
||||
private fun onRefreshStateChange(isRefreshing: Boolean?) {
|
||||
librarySwipeRefresh.isRefreshing = isRefreshing!!
|
||||
}
|
||||
|
||||
private fun onNetworkStateChange(networkState: NetworkState?) {
|
||||
when (networkState) {
|
||||
CONNECTED -> {
|
||||
}
|
||||
NOT_CONNECTED -> {
|
||||
if (libraryAdapter.itemCount > 0) {
|
||||
context.toast(R.string.no_network_connection)
|
||||
} else {
|
||||
libraryErrorText.setText(R.string.no_network_connection)
|
||||
libraryErrorText.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLibraryItemsChange(it: List<LibraryListItem>?) {
|
||||
libraryAdapter.itemList = it!!
|
||||
if (it.isEmpty()) {
|
||||
libraryErrorText.setText(
|
||||
if (isNotConnected) R.string.no_network_connection
|
||||
else R.string.no_items_msg
|
||||
)
|
||||
libraryErrorText.visibility = VISIBLE
|
||||
TestingUtils.unbindResource(LibraryFragment::class.java)
|
||||
} else {
|
||||
libraryErrorText.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshFragment() {
|
||||
if (isNotConnected) {
|
||||
context.toast(R.string.no_network_connection)
|
||||
} else {
|
||||
zimManageViewModel.requestDownloadLibrary.onNext(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadFile(book: Book) {
|
||||
downloader.download(book)
|
||||
}
|
||||
|
||||
private fun storeDeviceInPreferences(storageDevice: StorageDevice) {
|
||||
sharedPreferenceUtil.putPrefStorage(storageDevice.name)
|
||||
sharedPreferenceUtil.putPrefStorageTitle(
|
||||
getString(
|
||||
if (storageDevice.isInternal) R.string.internal_storage
|
||||
else R.string.external_storage
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun onBookItemClick(item: BookItem) {
|
||||
when {
|
||||
notEnoughSpaceAvailable(item) -> {
|
||||
context.toast(
|
||||
getString(R.string.download_no_space)
|
||||
+ "\n" + getString(R.string.space_available) + " "
|
||||
+ LibraryUtils.bytesToHuman(spaceAvailable)
|
||||
)
|
||||
libraryList.snack(
|
||||
R.string.download_change_storage,
|
||||
R.string.open,
|
||||
this::showStorageSelectDialog
|
||||
)
|
||||
return
|
||||
}
|
||||
isNotConnected -> {
|
||||
context.toast(R.string.no_network_connection)
|
||||
return
|
||||
}
|
||||
noWifiWithWifiOnlyPreferenceSet -> {
|
||||
dialogShower.show(WifiOnly, {
|
||||
sharedPreferenceUtil.putPrefWifiOnly(false)
|
||||
KiwixMobileActivity.wifiOnly = false
|
||||
downloadFile(item.book)
|
||||
})
|
||||
return
|
||||
}
|
||||
else -> downloadFile(item.book)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notEnoughSpaceAvailable(item: BookItem) =
|
||||
spaceAvailable < item.book.size.toLong() * 1024f
|
||||
|
||||
private fun showStorageSelectDialog() {
|
||||
val dialogFragment = StorageSelectDialog()
|
||||
dialogFragment.arguments = Bundle().apply {
|
||||
putString(
|
||||
StorageSelectDialog.STORAGE_DIALOG_INTERNAL,
|
||||
getString(string.internal_storage)
|
||||
)
|
||||
putString(
|
||||
StorageSelectDialog.STORAGE_DIALOG_EXTERNAL,
|
||||
getString(string.external_storage)
|
||||
)
|
||||
putInt(StorageSelectDialog.STORAGE_DIALOG_THEME, StyleUtils.dialogStyle())
|
||||
}
|
||||
dialogFragment.setOnSelectListener(this::storeDeviceInPreferences)
|
||||
dialogFragment.show(fragmentManager, getString(string.pref_storage))
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (C) 2018 Kiwix <android.kiwix.org>
|
||||
*
|
||||
* 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 org.kiwix.kiwixmobile.zim_manager.library_view;
|
||||
|
||||
import android.util.Log;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import javax.inject.Inject;
|
||||
import org.kiwix.kiwixmobile.base.BasePresenter;
|
||||
import org.kiwix.kiwixmobile.database.BookDao;
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
|
||||
import org.kiwix.kiwixmobile.network.KiwixService;
|
||||
|
||||
/**
|
||||
* Created by EladKeyshawn on 06/04/2017.
|
||||
*/
|
||||
|
||||
public class LibraryPresenter extends BasePresenter<LibraryViewCallback> {
|
||||
|
||||
@Inject
|
||||
KiwixService kiwixService;
|
||||
|
||||
@Inject
|
||||
BookDao bookDao;
|
||||
|
||||
@Inject
|
||||
public LibraryPresenter() {
|
||||
}
|
||||
|
||||
void loadBooks() {
|
||||
getMvpView().displayScanningContent();
|
||||
kiwixService.getLibrary()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(library -> getMvpView().showBooks(library.getBooks()), error -> {
|
||||
String msg = error.getLocalizedMessage();
|
||||
Log.w("kiwixLibrary", "Error loading books:" + (msg != null ? msg : "(null)"));
|
||||
getMvpView().displayNoItemsFound();
|
||||
});
|
||||
}
|
||||
|
||||
void loadRunningDownloadsFromDb() {
|
||||
for (LibraryNetworkEntity.Book book : bookDao.getDownloadingBooks()) {
|
||||
// if (!DownloadFragment.mDownloads.containsValue(book)) {
|
||||
book.url = book.remoteUrl;
|
||||
getMvpView().downloadFile(book);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (C) 2018 Kiwix <android.kiwix.org>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
interface AbsDelegateAdapter<INSTANCE : SUPERTYPE, SUPERTYPE, VIEWHOLDER : RecyclerView.ViewHolder> : AdapterDelegate<SUPERTYPE> {
|
||||
|
||||
override fun bind(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
itemToBind: SUPERTYPE
|
||||
) {
|
||||
onBindViewHolder(itemToBind as INSTANCE, viewHolder as VIEWHOLDER)
|
||||
}
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup): VIEWHOLDER
|
||||
|
||||
fun onBindViewHolder(
|
||||
item: INSTANCE,
|
||||
holder: VIEWHOLDER
|
||||
)
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder
|
||||
import android.view.ViewGroup
|
||||
|
||||
interface AdapterDelegate<T> {
|
||||
fun createViewHolder(parent: ViewGroup): ViewHolder
|
||||
|
||||
fun bind(
|
||||
viewHolder: ViewHolder,
|
||||
itemToBind: T
|
||||
)
|
||||
|
||||
fun isFor(item: T): Boolean
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.support.v4.util.SparseArrayCompat
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
|
||||
class AdapterDelegateManager<T>() {
|
||||
fun addDelegate(delegate: AdapterDelegate<T>) {
|
||||
delegates.put(delegates.size(), delegate)
|
||||
}
|
||||
|
||||
fun createViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
) = delegates[viewType].createViewHolder(parent)
|
||||
|
||||
fun onBindViewHolder(
|
||||
libraryListItem: T,
|
||||
holder: RecyclerView.ViewHolder
|
||||
) {
|
||||
delegates[holder.itemViewType].bind(holder, libraryListItem)
|
||||
}
|
||||
|
||||
fun getViewTypeFor(item: T) = delegates.keyAt(getDelegateIndexFor(item))
|
||||
|
||||
private fun getDelegateIndexFor(item: T): Int {
|
||||
for (index in 0..delegates.size()) {
|
||||
val valueAt = delegates.valueAt(index)
|
||||
if (valueAt.isFor(item)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
throw RuntimeException("No delegate registered for $item")
|
||||
}
|
||||
|
||||
var delegates: SparseArrayCompat<AdapterDelegate<T>> = SparseArrayCompat()
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
class Language constructor(
|
||||
locale: Locale,
|
||||
var active: Boolean?,
|
||||
var language: String = locale.displayLanguage,
|
||||
var languageLocalized: String = locale.getDisplayLanguage(locale),
|
||||
var languageCode: String = locale.isO3Language,
|
||||
var languageCodeISO2: String = locale.language
|
||||
)
|
||||
{
|
||||
|
||||
constructor(
|
||||
languageCode: String,
|
||||
active: Boolean?
|
||||
) : this(Locale(languageCode), active) {
|
||||
}
|
||||
|
||||
override fun equals(obj: Any?): Boolean {
|
||||
return (obj as Language).language == language && obj.active == active
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
|
||||
class LibraryAdapter(
|
||||
private val delegateManager: AdapterDelegateManager<LibraryListItem> = AdapterDelegateManager(),
|
||||
vararg delegates: AdapterDelegate<LibraryListItem>
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
init {
|
||||
delegates.forEach {
|
||||
delegateManager.addDelegate(it)
|
||||
}
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
var itemList: List<LibraryListItem> = mutableListOf()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
) = delegateManager.createViewHolder(parent, viewType)
|
||||
|
||||
override fun getItemCount() = itemList.size
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: RecyclerView.ViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
delegateManager.onBindViewHolder(itemList[position], holder)
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int) = itemList[position].id
|
||||
|
||||
override fun getItemViewType(position: Int) =
|
||||
delegateManager.getViewTypeFor(itemList[position])
|
||||
|
||||
}
|
||||
|
||||
//private Observable<Book> getMatches(Book b, String s) {
|
||||
// StringBuilder text = new StringBuilder();
|
||||
// text.append(b.getTitle()).append("|").append(b.getDescription()).append("|")
|
||||
// .append(parseURL(context, b.getUrl())).append("|");
|
||||
// if (bookUtils.localeMap.containsKey(b.getLanguage())) {
|
||||
// text.append(bookUtils.localeMap.get(b.getLanguage()).getDisplayLanguage()).append("|");
|
||||
// }
|
||||
// String[] words = s.toLowerCase().split("\\s+");
|
||||
// b.searchMatches = Observable.fromArray(words)
|
||||
// .filter(text.toString().toLowerCase()::contains)
|
||||
// .count()
|
||||
// .blockingGet()
|
||||
// .intValue();
|
||||
// if (b.searchMatches > 0) {
|
||||
// return Observable.just(b);
|
||||
// } else {
|
||||
// return Observable.empty();
|
||||
// }
|
||||
//}}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (C) 2018 Kiwix <android.kiwix.org>
|
||||
*
|
||||
* 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 org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import org.kiwix.kiwixmobile.R
|
||||
import org.kiwix.kiwixmobile.R.layout
|
||||
import org.kiwix.kiwixmobile.extensions.inflate
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryViewHolder.LibraryBookViewHolder
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryViewHolder.LibraryDividerViewHolder
|
||||
|
||||
sealed class LibraryDelegate<I : LibraryListItem, VH : LibraryViewHolder<I>> :
|
||||
AbsDelegateAdapter<I, LibraryListItem, VH> {
|
||||
|
||||
class BookDelegate(
|
||||
private val bookUtils: BookUtils,
|
||||
private val clickAction: (BookItem) -> Unit
|
||||
) : LibraryDelegate<BookItem, LibraryBookViewHolder>() {
|
||||
|
||||
override fun createViewHolder(parent: ViewGroup) =
|
||||
LibraryBookViewHolder(
|
||||
parent.inflate(R.layout.library_item, false),
|
||||
bookUtils,
|
||||
clickAction
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(
|
||||
item: BookItem,
|
||||
holder: LibraryBookViewHolder
|
||||
) {
|
||||
holder.bind(item)
|
||||
}
|
||||
|
||||
override fun isFor(item: LibraryListItem) = item is BookItem
|
||||
}
|
||||
|
||||
object DividerDelegate : LibraryDelegate<DividerItem, LibraryDividerViewHolder>() {
|
||||
override fun createViewHolder(parent: ViewGroup) =
|
||||
LibraryDividerViewHolder(parent.inflate(layout.library_divider, false))
|
||||
|
||||
override fun onBindViewHolder(
|
||||
item: DividerItem,
|
||||
holder: LibraryDividerViewHolder
|
||||
) {
|
||||
holder.bind(item)
|
||||
}
|
||||
|
||||
override fun isFor(item: LibraryListItem) = item is DividerItem
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||
|
||||
sealed class LibraryListItem() {
|
||||
abstract val id: Long
|
||||
|
||||
data class DividerItem constructor(
|
||||
override val id: Long,
|
||||
val text: String
|
||||
) : LibraryListItem()
|
||||
|
||||
data class BookItem(
|
||||
val book: Book,
|
||||
override val id: Long = book.id.hashCode().toLong()
|
||||
) : LibraryListItem()
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
import butterknife.internal.DebouncingOnClickListener
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.library_divider.divider_text
|
||||
import kotlinx.android.synthetic.main.library_item.creator
|
||||
import kotlinx.android.synthetic.main.library_item.date
|
||||
import kotlinx.android.synthetic.main.library_item.description
|
||||
import kotlinx.android.synthetic.main.library_item.favicon
|
||||
import kotlinx.android.synthetic.main.library_item.fileName
|
||||
import kotlinx.android.synthetic.main.library_item.language
|
||||
import kotlinx.android.synthetic.main.library_item.publisher
|
||||
import kotlinx.android.synthetic.main.library_item.size
|
||||
import kotlinx.android.synthetic.main.library_item.title
|
||||
import org.kiwix.kiwixmobile.KiwixApplication
|
||||
import org.kiwix.kiwixmobile.downloader.model.Base64String
|
||||
import org.kiwix.kiwixmobile.extensions.setBitmap
|
||||
import org.kiwix.kiwixmobile.extensions.setTextAndVisibility
|
||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.utils.NetworkUtils
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
|
||||
|
||||
sealed class LibraryViewHolder<T : LibraryListItem>(override val containerView: View) : RecyclerView.ViewHolder(
|
||||
containerView
|
||||
), LayoutContainer {
|
||||
|
||||
abstract fun bind(item: T)
|
||||
|
||||
class LibraryBookViewHolder(
|
||||
view: View,
|
||||
private val bookUtils: BookUtils,
|
||||
private val clickAction: (BookItem) -> Unit
|
||||
) : LibraryViewHolder<BookItem>(view) {
|
||||
override fun bind(item: BookItem) {
|
||||
title.setTextAndVisibility(item.book.title)
|
||||
description.setTextAndVisibility(item.book.description)
|
||||
creator.setTextAndVisibility(item.book.creator)
|
||||
publisher.setTextAndVisibility(item.book.publisher)
|
||||
date.setTextAndVisibility(item.book.date)
|
||||
size.setTextAndVisibility(MegaByte(item.book.size).humanReadable)
|
||||
language.text = bookUtils.getLanguage(item.book.getLanguage())
|
||||
fileName.text = NetworkUtils.parseURL(
|
||||
KiwixApplication.getInstance(), item.book.file?.path ?: ""
|
||||
)
|
||||
favicon.setBitmap(Base64String(item.book.favicon))
|
||||
|
||||
containerView.setOnClickListener {
|
||||
clickAction.invoke(item)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LibraryDividerViewHolder(view: View) : LibraryViewHolder<DividerItem>(view) {
|
||||
override fun bind(item: DividerItem) {
|
||||
divider_text.text = item.text
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view.adapter
|
||||
|
||||
import java.text.DecimalFormat
|
||||
|
||||
inline class MegaByte(val megabyteString: String?) {
|
||||
val humanReadable
|
||||
get() = megabyteString?.toLongOrNull()?.let {
|
||||
val units = arrayOf("KB", "MB", "GB", "TB")
|
||||
val conversion = (Math.log10(it.toDouble()) / Math.log10(1024.0)).toInt()
|
||||
(DecimalFormat("#,##0.#")
|
||||
.format(it / Math.pow(1024.0, conversion.toDouble()))
|
||||
+ " "
|
||||
+ units[conversion])
|
||||
} ?: ""
|
||||
|
||||
}
|
@ -1,61 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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"
|
||||
android:orientation="vertical"
|
||||
tools:context=".zim_manager.library_view.LibraryFragment">
|
||||
|
||||
<RelativeLayout
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/listBackground">
|
||||
android:animateLayoutChanges="true"
|
||||
tools:context=".zim_manager.library_view.LibraryFragment"
|
||||
>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/network_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/library_textview_padding"
|
||||
android:textSize="@dimen/library_font_size"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/network_permission_text"
|
||||
<TextView
|
||||
android:id="@+id/libraryErrorText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/network_permission_text_margin_top"
|
||||
android:text="@string/get_library_over_network"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/network_permission_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/network_permission_button_margin_top"
|
||||
android:text="@string/proceed"
|
||||
android:visibility="gone" />
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/library_swiperefresh"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/librarySwipeRefresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/library_list"
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/libraryList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/listBackground"
|
||||
android:divider="@null"
|
||||
android:paddingBottom="@dimen/library_article_list_padding" />
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
/>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
@ -3,7 +3,6 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/listBackground"
|
||||
android:orientation="vertical"
|
||||
android:animateLayoutChanges="true"
|
||||
>
|
||||
@ -11,7 +10,7 @@
|
||||
<TextView
|
||||
android:id="@+id/download_management_no_downloads"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_downloads_here"
|
||||
android:textSize="@dimen/download_management_no_downloads_text_size"
|
||||
android:visibility="gone"
|
||||
@ -26,6 +25,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
@ -1,109 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/favicon"
|
||||
android:layout_width="@dimen/favicon_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginRight="@dimen/favicon_margin_right"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@mipmap/kiwix_icon" />
|
||||
android:id="@+id/favicon"
|
||||
android:layout_width="@dimen/favicon_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginRight="@dimen/favicon_margin_right"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@mipmap/kiwix_icon"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/dimen_small_padding"
|
||||
tools:ignore="HardcodedText">
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/dimen_small_padding"
|
||||
tools:ignore="HardcodedText"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Title"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem" />
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Title"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Description"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Description"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/dimen_medium_padding">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/dimen_medium_padding"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="File Size"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="File Size"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/creator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Author"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/creator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Author"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/publisher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Publisher"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/publisher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Publisher"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="right"
|
||||
android:orientation="vertical">
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="right"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Date"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Date"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/language"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Language"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/language"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Language"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="File Name"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
android:id="@+id/fileName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="File Name"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -11,11 +11,7 @@
|
||||
<TextView
|
||||
android:id="@+id/file_management_no_files"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/file_management_no_files_padding_bottom"
|
||||
android:text="@string/no_files_here"
|
||||
android:textSize="@dimen/file_management_no_files_text_size"
|
||||
@ -37,8 +33,7 @@
|
||||
android:id="@+id/zimfilelist"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@null"
|
||||
android:paddingBottom="@dimen/zimfilelist_padding_bottom"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
/>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
@ -1,51 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/zim_manager_main_activity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".zim_manager.ZimManageActivity">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/zim_manager_main_activity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".zim_manager.ZimManageActivity"
|
||||
>
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/dimen_medium_padding"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/dimen_medium_padding"
|
||||
android:theme="@style/AppTheme.AppBarOverlay"
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
>
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay">
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:layout_scrollFlags="scroll|snap|enterAlways"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||
>
|
||||
|
||||
</android.support.v7.widget.Toolbar>
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp" />
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
/>
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"
|
||||
/>
|
||||
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
@ -14,16 +14,13 @@
|
||||
<dimen name="abc_dropdownitem_text_padding_right">8dip</dimen>
|
||||
<dimen name="library_textview_padding">75dp</dimen>
|
||||
<dimen name="library_font_size">20sp</dimen>
|
||||
<dimen name="library_article_list_padding">60dp</dimen>
|
||||
<dimen name="network_permission_text_margin_top">200dp</dimen>
|
||||
<dimen name="network_permission_button_margin_top">230dp</dimen>
|
||||
<dimen name="bookmark_title_text_size">15sp</dimen>
|
||||
<dimen name="download_management_no_downloads_padding_bottom">75dp</dimen>
|
||||
<dimen name="help_cardview_card_elevation">2dp</dimen>
|
||||
<dimen name="kiwix_search_widget_layout_id_height">50dp</dimen>
|
||||
<dimen name="file_management_no_files_padding_bottom">75dp</dimen>
|
||||
<dimen name="file_management_no_files_text_size">20sp</dimen>
|
||||
<dimen name="zimfilelist_padding_bottom">60dp</dimen>
|
||||
<dimen name="webview_search_edit_text_margin_right">10dip</dimen>
|
||||
<dimen name="progressbar_layout_margin_top">300dp</dimen>
|
||||
<dimen name="fullscreen_control_button_margin">7dp</dimen>
|
||||
|
@ -14,7 +14,7 @@ buildscript {
|
||||
}
|
||||
|
||||
ext {
|
||||
supportLibraryVersion = '27.0.2'
|
||||
supportLibraryVersion = '27.1.1'
|
||||
rxJavaVersion = '2.1.9'
|
||||
rxAndroidVersion = '2.0.2'
|
||||
okHttpVersion = '3.9.1'
|
||||
|
Loading…
x
Reference in New Issue
Block a user