use of com.ichi2.libanki.Media in project Anki-Android by Ramblurr.
the class Media method _changes.
private Pair<List<String>, List<String>> _changes() {
Map<String, Pair<String, Long>> cache = new HashMap<String, Pair<String, Long>>();
Map<String, Boolean> used = new HashMap<String, Boolean>();
Cursor cur = null;
try {
cur = mMediaDb.getDatabase().query("media", new String[] { "fname", "csum", "mod" }, null, null, null, null, null);
while (cur.moveToNext()) {
cache.put(cur.getString(0), new Pair<String, Long>(cur.getString(1), cur.getLong(1)));
used.put(cur.getString(0), false);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (cur != null) {
cur.close();
}
}
List<String> added = new ArrayList<String>();
List<String> removed = new ArrayList<String>();
File mediaDir = new File(getDir());
for (File f : mediaDir.listFiles()) {
// ignore folders and thumbs.db
if (f.isDirectory()) {
continue;
}
String fname = f.getName();
if (fname.compareTo("thumbs.db") == 0) {
continue;
}
// and files with invalid chars
boolean bad = false;
for (String c : new String[] { "\0", "/", "\\", ":" }) {
if (fname.contains(c)) {
bad = true;
break;
}
}
if (bad) {
continue;
}
// empty files are invalid; clean them up and continue
if (f.length() == 0) {
f.delete();
continue;
}
// newly added?
if (!cache.containsKey(fname)) {
added.add(fname);
} else {
// modified since last time?
if ((f.lastModified() / 1000) != cache.get(fname).second) {
// and has different checksum?
if (_checksum(f.getAbsolutePath()).compareTo(cache.get(fname).first) != 0) {
added.add(fname);
}
}
// mark as used
used.put(fname, true);
}
}
// look for any entries in the cache that no longer exist on disk
for (String fname : used.keySet()) {
if (!used.get(fname)) {
removed.add(fname);
}
}
return new Pair<List<String>, List<String>>(added, removed);
}
use of com.ichi2.libanki.Media in project Anki-Android by Ramblurr.
the class Connection method doInBackgroundSync.
private Payload doInBackgroundSync(Payload data) {
// for for doInBackgroundLoadDeckCounts if any
DeckTask.waitToFinish();
String hkey = (String) data.data[0];
boolean media = (Boolean) data.data[1];
String conflictResolution = (String) data.data[2];
int mediaUsn = (Integer) data.data[3];
boolean colCorruptFullSync = false;
Collection col = AnkiDroidApp.getCol();
if (!AnkiDroidApp.colIsOpen()) {
if (conflictResolution != null && conflictResolution.equals("download")) {
colCorruptFullSync = true;
} else {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
}
String path = AnkiDroidApp.getCollectionPath();
BasicHttpSyncer server = new RemoteServer(this, hkey);
Syncer client = new Syncer(col, server);
// run sync and check state
boolean noChanges = false;
if (conflictResolution == null) {
// Log.i(AnkiDroidApp.TAG, "Sync - starting sync");
publishProgress(R.string.sync_prepare_syncing);
Object[] ret = client.sync(this);
data.message = client.getSyncMsg();
mediaUsn = client.getmMediaUsn();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
String retCode = (String) ret[0];
if (!retCode.equals("noChanges") && !retCode.equals("success")) {
data.success = false;
data.result = ret;
// note mediaUSN for later
data.data = new Object[] { mediaUsn };
return data;
}
// save and note success state
if (retCode.equals("noChanges")) {
// publishProgress(R.string.sync_no_changes_message);
noChanges = true;
} else {
// publishProgress(R.string.sync_database_success);
}
} else {
try {
server = new FullSyncer(col, hkey, this);
if (conflictResolution.equals("upload")) {
// Log.i(AnkiDroidApp.TAG, "Sync - fullsync - upload collection");
publishProgress(R.string.sync_preparing_full_sync_message);
Object[] ret = server.upload();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
AnkiDroidApp.openCollection(path);
return data;
}
if (!((String) ret[0]).equals(BasicHttpSyncer.ANKIWEB_STATUS_OK)) {
data.success = false;
data.result = ret;
AnkiDroidApp.openCollection(path);
return data;
}
} else if (conflictResolution.equals("download")) {
// Log.i(AnkiDroidApp.TAG, "Sync - fullsync - download collection");
publishProgress(R.string.sync_downloading_message);
Object[] ret = server.download();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
AnkiDroidApp.openCollection(path);
return data;
}
if (!((String) ret[0]).equals("success")) {
data.success = false;
data.result = ret;
if (!colCorruptFullSync) {
AnkiDroidApp.openCollection(path);
}
return data;
}
}
col = AnkiDroidApp.openCollection(path);
} catch (OutOfMemoryError e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-fullSync");
data.success = false;
data.result = new Object[] { "OutOfMemoryError" };
data.data = new Object[] { mediaUsn };
return data;
} catch (RuntimeException e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-fullSync");
data.success = false;
data.result = new Object[] { "IOException" };
data.data = new Object[] { mediaUsn };
return data;
}
}
// clear undo to avoid non syncing orphans (because undo resets usn too
if (!noChanges) {
col.clearUndo();
}
// then move on to media sync
boolean noMediaChanges = false;
String mediaError = null;
if (media) {
server = new RemoteMediaServer(hkey, this);
MediaSyncer mediaClient = new MediaSyncer(col, (RemoteMediaServer) server);
String ret;
try {
ret = mediaClient.sync(mediaUsn, this);
if (ret == null) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_error);
} else {
if (ret.equals("noChanges")) {
publishProgress(R.string.sync_media_no_changes);
noMediaChanges = true;
}
if (ret.equals("sanityFailed")) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_sanity_failed);
} else {
publishProgress(R.string.sync_media_success);
}
}
} catch (RuntimeException e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-mediaSync");
mediaError = e.getLocalizedMessage();
}
}
if (noChanges && noMediaChanges) {
data.success = false;
data.result = new Object[] { "noChanges" };
return data;
} else {
data.success = true;
TreeSet<Object[]> decks = col.getSched().deckDueTree();
int[] counts = new int[] { 0, 0, 0 };
for (Object[] deck : decks) {
if (((String[]) deck[0]).length == 1) {
counts[0] += (Integer) deck[2];
counts[1] += (Integer) deck[3];
counts[2] += (Integer) deck[4];
}
}
Object[] dc = col.getSched().deckCounts();
data.result = dc[0];
data.data = new Object[] { conflictResolution, col, dc[1], dc[2], mediaError };
return data;
}
}
use of com.ichi2.libanki.Media in project Anki-Android by Ramblurr.
the class DeckPicker method sync.
/**
* The mother of all syncing attempts. This might be called from sync() as first attempt to sync a collection OR
* from the mSyncConflictResolutionListener if the first attempt determines that a full-sync is required. In the
* second case, we have passed the mediaUsn that was obtained during the first attempt.
*
* @param syncConflictResolution Either "upload" or "download", depending on the user's choice.
* @param syncMediaUsn The media Usn, as determined during the prior sync() attempt that determined that full
* syncing was required.
*/
private void sync(String syncConflictResolution, int syncMediaUsn) {
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
String hkey = preferences.getString("hkey", "");
if (hkey.length() == 0) {
showDialog(DIALOG_USER_NOT_LOGGED_IN_SYNC);
} else {
Connection.sync(mSyncListener, new Connection.Payload(new Object[] { hkey, preferences.getBoolean("syncFetchesMedia", true), syncConflictResolution, syncMediaUsn }));
}
}
use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.
the class SettingFragment method onClick.
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.user_protocol) {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_USER_PROTOCOL, "");
} else if (id == R.id.user_private) {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_PRIVATE, "");
} else if (id == R.id.rl_market_like) {
goAppShop(getAnkiActivity(), BuildConfig.APPLICATION_ID, "");
} else if (id == R.id.vip_power) {
Timber.i("click vip button");
getAnkiActivity().openVipUrl(mVipUrl);
} else if (id == R.id.rl_anki_course || id == R.id.rl_team || id == R.id.rl_version || id == R.id.rl_feedback) {
if (id == R.id.rl_anki_course) {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_ANKI_COURSE, "");
} else if (id == R.id.rl_version) {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_VERSION, "");
} else if (id == R.id.rl_team) {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_VOLUNTEER, "");
} else {
WebViewActivity.openUrlInApp(getAnkiActivity(), URL_FEEDBACK, "");
}
} else if (id == R.id.ll_switch_server) {
final Dialog dialog = new Dialog(getAnkiActivity(), R.style.DialogTheme);
dialog.setContentView(R.layout.dialog_switch_server);
Window dialogWindow = dialog.getWindow();
dialogWindow.setGravity(Gravity.TOP | Gravity.LEFT);
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
int notificationBar = Resources.getSystem().getDimensionPixelSize(Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android"));
int[] location = new int[2];
// 获取在当前窗体内的绝对坐标
mLl_switch_server.getLocationInWindow(location);
// 获取在整个屏幕内的绝对坐标
mLl_switch_server.getLocationOnScreen(location);
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.x = location[0];
lp.y = location[1] + mLl_switch_server.getHeight() - notificationBar + 20;
dialogWindow.setAttributes(lp);
updateSwitchServerDialog(dialog);
dialog.findViewById(R.id.rl_over_sea_server).setOnClickListener(view -> {
String account = AnkiDroidApp.getSharedPrefs(getAnkiActivity()).getString(Consts.KEY_SAVED_ANKI_WEB_ACCOUNT, "");
if (account.isEmpty()) {
// 未登陆,跳转到登陆
Intent myAccount = new Intent(getAnkiActivity(), MyAccount2.class);
myAccount.putExtra("notLoggedIn", true);
getAnkiActivity().startActivityWithAnimation(myAccount, ActivityTransitionAnimation.FADE);
} else if (Consts.LOGIN_SERVER == Consts.LOGIN_SERVER_ANKICHINA) {
// 已登陆,切换为当前状态
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getAnkiActivity());
SharedPreferences.Editor editor = preferences.edit();
editor.putString("username", preferences.getString(Consts.KEY_SAVED_ANKI_WEB_ACCOUNT, ""));
editor.putString("hkey", preferences.getString(Consts.KEY_SAVED_ANKI_WEB_HKEY, ""));
editor.putString("token", "");
Consts.LOGIN_SERVER = Consts.LOGIN_SERVER_ANKIWEB;
editor.putInt(Consts.KEY_ANKI_ACCOUNT_SERVER, Consts.LOGIN_SERVER);
editor.apply();
HostNumFactory.getInstance(getAnkiActivity()).reset();
// force media resync on deauth
getAnkiActivity().getCol().getMedia().forceResync();
MobclickAgent.onProfileSignOff();
updateSwitchServerLayout();
}
checkRestServerSpace();
dialog.dismiss();
});
dialog.findViewById(R.id.rl_china_server).setOnClickListener(view -> {
String account = AnkiDroidApp.getSharedPrefs(getAnkiActivity()).getString(Consts.KEY_SAVED_ANKI_CHINA_PHONE, "");
if (account.isEmpty()) {
// 未登陆,跳转到登陆
Intent myAccount = new Intent(getAnkiActivity(), MyAccount.class);
myAccount.putExtra("notLoggedIn", true);
getAnkiActivity().startActivityWithAnimation(myAccount, ActivityTransitionAnimation.FADE);
} else if (Consts.LOGIN_SERVER == Consts.LOGIN_SERVER_ANKIWEB) {
// 已登陆,切换为当前状态
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getAnkiActivity());
SharedPreferences.Editor editor = preferences.edit();
// 切换为ankichina的登陆状态
editor.putString("username", preferences.getString(Consts.KEY_SAVED_ANKI_CHINA_PHONE, ""));
editor.putString("hkey", preferences.getString(Consts.KEY_SAVED_ANKI_CHINA_HKEY, ""));
editor.putString("token", preferences.getString(Consts.KEY_SAVED_ANKI_CHINA_TOKEN, ""));
Consts.LOGIN_SERVER = Consts.LOGIN_SERVER_ANKICHINA;
editor.putInt(Consts.KEY_ANKI_ACCOUNT_SERVER, Consts.LOGIN_SERVER);
editor.apply();
HostNumFactory.getInstance(getAnkiActivity()).reset();
getAnkiActivity().getCol().getMedia().forceResync();
MobclickAgent.onProfileSignOff();
updateSwitchServerLayout();
}
checkRestServerSpace();
dialog.dismiss();
});
dialog.show();
}
}
use of com.ichi2.libanki.Media in project AnkiChinaAndroid by ankichinateam.
the class NoteEditor method populateEditFields.
private void populateEditFields(FieldChangeType type, boolean editModelMode) {
List<FieldEditLine> editLines = mFieldState.loadFieldEditLines(type);
mFieldsLayoutContainer.removeAllViews();
mCustomViewIds.clear();
mEditFields = new LinkedList<>();
// Use custom font if selected from preferences
Typeface mCustomTypeface = null;
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
String customFont = preferences.getString("browserEditorFont", "");
if (!"".equals(customFont)) {
mCustomTypeface = AnkiFont.getTypeface(this, customFont);
}
ClipboardManager clipboard = ContextCompat.getSystemService(this, ClipboardManager.class);
FieldEditLine previous = null;
mCustomViewIds.ensureCapacity(editLines.size());
for (int i = 0; i < editLines.size(); i++) {
FieldEditLine edit_line_view = editLines.get(i);
mCustomViewIds.add(edit_line_view.getId());
FieldEditText newTextbox = edit_line_view.getEditText();
newTextbox.setImagePasteListener(this::onImagePaste);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
if (i == 0) {
findViewById(R.id.note_deck_spinner).setNextFocusForwardId(newTextbox.getId());
}
if (previous != null) {
previous.getLastViewInTabOrder().setNextFocusForwardId(newTextbox.getId());
}
}
previous = edit_line_view;
edit_line_view.setEnableAnimation(animationEnabled());
// TODO: Remove the >= M check - one callback works on API 11.
if (CompatHelper.getSdkVersion() >= Build.VERSION_CODES.M) {
// Use custom implementation of ActionMode.Callback customize selection and insert menus
Field f = new Field(getFieldByIndex(i), getCol());
ActionModeCallback actionModeCallback = new ActionModeCallback(newTextbox, f);
edit_line_view.setActionModeCallbacks(actionModeCallback);
}
edit_line_view.setTypeface(mCustomTypeface);
edit_line_view.setHintLocale(getHintLocaleForField(edit_line_view.getName()));
initFieldEditText(newTextbox, i, !editModelMode);
mEditFields.add(newTextbox);
SharedPreferences prefs = AnkiDroidApp.getSharedPrefs(this);
if (prefs.getInt("note_editor_font_size", -1) > 0) {
newTextbox.setTextSize(prefs.getInt("note_editor_font_size", -1));
}
newTextbox.setCapitalize(prefs.getBoolean("note_editor_capitalize", true));
ImageButton mediaButton = edit_line_view.getMediaButton();
// Load icons from attributes
int[] icons = Themes.getResFromAttr(this, new int[] { R.attr.attachFileImage, R.attr.upDownImage });
// Make the icon change between media icon and switch field icon depending on whether editing note type
if (editModelMode && allowFieldRemapping()) {
// Allow remapping if originally more than two fields
mediaButton.setBackgroundResource(icons[1]);
setRemapButtonListener(mediaButton, i);
} else if (editModelMode && !allowFieldRemapping()) {
mediaButton.setBackgroundResource(0);
} else {
// Use media editor button if not changing note type
mediaButton.setBackgroundResource(icons[0]);
setMMButtonListener(mediaButton, i);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && previous != null) {
previous.getLastViewInTabOrder().setNextFocusForwardId(R.id.CardEditorTagButton);
}
mediaButton.setContentDescription(getString(R.string.multimedia_editor_attach_mm_content, edit_line_view.getName()));
mFieldsLayoutContainer.addView(edit_line_view);
}
}
Aggregations