Merge pull request #850 from kiwix/abdulwd/merge

Merge master branch with 3.0
This commit is contained in:
Isaac Hutt 2018-08-27 21:13:04 +01:00 committed by GitHub
commit 40e74aec1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 321 additions and 147 deletions

View File

@ -1,45 +0,0 @@
# Fill out this template with your issue then delete these lines only leaving the titles and your responses.
# For a Bug Report:
## Bug Report
### Are you ready to report?
- Your issue may already be reported! Please search on the [issue track](../) before creating one.
- Ensure you have tested with the last (dev) version of the software. (If not, and if possible, run your test again with the most recent version available.)
### Environment
* version of the software you use : _____
* device / operating system : _____
### The Bug:
* What do you obtain? A copy of the error message or a screenshot is always useful.
* When does this occur?
#### Steps to reproduce:
1. _____
2. _____
3. _____
...
* What should be the behaviour from your point of view? How do you expect the service to work?
### Other Comments:
* What is the context of this ticket? If not obvious, explain why you need to do this.
* If you have an idea about the technical background of the ticket, please share it.
# For a Feature Request:
## Feature Request
#### Feature Description
Please describe the feature you want to add to the project.

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
---
<!-- Checklist for reporting a bug
- Check the issue tracker. The issue you have may have already been reported.
- Ensure you have tested the latest developers version.
-->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Steps to reproduce the behavior:**
1.
<!--
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem otherwise delete this heading. -->
**Environment**
- Version of Kiwix Android :
- Device :
- OS version :
**Logs**
<!-- If applicable, add logs to help the developers in identifying your problem otherwise delete this heading. -->

View File

@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- Checklist for requesting a feature:
- Check the issue tracker. The feature you are requesting may have already been requested.
- Check if the feature does not exists on the latest developers version.
-->
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Example: I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered.
If not applicable delete this heading. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here.
If not applicable delete this heading. -->

31
.github/ISSUE_TEMPLATE/test_request.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: Request Tests
about: Identify code liable to break and create tests to prevent software regression due to code changes
---
<!-- Checklist for reporting a bug
- Check the issue tracker. The issue you have may have already been reported.
- Ensure that you are using the latest developers version.
- Make sure that the tests are not for any other framework libraries that are being used in the code.
- Prefer code that seems to get changed by different developers and accessed by a lot of other modules.
-->
**Type of Test**
<!-- Unit Test or UI Test -->
* [ ] Unit Test
* [ ] UI Test
**Particular area and files to be tested**
<!--
In case of Unit Tests, mention the names of the files or modules to be tested.
In case of UI Tests, mention the names of the activities to be tested.
-->
**Current Status of the tests**
<!-- Are there any tests included for this particular area, which need improvement, or has this are never been tested at all?
(You can see the tests that we are currently using in the "androidTest", and "androidTestKiwix" folders in the "app/src" folder) -->
**Particular Behaviour to be tested**
<!-- Give a brief description of the particular cases which need to be tested.
(For example: test whether data is saved in the database on clicking a particular button, or test whether the default language is preselected, etc) -->

View File

@ -1,4 +1,4 @@
2.3
2.4
FIX: External SD card problems
FIX: Some UI translation
FIX: Download manager process sporadic problems

View File

@ -76,7 +76,7 @@ public class BasicTest {
openDrawerWithGravity(R.id.drawer_layout, Gravity.RIGHT);
assertDrawerIsOpenWithGravity(R.id.drawer_layout, Gravity.RIGHT);
assertDisplayed(R.string.no_section_info);
assertDisplayed(R.string.menu_help);
closeDrawerWithGravity(R.id.drawer_layout, Gravity.RIGHT);
assertDrawerIsClosedWithGravity(R.id.drawer_layout, Gravity.RIGHT);*/

View File

@ -2,6 +2,9 @@
<html>
<head>
<meta charset="UTF-8"/>
<title>Home</title>
<title>REPLACE_menu_home</title>
</head>
<body>
<h1 style="display:none;">REPLACE_menu_home</h1>
</body>
</html>

View File

@ -23,6 +23,7 @@ import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.LanguageUtils;
import org.kiwix.kiwixmobile.utils.SharedPreferenceUtil;
import javax.inject.Inject;
@ -42,6 +43,7 @@ public abstract class BaseActivity extends AppCompatActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
LanguageUtils.handleLocaleChange(this, sharedPreferenceUtil);
}
@Override

View File

@ -36,6 +36,7 @@ import org.kiwix.kiwixmobile.data.local.entity.LibraryDatabaseEntity;
import org.kiwix.kiwixmobile.data.local.entity.NetworkLanguageDatabaseEntity;
import org.kiwix.kiwixmobile.data.local.entity.RecentSearch;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.UpdateUtils;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
@ -52,7 +53,7 @@ import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
@Singleton
public class KiwixDatabase extends SquidDatabase {
private static final int VERSION = 16;
private static final int VERSION = 17;
private final Context context;
@Inject
@ -125,6 +126,8 @@ public class KiwixDatabase extends SquidDatabase {
tryAddColumn(Bookmark.ZIM_FILE_PATH);
tryAddColumn(Bookmark.FAVICON);
migrateBookmarksVersion16();
case 16:
new BookmarksDao(this).processBookmark(UpdateUtils::reformatProviderUrl);
}
return true;
}

View File

@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.data.local.dao;
import com.yahoo.squidb.data.SquidCursor;
import com.yahoo.squidb.sql.Query;
import com.yahoo.squidb.sql.Update;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.KiwixDatabase;
@ -107,4 +108,23 @@ public class BookmarksDao {
kiwixDatabase.deleteWhere(Bookmark.class, Bookmark.BOOKMARK_URL.eq(bookmark.getBookmarkUrl())
.and(Bookmark.ZIM_ID.eq(bookmark.getZimId())));
}
public void processBookmark(StringOperation operation) {
try (SquidCursor<Bookmark> bookmarkCursor = kiwixDatabase.query(Bookmark.class,
Query.select(Bookmark.ID, Bookmark.BOOKMARK_URL))) {
while (bookmarkCursor.moveToNext()) {
String url = bookmarkCursor.get(Bookmark.BOOKMARK_URL);
url = operation.apply(url);
if (url != null) {
kiwixDatabase.update(Update.table(Bookmark.TABLE)
.where(Bookmark.ID.eq(bookmarkCursor.get(Bookmark.ID)))
.set(Bookmark.BOOKMARK_URL, url));
}
}
}
}
public interface StringOperation {
String apply(String string);
}
}

View File

@ -26,7 +26,7 @@ public class ChunkUtils {
public static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
public static final String ZIM_EXTENSION = ".zim";
public static final String PART = ".part";
public static final String PART = ".part.part";
public static final long CHUNK_SIZE = 1024L * 1024L * 1024L * 2L;
public static List<Chunk> getChunks(String url, long contentLength, int notificationID) {
@ -63,7 +63,7 @@ public class ChunkUtils {
private static String[] getZimChunkFileNames(String fileName, int count) {
if (count == 1) {
return new String[] { fileName + PART};
return new String[]{fileName + PART};
}
int position = fileName.lastIndexOf(".");
String baseName = position > 0 ? fileName.substring(0, position) : fileName;

View File

@ -71,6 +71,9 @@ import okhttp3.Request;
import okhttp3.Response;
import okio.BufferedSource;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.ALPHABET;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.PART;
import static org.kiwix.kiwixmobile.downloader.ChunkUtils.ZIM_EXTENSION;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_BOOK;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_LIBRARY;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_NOTIFICATION_ID;
@ -139,8 +142,7 @@ public class DownloadService extends Service {
if (intent == null) {
return START_NOT_STICKY;
}
String log = intent.getAction();
log += " : ";
String log = intent.getAction() + " : ";
if (intent.hasExtra(NOTIFICATION_ID)) {
log += intent.getIntExtra(NOTIFICATION_ID, -3);
}
@ -322,6 +324,35 @@ public class DownloadService extends Service {
notification.get(notificationID).setContentText(getString(R.string.zim_file_downloaded));
final Intent target = new Intent(DownloadService.this, MainActivity.class);
target.putExtra(EXTRA_ZIM_FILE, KIWIX_ROOT + StorageUtils.getFileNameFromUrl(book.getUrl()));
//Remove the extra ".part" from files
String filename = book.file.getPath();
if (filename.endsWith(ZIM_EXTENSION)) {
filename = filename + PART;
File partFile = new File(filename);
if (partFile.exists()) {
partFile.renameTo(new File(partFile.getPath().replaceAll(".part", "")));
}
} else {
for (int i = 0; true; i++) {
char first = ALPHABET.charAt(i / 26);
char second = ALPHABET.charAt(i % 26);
String chunkExtension = String.valueOf(first) + second;
filename = book.file.getPath();
filename = filename.replaceAll(".zim([a-z][a-z]){0,1}$", ".zim");
filename = filename + chunkExtension + ".part";
File partFile = new File(filename);
if (partFile.exists()) {
partFile.renameTo(new File(partFile.getPath().replaceAll(".part$", "")));
} else {
File lastChunkFile = new File(filename + ".part");
if (lastChunkFile.exists()) {
lastChunkFile.renameTo(new File(partFile.getPath().replaceAll(".part", "")));
} else {
break;
}
}
}
}
target.putExtra(EXTRA_NOTIFICATION_ID, notificationID);
PendingIntent pendingIntent = PendingIntent.getActivity
(getBaseContext(), 0,
@ -453,7 +484,7 @@ public class DownloadService extends Service {
// Create chunk file
File file = new File(KIWIX_ROOT, chunk.getFileName());
file.getParentFile().mkdirs();
File fullFile = new File(file.getPath().substring(0, file.getPath().length() - 5));
File fullFile = new File(file.getPath().substring(0, file.getPath().length() - PART.length()));
long downloaded = Long.parseLong(chunk.getRangeHeader().split("-")[0]);
if (fullFile.exists() && fullFile.length() == chunk.getSize()) {
@ -535,7 +566,8 @@ public class DownloadService extends Service {
break;
}
if (MainActivity.wifiOnly && !NetworkUtils.isWiFi(getApplicationContext())) {
if (MainActivity.wifiOnly && !NetworkUtils.isWiFi(getApplicationContext()) ||
!NetworkUtils.isNetworkAvailable(getApplicationContext())) {
pauseDownload(chunk.getNotificationID());
}
@ -594,16 +626,16 @@ public class DownloadService extends Service {
if (downloadStatus.get(chunk.getNotificationID()) == CANCEL) {
String path = file.getPath();
Log.i(KIWIX_TAG, "Download Cancelled, deleting file: " + path);
if (path.substring(path.length() - 8).equals("zim.part")) {
path = path.substring(0, path.length() - 5);
if (path.substring(path.length() - (ZIM_EXTENSION + PART).length()).equals(ZIM_EXTENSION + PART)) {
path = path.substring(0, path.length() - PART.length() + 1);
FileUtils.deleteZimFile(path);
} else {
path = path.substring(0, path.length() - 7) + "aa";
path = path.substring(0, path.length() - (ZIM_EXTENSION + PART).length() + 2) + "aa";
FileUtils.deleteZimFile(path);
}
} else {
Log.i(KIWIX_TAG, "Download completed, renaming file ([" + file.getPath() + "] -> .zim)");
file.renameTo(new File(file.getPath().replace(".part", "")));
Log.i(KIWIX_TAG, "Download completed, renaming file ([" + file.getPath() + "] -> .zim.part)");
file.renameTo(new File(file.getPath().replaceAll(".part$", "")));
}
// Mark chunk status as downloaded
chunk.isDownloaded = true;
@ -627,6 +659,7 @@ public class DownloadService extends Service {
NotificationChannel ongoingDownloadsChannel = new NotificationChannel(
Constants.ONGOING_DOWNLOAD_CHANNEL_ID, name, importance);
ongoingDownloadsChannel.setDescription(description);
ongoingDownloadsChannel.setSound(null, null);
NotificationManager notificationManager = (NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(ongoingDownloadsChannel);

View File

@ -140,7 +140,9 @@ import static org.kiwix.kiwixmobile.utils.Constants.TAG_CURRENT_POSITIONS;
import static org.kiwix.kiwixmobile.utils.Constants.TAG_CURRENT_TAB;
import static org.kiwix.kiwixmobile.utils.Constants.TAG_FILE_SEARCHED;
import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
import static org.kiwix.kiwixmobile.utils.LanguageUtils.getResourceString;
import static org.kiwix.kiwixmobile.utils.StyleUtils.dialogStyle;
import static org.kiwix.kiwixmobile.utils.UpdateUtils.reformatProviderUrl;
public class MainActivity extends BaseActivity implements WebViewCallback,
MainContract.View, BooksAdapter.OnItemClickListener {
@ -321,6 +323,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter.attachView(this);
new WebView(this).destroy(); // Workaround for buggy webViews see #710
wifiOnly = sharedPreferenceUtil.getPrefWifiOnly();
nightMode = sharedPreferenceUtil.nightMode();
handleLocaleCheck();
@ -346,25 +349,8 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
tableDrawerRight.setLayoutManager(new LinearLayoutManager(this));
TableDrawerAdapter tableDrawerAdapter = new TableDrawerAdapter();
TableDrawerAdapter tableDrawerAdapter = setupTableDrawerAdapter();
tableDrawerRight.setAdapter(tableDrawerAdapter);
tableDrawerAdapter.setTableClickListener(new TableClickListener() {
@Override
public void onHeaderClick(View view) {
getCurrentWebView().setScrollY(0);
drawerLayout.closeDrawer(GravityCompat.END);
}
@Override
public void onSectionClick(View view, int position) {
getCurrentWebView().loadUrl("javascript:document.getElementById('"
+ documentSections.get(position).id
+ "').scrollIntoView();");
drawerLayout.closeDrawers();
}
});
tableDrawerAdapter.notifyDataSetChanged();
tabsAdapter.setTabClickListener(new TabsAdapter.TabClickListener() {
@ -391,8 +377,17 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
documentParser = new DocumentParser(new DocumentParser.SectionsListener() {
@Override
public void sectionsLoaded(String title, List<DocumentSection> sections) {
for (DocumentSection section : sections) {
if (section.title.contains("REPLACE_")) {
section.title = getResourceString(getApplicationContext(), section.title);
}
}
documentSections.addAll(sections);
tableDrawerAdapter.setTitle(title);
if (title.contains("REPLACE_")) {
tableDrawerAdapter.setTitle(getResourceString(getApplicationContext(), title));
} else {
tableDrawerAdapter.setTitle(title);
}
tableDrawerAdapter.setSections(documentSections);
tableDrawerAdapter.notifyDataSetChanged();
}
@ -443,6 +438,26 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
new ItemTouchHelper(tabCallback).attachToRecyclerView(tabRecyclerView);
}
private TableDrawerAdapter setupTableDrawerAdapter() {
TableDrawerAdapter tableDrawerAdapter = new TableDrawerAdapter();
tableDrawerAdapter.setTableClickListener(new TableClickListener() {
@Override
public void onHeaderClick(View view) {
getCurrentWebView().setScrollY(0);
drawerLayout.closeDrawer(GravityCompat.END);
}
@Override
public void onSectionClick(View view, int position) {
getCurrentWebView().loadUrl("javascript:document.getElementById('"
+ documentSections.get(position).id
+ "').scrollIntoView();");
drawerLayout.closeDrawers();
}
});
return tableDrawerAdapter;
}
private void showTabSwitcher() {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_round_add_white_36dp));
@ -750,7 +765,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
}
}
private KiwixWebView getCurrentWebView() {
KiwixWebView getCurrentWebView() {
if (webViewList.size() == 0) return newTab();
if (currentWebViewIndex < webViewList.size()) {
return webViewList.get(currentWebViewIndex);
@ -1191,18 +1206,19 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
intent.setAction("");
goToSearch(true);
break;
case Intent.ACTION_VIEW: {
final String zimFile = ZimContentProvider.getZimFile();
saveTabStates();
Intent i = new Intent(MainActivity.this, SearchActivity.class);
i.putExtra(EXTRA_ZIM_FILE, zimFile);
if (intent.getData() != null) {
i.putExtra(EXTRA_SEARCH, intent.getData().getLastPathSegment());
case Intent.ACTION_VIEW:
if (intent.getType() == null || !intent.getType().equals("application/octet-stream")) {
final String zimFile = ZimContentProvider.getZimFile();
saveTabStates();
Intent i = new Intent(MainActivity.this, SearchActivity.class);
i.putExtra(EXTRA_ZIM_FILE, zimFile);
if (intent.getData() != null) {
i.putExtra(EXTRA_SEARCH, intent.getData().getLastPathSegment());
}
intent.setAction("");
startActivityForResult(i, REQUEST_FILE_SEARCH);
}
intent.setAction("");
startActivityForResult(i, REQUEST_FILE_SEARCH);
break;
}
case NEW_TAB:
newTab(HOME_URL);
break;
@ -1602,11 +1618,11 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
JSONArray urls = new JSONArray(zimArticles);
JSONArray positions = new JSONArray(zimPositions);
int i = 0;
getCurrentWebView().loadUrl(urls.getString(i));
getCurrentWebView().loadUrl(reformatProviderUrl(urls.getString(i)));
getCurrentWebView().setScrollY(positions.getInt(i));
i++;
for (; i < urls.length(); i++) {
newTab(urls.getString(i));
newTab(reformatProviderUrl(urls.getString(i)));
getCurrentWebView().setScrollY(positions.getInt(i));
}
selectTab(currentTab);

View File

@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.main;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.LayoutInflater;
@ -45,7 +46,7 @@ public class TableDrawerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
private int selectedPosition = 0;
public TableDrawerAdapter() {
TableDrawerAdapter() {
sections = new ArrayList<>();
}
@ -54,8 +55,9 @@ public class TableDrawerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
return 1;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
int resource = R.layout.section_list;
Context context = parent.getContext();
View v = LayoutInflater.from(context).inflate(resource, parent, false);
@ -72,7 +74,7 @@ public class TableDrawerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ViewHolder vh = (ViewHolder) holder;
Context context = holder.itemView.getContext();
@ -85,6 +87,9 @@ public class TableDrawerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
vh.title.setText(title);
} else {
String empty = context.getString(R.string.no_section_info);
if (context instanceof MainActivity) {
empty = ((MainActivity) context).getCurrentWebView().getTitle();
}
vh.title.setText(empty);
}
vh.itemView.setOnClickListener(v -> {
@ -152,14 +157,14 @@ public class TableDrawerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
public static class HeaderViewHolder extends ViewHolder {
public HeaderViewHolder(View v) {
HeaderViewHolder(View v) {
super(v);
}
}
public static class SectionViewHolder extends ViewHolder {
public SectionViewHolder(View v) {
SectionViewHolder(View v) {
super(v);
}
}

View File

@ -39,6 +39,7 @@ import static org.kiwix.kiwixmobile.utils.DimenUtils.getToolbarHeight;
import static org.kiwix.kiwixmobile.utils.DimenUtils.getWindowHeight;
import static org.kiwix.kiwixmobile.utils.DimenUtils.getWindowWidth;
import static org.kiwix.kiwixmobile.utils.ImageUtils.getBitmapFromView;
import static org.kiwix.kiwixmobile.utils.LanguageUtils.getResourceString;
import static org.kiwix.kiwixmobile.utils.StyleUtils.fromHtml;
public class TabsAdapter extends RecyclerView.Adapter<TabsAdapter.ViewHolder> {
@ -113,7 +114,11 @@ public class TabsAdapter extends RecyclerView.Adapter<TabsAdapter.ViewHolder> {
if (webView.getParent() != null) {
((ViewGroup) webView.getParent()).removeView(webView);
}
holder.title.setText(fromHtml(webView.getTitle()));
String webViewTitle = fromHtml(webView.getTitle()).toString();
if (webViewTitle.contains("REPLACE_")) {
webViewTitle = getResourceString(holder.title.getContext().getApplicationContext(), webViewTitle);
}
holder.title.setText(webViewTitle);
holder.close.setOnClickListener(v -> listener.onCloseTab(v, holder.getAdapterPosition()));
holder.content.setImageBitmap(getBitmapFromView(webView));
holder.content.setOnClickListener(v -> {

View File

@ -29,7 +29,6 @@ import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -63,9 +62,10 @@ public class SearchActivity extends BaseActivity
public static final String EXTRA_SEARCH_IN_TEXT = "bool_searchintext";
private final int REQ_CODE_SPEECH_INPUT = 100;
private ListView mListView;
private AutoCompleteAdapter mAutoAdapter;
private ArrayAdapter<String> mDefaultAdapter;
private ListView listView;
private ArrayAdapter<String> currentAdapter;
private AutoCompleteAdapter autoAdapter;
private ArrayAdapter<String> defaultAdapter;
private SearchView searchView;
private String searchText;
@ -85,14 +85,14 @@ public class SearchActivity extends BaseActivity
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_back);
getSupportActionBar().setHomeButtonEnabled(true);
searchPresenter.attachView(this);
mListView = findViewById(R.id.search_list);
mDefaultAdapter = getDefaultAdapter();
listView = findViewById(R.id.search_list);
defaultAdapter = getDefaultAdapter();
searchPresenter.getRecentSearches();
mListView.setAdapter(mDefaultAdapter);
activateDefaultAdapter();
mAutoAdapter = new AutoCompleteAdapter(this);
mListView.setOnItemClickListener(this);
mListView.setOnItemLongClickListener(this);
autoAdapter = new AutoCompleteAdapter(this);
listView.setOnItemClickListener(this);
listView.setOnItemLongClickListener(this);
boolean IS_VOICE_SEARCH_INTENT = getIntent().getBooleanExtra(EXTRA_IS_WIDGET_VOICE, false);
if (IS_VOICE_SEARCH_INTENT) {
@ -100,10 +100,20 @@ public class SearchActivity extends BaseActivity
}
}
public void activateDefaultAdapter() {
currentAdapter = defaultAdapter;
listView.setAdapter(currentAdapter);
}
public void activateAutoAdapter() {
currentAdapter = autoAdapter;
listView.setAdapter(currentAdapter);
}
@Override
public void addRecentSearches(List<String> recentSearches) {
mDefaultAdapter.addAll(recentSearches);
mDefaultAdapter.notifyDataSetChanged();
defaultAdapter.addAll(recentSearches);
defaultAdapter.notifyDataSetChanged();
}
@Override
@ -128,8 +138,8 @@ public class SearchActivity extends BaseActivity
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
if (searchText != null) {
searchView.setQuery(searchText, false);
mListView.setAdapter(mAutoAdapter);
mAutoAdapter.getFilter().filter(searchText.toLowerCase());
activateAutoAdapter();
autoAdapter.getFilter().filter(searchText.toLowerCase());
}
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@ -140,10 +150,10 @@ public class SearchActivity extends BaseActivity
@Override
public boolean onQueryTextChange(String s) {
if (s.equals("")) {
mListView.setAdapter(mDefaultAdapter);
activateDefaultAdapter();
} else {
mListView.setAdapter(mAutoAdapter);
mAutoAdapter.getFilter().filter(s.toLowerCase());
activateAutoAdapter();
autoAdapter.getFilter().filter(s.toLowerCase());
}
return true;
@ -198,15 +208,7 @@ public class SearchActivity extends BaseActivity
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CharSequence text = ((TextView) view).getText();
String title;
if (text instanceof Spanned) {
title = Html.toHtml((Spanned) text);
// To remove the "ltr style information" from spanned text
title = title.substring(title.indexOf(">") + 1, title.lastIndexOf("<"));
} else {
title = text.toString();
}
String title = currentAdapter.getItem(position);
searchPresenter.saveSearch(title);
sendMessage(title);
}
@ -242,8 +244,8 @@ public class SearchActivity extends BaseActivity
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (parent.getAdapter() == mDefaultAdapter) {
String searched = mListView.getItemAtPosition(position).toString();
if (parent.getAdapter() == defaultAdapter) {
String searched = listView.getItemAtPosition(position).toString();
deleteSpecificSearchDialog(searched);
}
return true;
@ -268,8 +270,8 @@ public class SearchActivity extends BaseActivity
}
private void resetAdapter() {
mDefaultAdapter = getDefaultAdapter();
mListView.setAdapter(mDefaultAdapter);
defaultAdapter = getDefaultAdapter();
activateDefaultAdapter();
searchPresenter.getRecentSearches();
}

View File

@ -34,7 +34,7 @@ public class SplashActivity extends BaseActivity {
super.onCreate(savedInstanceState);
if (!BuildConfig.DEBUG) {
Context appContext = this;
Context appContext = getApplicationContext();
Thread.setDefaultUncaughtExceptionHandler((paramThread, paramThrowable) -> {
final Intent intent = new Intent(appContext, ErrorActivity.class);

View File

@ -17,6 +17,8 @@
*/
package org.kiwix.kiwixmobile.utils;
import org.kiwix.kiwixmobile.BuildConfig;
public final class Constants {
public static final String TAG_KIWIX = "kiwix";
@ -125,4 +127,8 @@ public final class Constants {
// Notification Channel Constants
public static final String ONGOING_DOWNLOAD_CHANNEL_ID = "ongoing_downloads_channel_id";
public static final String OLD_PROVIDER_DOMAIN = "org.kiwix.zim.base";
public static final String NEW_PROVIDER_DOMAIN = BuildConfig.APPLICATION_ID + ".zim.base";
}

View File

@ -107,10 +107,10 @@ public class LanguageUtils {
return mLocaleMap.get(iso3.toUpperCase());
}
public static Locale getCurrentLocale(Context context){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
public static Locale getCurrentLocale(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return context.getResources().getConfiguration().getLocales().get(0);
} else{
} else {
//noinspection deprecation
return context.getResources().getConfiguration().locale;
}
@ -151,6 +151,20 @@ public class LanguageUtils {
return "fonts/DejaVuSansCondensed.ttf";
}
public static String getResourceString(Context appContext, String str) {
String resourceName = str;
if (resourceName.contains("REPLACE_")) {
resourceName = resourceName.replace("REPLACE_", "");
}
int resourceId = appContext.getResources()
.getIdentifier(
resourceName,
"string",
appContext.getPackageName()
);
return appContext.getResources().getString(resourceId);
}
// Read the language codes, that are supported in this app from the locales.txt file
private void getLanguageCodesFromAssets() {

View File

@ -0,0 +1,10 @@
package org.kiwix.kiwixmobile.utils;
import static org.kiwix.kiwixmobile.utils.Constants.NEW_PROVIDER_DOMAIN;
import static org.kiwix.kiwixmobile.utils.Constants.OLD_PROVIDER_DOMAIN;
public class UpdateUtils {
public static String reformatProviderUrl(String url) {
return url.replace(OLD_PROVIDER_DOMAIN, NEW_PROVIDER_DOMAIN);
}
}

View File

@ -27,6 +27,7 @@ import android.provider.DocumentsContract;
import android.util.Log;
import org.kiwix.kiwixmobile.BuildConfig;
import org.kiwix.kiwixmobile.downloader.ChunkUtils;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
import java.io.File;
@ -61,8 +62,8 @@ public class FileUtils {
}
public static synchronized void deleteZimFile(String path) {
if (path.substring(path.length() - 5).equals(".part")) {
path = path.substring(0, path.length() - 5);
if (path.substring(path.length() - ChunkUtils.PART.length()).equals(ChunkUtils.PART)) {
path = path.substring(0, path.length() - ChunkUtils.PART.length());
}
Log.i("kiwix", "Deleting file: " + path);
File file = new File(path);
@ -86,10 +87,16 @@ public class FileUtils {
}
private static synchronized boolean deleteZimFileParts(String path) {
File file = new File(path + ".part");
File file = new File(path + ChunkUtils.PART);
if (file.exists()) {
file.delete();
return true;
} else {
File singlePart = new File(path + ".part");
if (singlePart.exists()) {
singlePart.delete();
return true;
}
}
return false;
}
@ -206,15 +213,16 @@ public class FileUtils {
stream.read(buffer);
stream.close();
content = new String(buffer);
} catch (IOException ignored) { }
} catch (IOException ignored) {
}
return readCsv(content);
}
public static List<File> getAllZimParts(Book book) {
List<File> files = new ArrayList<>();
if(book.file.getPath().endsWith(".zim") || book.file.getPath().endsWith(".zim.part")) {
if(book.file.exists()) {
if (book.file.getPath().endsWith(".zim") || book.file.getPath().endsWith(".zim.part")) {
if (book.file.exists()) {
files.add(book.file);
} else {
files.add(new File(book.file + ".part"));
@ -222,12 +230,12 @@ public class FileUtils {
return files;
}
String path = book.file.getPath();
for(char alphabetFirst = 'a'; alphabetFirst <= 'z'; alphabetFirst++) {
for(char alphabetSecond = 'a'; alphabetSecond <= 'z'; alphabetSecond++) {
for (char alphabetFirst = 'a'; alphabetFirst <= 'z'; alphabetFirst++) {
for (char alphabetSecond = 'a'; alphabetSecond <= 'z'; alphabetSecond++) {
path = path.substring(0, path.length() - 2) + alphabetFirst + alphabetSecond;
if(new File(path).exists()) {
if (new File(path).exists()) {
files.add(new File(path));
} else if(new File(path + ".part").exists()) {
} else if (new File(path + ".part").exists()) {
files.add(new File(path + ".part"));
} else {
return files;
@ -267,7 +275,7 @@ public class FileUtils {
return false;
}
public static String getFileName (String fileName) {
public static String getFileName(String fileName) {
if (new File(fileName).exists()) {
return fileName;
} else if (new File(fileName + ".part").exists()) {

View File

@ -163,11 +163,11 @@ public class ZimFileSelectFragment extends BaseFragment
public void checkPermissions() {
if (ContextCompat.checkSelfPermission(zimManageActivity,
Manifest.permission.READ_EXTERNAL_STORAGE)
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED && Build.VERSION.SDK_INT > 18) {
Toast.makeText(super.getActivity(), getResources().getString(R.string.request_storage), Toast.LENGTH_LONG)
.show();
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE_PERMISSION);
} else {
getFiles();

View File

@ -44,6 +44,7 @@
<item name="android:textColorPrimary">@color/primary_light</item>
<item name="android:textColorSecondary">@color/primary_light</item>
<item name="android:textColorTertiary">@color/primary_light</item>
<item name="android:alertDialogTheme">@style/AppTheme.Dialog.Night</item>
<item name="colorControlNormal">@color/accent</item>
</style>
@ -79,10 +80,12 @@
<style name="AppTheme.Dialog.Night" parent="Theme.AppCompat.DayNight.Dialog.Alert">
<item name="colorAccent">@color/accent</item>
<item name="android:textColorPrimary">@color/white</item>
<item name="android:colorBackground">@color/cardview_dark_background</item>
<item name="buttonBarNegativeButtonStyle">@style/NegativeButtonStyle</item>
<item name="buttonBarPositiveButtonStyle">@style/PositiveButtonStyle</item>
<item name="buttonBarNeutralButtonStyle">@style/NeutralButtonStyle</item>
<item name="android:textColorAlertDialogListItem">@color/white</item>
<item name="android:windowBackground">@color/cardview_dark_background</item>
<item name="android:textColorSecondary">@color/primary_light</item>
</style>
<style name="NegativeButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">

View File

@ -16,7 +16,7 @@ runID = os.environ['TRAVIS_BUILD_NUMBER']
apiKey = os.environ['BITBAR_API_KEY']
testName = "Auto Test {}".format(runID)
for x in range(0, 50):
for x in range(0, 200):
r = requests.get('https://cloud.testdroid.com/api/me/projects/{}/runs'.format(PROJECT_ID), auth=(apiKey, ''), headers={"Accept" : "application/json"})
result = list(filter(lambda run: run.get("displayName") == testName, r.json().get("data")))
if len(result) > 0 and result[0].get("state") == "FINISHED":