use of com.ichi2.libanki.Collection in project Anki-Android by Ramblurr.
the class StudyOptionsFragment method createFilteredDeck.
private void createFilteredDeck(JSONArray delays, Object[] terms, Boolean resched) {
JSONObject dyn;
if (AnkiDroidApp.colIsOpen()) {
Collection col = AnkiDroidApp.getCol();
try {
String deckName = col.getDecks().current().getString("name");
String customStudyDeck = getResources().getString(R.string.custom_study_deck_name);
JSONObject cur = col.getDecks().byName(customStudyDeck);
if (cur != null) {
if (cur.getInt("dyn") != 1) {
StyledDialog.Builder builder = new StyledDialog.Builder(getActivity());
builder.setMessage(R.string.custom_study_deck_exists);
builder.setNegativeButton(getResources().getString(R.string.cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//
}
});
builder.create().show();
return;
} else {
// safe to empty
col.getSched().emptyDyn(cur.getLong("id"));
// reuse; don't delete as it may have children
dyn = cur;
col.getDecks().select(cur.getLong("id"));
}
} else {
long did = col.getDecks().newDyn(customStudyDeck);
dyn = col.getDecks().get(did);
}
// and then set various options
dyn.put("delays", delays);
JSONArray ar = dyn.getJSONArray("terms");
ar.getJSONArray(0).put(0, new StringBuilder("deck:\"").append(deckName).append("\" ").append(terms[0]).toString());
ar.getJSONArray(0).put(1, terms[1]);
ar.getJSONArray(0).put(2, terms[2]);
dyn.put("resched", resched);
if (mFragmented) {
Bundle config = new Bundle();
config.putString("searchSuffix", "'deck:" + dyn.getString("name") + "'");
initAllContentViews(getLayoutInflater(config));
finishCongrats();
} else {
// Load a new fragment with the filtered deck view. The config passed is null, so it uses the
// current deck. The deck we just created is internally set as the current deck.
((StudyOptionsActivity) getActivity()).loadContent(false, null);
}
// Initial rebuild
mProgressDialog = StyledProgressDialog.show(getActivity(), "", getResources().getString(R.string.rebuild_custom_study_deck), true);
DeckTask.launchDeckTask(DeckTask.TASK_TYPE_REBUILD_CRAM, mRebuildCustomStudyListener, new DeckTask.TaskData(AnkiDroidApp.getCol(), AnkiDroidApp.getCol().getDecks().selected(), mFragmented));
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
use of com.ichi2.libanki.Collection in project Anki-Android by Ramblurr.
the class StudyOptionsFragment method onPrepareDialog.
private void onPrepareDialog(int id, StyledDialog styledDialog) {
Resources res = getResources();
switch(id) {
case DIALOG_CUSTOM_STUDY_DETAILS:
styledDialog.setTitle(res.getStringArray(R.array.custom_study_options_labels)[mCustomDialogChoice]);
switch(mCustomDialogChoice + 1) {
case CUSTOM_STUDY_NEW:
if (AnkiDroidApp.colIsOpen()) {
Collection col = AnkiDroidApp.getCol();
mCustomStudyTextView1.setText(res.getString(R.string.custom_study_new_total_new, col.getSched().totalNewForCurrentDeck()));
}
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_new_extend));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("extendNew", 10)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (AnkiDroidApp.colIsOpen()) {
try {
int n = Integer.parseInt(mCustomStudyEditText.getText().toString());
AnkiDroidApp.getSharedPrefs(getActivity()).edit().putInt("extendNew", n).commit();
Collection col = AnkiDroidApp.getCol();
JSONObject deck = col.getDecks().current();
deck.put("extendNew", n);
col.getDecks().save(deck);
col.getSched().extendLimits(n, 0);
resetAndUpdateValuesFromDeck();
finishCongrats();
} catch (NumberFormatException e) {
// ignore non numerical values
Themes.showThemedToast(getActivity().getBaseContext(), getResources().getString(R.string.custom_study_invalid_number), false);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
});
break;
case CUSTOM_STUDY_REV:
if (AnkiDroidApp.colIsOpen()) {
Collection col = AnkiDroidApp.getCol();
mCustomStudyTextView1.setText(res.getString(R.string.custom_study_rev_total_rev, col.getSched().totalRevForCurrentDeck()));
}
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_rev_extend));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("extendRev", 10)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (AnkiDroidApp.colIsOpen()) {
try {
int n = Integer.parseInt(mCustomStudyEditText.getText().toString());
AnkiDroidApp.getSharedPrefs(getActivity()).edit().putInt("extendRev", n).commit();
Collection col = AnkiDroidApp.getCol();
JSONObject deck = col.getDecks().current();
deck.put("extendRev", n);
col.getDecks().save(deck);
col.getSched().extendLimits(0, n);
resetAndUpdateValuesFromDeck();
finishCongrats();
} catch (NumberFormatException e) {
// ignore non numerical values
Themes.showThemedToast(getActivity().getBaseContext(), getResources().getString(R.string.custom_study_invalid_number), false);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
});
break;
case CUSTOM_STUDY_FORGOT:
mCustomStudyTextView1.setText("");
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_forgotten));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("forgottenDays", 2)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
JSONArray ar = new JSONArray();
try {
int forgottenDays = Integer.parseInt(((EditText) mCustomStudyEditText).getText().toString());
ar.put(0, 1);
createFilteredDeck(ar, new Object[] { String.format(Locale.US, "rated:%d:1", forgottenDays), 9999, Sched.DYN_RANDOM }, false);
} catch (NumberFormatException e) {
// ignore non numerical values
Themes.showThemedToast(getActivity().getBaseContext(), getResources().getString(R.string.custom_study_invalid_number), false);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
});
break;
case CUSTOM_STUDY_AHEAD:
mCustomStudyTextView1.setText("");
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_ahead));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("aheadDays", 1)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
int days = Integer.parseInt(((EditText) mCustomStudyEditText).getText().toString());
createFilteredDeck(new JSONArray(), new Object[] { String.format(Locale.US, "prop:due<=%d", days), 9999, Sched.DYN_DUE }, true);
} catch (NumberFormatException e) {
// ignore non numerical values
Themes.showThemedToast(getActivity().getBaseContext(), getResources().getString(R.string.custom_study_invalid_number), false);
}
}
});
break;
case CUSTOM_STUDY_RANDOM:
mCustomStudyTextView1.setText("");
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_random));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("randomCards", 100)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
int randomCards = Integer.parseInt(((EditText) mCustomStudyEditText).getText().toString());
createFilteredDeck(new JSONArray(), new Object[] { "", randomCards, Sched.DYN_RANDOM }, true);
} catch (NumberFormatException e) {
// ignore non numerical values
Themes.showThemedToast(getActivity().getBaseContext(), getResources().getString(R.string.custom_study_invalid_number), false);
}
}
});
break;
case CUSTOM_STUDY_PREVIEW:
mCustomStudyTextView1.setText("");
mCustomStudyTextView2.setText(res.getString(R.string.custom_study_preview));
mCustomStudyEditText.setText(Integer.toString(AnkiDroidApp.getSharedPrefs(getActivity()).getInt("previewDays", 1)));
styledDialog.setButtonOnClickListener(Dialog.BUTTON_POSITIVE, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String previewDays = ((EditText) mCustomStudyEditText).getText().toString();
createFilteredDeck(new JSONArray(), new Object[] { "is:new added:" + previewDays, 9999, Sched.DYN_OLDEST }, false);
}
});
break;
}
}
}
use of com.ichi2.libanki.Collection in project Anki-Android by Ramblurr.
the class Connection method doInBackgroundUpgradeDecks.
private Payload doInBackgroundUpgradeDecks(Payload data) {
// Enable http request canceller
mCancelCallback = new CancelCallback();
String path = (String) data.data[0];
File ankiDir = new File(path);
if (!ankiDir.isDirectory()) {
data.success = false;
data.data = new Object[] { "wrong anki directory" };
return data;
}
// step 1: gather all .anki files into a zip, without media.
// we must store them as 1.anki, 2.anki and provide a map so we don't run into
// encoding issues with the zip file.
File[] fileList = ankiDir.listFiles(new OldAnkiDeckFilter());
List<String> corruptFiles = new ArrayList<String>();
JSONObject map = new JSONObject();
byte[] buf = new byte[1024];
String zipFilename = path + "/upload.zip";
String colFilename = path + AnkiDroidApp.COLLECTION_PATH;
try {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilename));
int n = 1;
for (File f : fileList) {
String deckPath = f.getAbsolutePath();
// set journal mode to delete
try {
AnkiDb d = AnkiDatabaseManager.getDatabase(deckPath);
} catch (SQLiteDatabaseCorruptException e) {
// ignore invalid .anki files
corruptFiles.add(f.getName());
continue;
} finally {
AnkiDatabaseManager.closeDatabase(deckPath);
}
// zip file
String tmpName = n + ".anki";
FileInputStream in = new FileInputStream(deckPath);
ZipEntry ze = new ZipEntry(tmpName);
zos.putNextEntry(ze);
int len;
while ((len = in.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
map.put(tmpName, f.getName());
n++;
}
// if all .anki files were found corrupted, abort
if (fileList.length == corruptFiles.size()) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
ZipEntry ze = new ZipEntry("map.json");
zos.putNextEntry(ze);
InputStream in = new ByteArrayInputStream(Utils.jsonToString(map).getBytes("UTF-8"));
int len;
while ((len = in.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
zos.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
File zipFile = new File(zipFilename);
// step 1.1: if it's over 50MB compressed, it must be upgraded by the user
if (zipFile.length() > 50 * 1024 * 1024) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_exceeds) };
return data;
}
// step 2: upload zip file to upgrade service and get token
BasicHttpSyncer h = new BasicHttpSyncer(null, null);
// note: server doesn't expect it to be gzip compressed, because the zip file is compressed
// enable cancelling
publishProgress(R.string.upgrade_decks_upload, null, true);
try {
HttpResponse resp = h.req("upgrade/upload", new FileInputStream(zipFile), 0, false, null, mCancelCallback);
if (resp == null && !isCancelled()) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
String result;
String key = null;
if (!isCancelled()) {
result = h.stream2String(resp.getEntity().getContent());
if (result != null && result.startsWith("ok:")) {
key = result.split(":")[1];
} else {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
}
while (!isCancelled()) {
result = h.stream2String(h.req("upgrade/status?key=" + key).getEntity().getContent());
if (result.equals("error")) {
data.success = false;
data.data = new Object[] { "error" };
return data;
} else if (result.startsWith("waiting:")) {
publishProgress(R.string.upgrade_decks_upload, result.split(":")[1]);
} else if (result.equals("upgrading")) {
publishProgress(new Object[] { R.string.upgrade_decks_upgrade_started });
} else if (result.equals("ready")) {
break;
} else {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
Thread.sleep(1000);
}
// gzip compression if the client says it can handle it
if (!isCancelled()) {
publishProgress(new Object[] { R.string.upgrade_decks_downloading });
resp = h.req("upgrade/download?key=" + key, null, 6, true, null, mCancelCallback);
// uploads/downloads have finished so disable cancelling
}
publishProgress(R.string.upgrade_decks_downloading, null, false);
if (isCancelled()) {
return null;
}
if (resp == null) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_failed) };
return data;
}
// step 5: check the received file is valid
InputStream cont = resp.getEntity().getContent();
if (!h.writeToFile(cont, colFilename)) {
data.success = false;
data.data = new Object[] { sContext.getString(R.string.upgrade_deck_web_upgrade_sdcard, new File(colFilename).length() / 1048576 + 1) };
(new File(colFilename)).delete();
return data;
}
// check the received file is ok
publishProgress(new Object[] { R.string.sync_check_download_file });
publishProgress(R.string.sync_check_download_file);
try {
AnkiDb d = AnkiDatabaseManager.getDatabase(colFilename);
if (!d.queryString("PRAGMA integrity_check").equalsIgnoreCase("ok")) {
data.success = false;
data.data = new Object[] { sContext.getResources() };
return data;
}
} finally {
AnkiDatabaseManager.closeDatabase(colFilename);
}
Collection col = AnkiDroidApp.openCollection(colFilename);
ArrayList<String> decks = col.getDecks().allNames(false);
ArrayList<String> failed = new ArrayList<String>();
ArrayList<File> mediaDirs = new ArrayList<File>();
for (File f : fileList) {
String name = f.getName().replaceFirst("\\.anki$", "");
if (!decks.contains(name)) {
failed.add(name);
} else {
mediaDirs.add(new File(f.getAbsolutePath().replaceFirst("\\.anki$", ".media")));
}
}
File newMediaDir = new File(col.getMedia().getDir());
// step 6. move media files to new media directory
publishProgress(new Object[] { R.string.upgrade_decks_media });
ArrayList<String> failedMedia = new ArrayList<String>();
File curMediaDir = null;
for (File mediaDir : mediaDirs) {
curMediaDir = mediaDir;
// Check if media directory exists and is local
if (!curMediaDir.exists() || !curMediaDir.isDirectory()) {
// If not try finding it in dropbox 1.2.x
curMediaDir = new File(AnkiDroidApp.getDropboxDir(), mediaDir.getName());
if (!curMediaDir.exists() || !curMediaDir.isDirectory()) {
// No media for this deck
continue;
}
}
// Found media dir, copy files
for (File m : curMediaDir.listFiles()) {
try {
Utils.copyFile(m, new File(newMediaDir, m.getName()));
} catch (IOException e) {
failedMedia.add(curMediaDir.getName().replaceFirst("\\.media$", ".anki"));
break;
}
}
}
data.data = new Object[] { failed, failedMedia, newMediaDir.getAbsolutePath() };
data.success = true;
return data;
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (IllegalStateException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
(new File(zipFilename)).delete();
}
}
use of com.ichi2.libanki.Collection in project Anki-Android by Ramblurr.
the class DeckTask method doInBackgroundExportApkg.
private TaskData doInBackgroundExportApkg(TaskData... params) {
Log.i(AnkiDroidApp.TAG, "doInBackgroundExportApkg");
Object[] data = params[0].getObjArray();
String colPath = (String) data[0];
String apkgPath = (String) data[1];
boolean includeMedia = (Boolean) data[2];
byte[] buf = new byte[1024];
try {
try {
AnkiDb d = AnkiDatabaseManager.getDatabase(colPath);
} catch (SQLiteDatabaseCorruptException e) {
// collection is invalid
return new TaskData(false);
} finally {
AnkiDatabaseManager.closeDatabase(colPath);
}
// export collection
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(apkgPath));
FileInputStream colFin = new FileInputStream(colPath);
ZipEntry ze = new ZipEntry("collection.anki2");
zos.putNextEntry(ze);
int len;
while ((len = colFin.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
colFin.close();
// export media
JSONObject media = new JSONObject();
if (includeMedia) {
File mediaDir = new File(AnkiDroidApp.getCurrentAnkiDroidMediaDir());
if (mediaDir.exists() && mediaDir.isDirectory()) {
File[] mediaFiles = mediaDir.listFiles();
int c = 0;
for (File f : mediaFiles) {
FileInputStream mediaFin = new FileInputStream(f);
ze = new ZipEntry(Integer.toString(c));
zos.putNextEntry(ze);
while ((len = mediaFin.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
media.put(Integer.toString(c), f.getName());
}
}
}
ze = new ZipEntry("media");
zos.putNextEntry(ze);
InputStream mediaIn = new ByteArrayInputStream(Utils.jsonToString(media).getBytes("UTF-8"));
while ((len = mediaIn.read(buf)) >= 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
zos.close();
} catch (FileNotFoundException e) {
return new TaskData(false);
} catch (IOException e) {
return new TaskData(false);
} catch (JSONException e) {
return new TaskData(false);
}
return new TaskData(true);
}
use of com.ichi2.libanki.Collection in project Anki-Android by Ramblurr.
the class DeckTask method doInBackgroundCheckDatabase.
private TaskData doInBackgroundCheckDatabase(TaskData... params) {
Log.i(AnkiDroidApp.TAG, "doInBackgroundCheckDatabase");
Collection col = params[0].getCollection();
long result = col.fixIntegrity();
if (result == -1) {
return new TaskData(false);
} else {
return new TaskData(0, result, true);
}
}
Aggregations