1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-04 10:19:33 +02:00

Merge branch 'master' into basket

This commit is contained in:
Nikolay Pultsin 2011-02-28 16:18:52 +03:00
commit b5b1699f03
33 changed files with 488 additions and 334 deletions

View file

@ -131,9 +131,17 @@
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.NetworkLibraryActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden">
<activity android:name="org.geometerplus.android.fbreader.network.NetworkLibraryActivity" android:process=":networkLibrary" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden">
<meta-data android:name="android.app.default_searchable" android:value="org.geometerplus.android.fbreader.network.NetworkSearchActivity" />
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.AddCustomCatalogActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" android:theme="@android:style/Theme.Dialog">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="*" android:scheme="opds" />
</intent-filter>
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.NetworkCatalogActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" />
<service android:name="org.geometerplus.android.fbreader.network.ItemsLoadingService" android:process=":networkLibrary" />
<activity android:name="org.geometerplus.android.fbreader.network.NetworkBookInfoActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" />

View file

@ -131,9 +131,17 @@
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.NetworkLibraryActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden">
<activity android:name="org.geometerplus.android.fbreader.network.NetworkLibraryActivity" android:process=":networkLibrary" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden">
<meta-data android:name="android.app.default_searchable" android:value="org.geometerplus.android.fbreader.network.NetworkSearchActivity" />
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.AddCustomCatalogActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" android:theme="@android:style/Theme.Dialog">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="*" android:scheme="opds" />
</intent-filter>
</activity>
<activity android:name="org.geometerplus.android.fbreader.network.NetworkCatalogActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" />
<service android:name="org.geometerplus.android.fbreader.network.ItemsLoadingService" android:process=":networkLibrary" />
<activity android:name="org.geometerplus.android.fbreader.network.NetworkBookInfoActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" />

View file

@ -1,6 +1,7 @@
===== 0.99.14 (??? ??, 2011) =====
* Thai localization (by Samphan Pojanasophanakul)
* Fixed TTF font style detection
* opds:// URLs support has been implemented
===== 0.99.13 (Feb 13, 2011) =====
* Fixed book/position forgetting bug

View file

@ -2,3 +2,4 @@ DONE hyphenations are not changed after language changing in book info dialog
* scrolling: 4 directions
* scrolling: add 3D animation
DONE 'disable douple tapping' option
* float numbers as series index

1
TODO.CustomCatalog Normal file
View file

@ -0,0 +1 @@
* start FBReader in new task

View file

@ -586,7 +586,7 @@
<node name="register" value="Přihlásit" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Vlastní katalog" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Název" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Stručný obsah" />

View file

@ -587,7 +587,7 @@
<node name="register" value="Anmelden" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Benutzerspezifischer Katalog" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Titel" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Zusammenfassung" />

View file

@ -587,7 +587,7 @@
<node name="register" value="Sign up" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Custom catalog" />
<node name="title" value="FBReader: add custom catalog" />
<node name="catalogTitle" value="Title" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Summary" />

View file

@ -589,7 +589,7 @@
<node name="register" value="Inscription"/>
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Catalogue personalisé" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Titre" />
<node name="catalogUrl" value="Adresse du catalogue sur le réseau" />
<node name="catalogSummary" value="Description" />

View file

@ -586,7 +586,7 @@
<node name="register" value="Rexistro" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Catálogo personalizado" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Título" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Resumo" />

View file

@ -586,7 +586,7 @@
<node name="register" value="Regisztráció" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Saját katalógus" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Cím" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Leírás" />

View file

@ -586,7 +586,7 @@
<node name="register" value="Registrati" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Catalogo personalizzato" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Titolo" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Sommario" />

View file

@ -586,7 +586,7 @@
<node name="register" value="Registeren" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Andere catalogus" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Titel" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Beschrijving" />

View file

@ -585,7 +585,7 @@
<node name="register" value="Зарегистрироваться" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Пользовательский каталог" />
<node name="title" value="FBReader: добавление каталога" />
<node name="catalogTitle" value="Название" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Описание" />

View file

@ -590,7 +590,7 @@
<node name="register" value="ลงทะเบียน"/>
</node>
<node name="CustomCatalogDialog">
<node name="title" value="แคตตาล็อกที่กำหนดเอง"/>
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="ชื่อแคตตาล็อก"/>
<node name="catalogUrl" value="URL"/>
<node name="catalogSummary" value="สรุป"/>

View file

@ -586,7 +586,7 @@
<node name="register" value="Зареєструватися" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Користувацький каталог" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Назва" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Опис" />

View file

@ -586,7 +586,7 @@
<node name="register" value="Đăng ký" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="Tùy chỉnh catalo" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="Tiêu đề" />
<node name="catalogUrl" value="URL" />
<node name="catalogSummary" value="Tóm tắt" />

View file

@ -586,7 +586,7 @@
<node name="register" value="注册" />
</node>
<node name="CustomCatalogDialog">
<node name="title" value="自定义书库目录" />
<node name="title" value="FBReader: add custom catalog" toBeTranslated="true" />
<node name="catalogTitle" value="目录名称" />
<node name="catalogUrl" value="目录网址" />
<node name="catalogSummary" value="简介" />

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/network_custom_catalog_dialog"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
@ -12,124 +11,124 @@
android:orientation="vertical"
>
<RelativeLayout
android:id="@+id/network_catalog_title_group"
android:id="@+id/add_custom_catalog_title_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/network_catalog_title_text"
android:id="@+id/add_custom_catalog_title_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_alignParentTop="true"
/>
<TextView
android:id="@+id/network_catalog_title_star"
android:id="@+id/add_custom_catalog_title_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*"
android:textColor="#ffff0000"
android:layout_marginLeft="4dp"
android:layout_alignParentRight="true"
android:layout_below="@id/network_catalog_title_text"
android:layout_below="@id/add_custom_catalog_title_label"
/>
<EditText
android:id="@+id/network_catalog_title"
android:id="@+id/add_custom_catalog_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/network_catalog_title_star"
android:layout_below="@id/network_catalog_title_text"
android:layout_toLeftOf="@id/add_custom_catalog_title_star"
android:layout_below="@id/add_custom_catalog_title_label"
/>
<TextView
android:id="@+id/network_catalog_title_example"
android:id="@+id/add_custom_catalog_title_example"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="right"
android:layout_alignParentBottom="true"
android:layout_below="@id/network_catalog_title"
android:layout_below="@id/add_custom_catalog_title"
/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/network_catalog_url_group"
android:id="@+id/add_custom_catalog_url_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
>
<TextView
android:id="@+id/network_catalog_url_text"
android:id="@+id/add_custom_catalog_url_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_alignParentTop="true"
/>
<TextView
android:id="@+id/network_catalog_url_star"
android:id="@+id/add_custom_catalog_url_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*"
android:textColor="#ffff0000"
android:layout_marginLeft="4dp"
android:layout_alignParentRight="true"
android:layout_below="@id/network_catalog_url_text"
android:layout_below="@id/add_custom_catalog_url_label"
/>
<EditText
android:id="@+id/network_catalog_url"
android:id="@+id/add_custom_catalog_url"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="textUri"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/network_catalog_url_star"
android:layout_below="@id/network_catalog_url_text"
android:layout_toLeftOf="@id/add_custom_catalog_url_star"
android:layout_below="@id/add_custom_catalog_url_label"
/>
<TextView
android:id="@+id/network_catalog_url_example"
android:id="@+id/add_custom_catalog_url_example"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="right"
android:layout_alignParentBottom="true"
android:layout_below="@id/network_catalog_url"
android:layout_below="@id/add_custom_catalog_url"
/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/network_catalog_summary_group"
android:id="@+id/add_custom_catalog_summary_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
>
<TextView
android:id="@+id/network_catalog_summary_text"
android:id="@+id/add_custom_catalog_summary_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_alignParentTop="true"
/>
<EditText
android:id="@+id/network_catalog_summary"
android:id="@+id/add_custom_catalog_summary"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_below="@id/network_catalog_summary_text"
android:layout_below="@id/add_custom_catalog_summary_label"
/>
<TextView
android:id="@+id/network_catalog_summary_example"
android:id="@+id/add_custom_catalog_summary_example"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="right"
android:layout_alignParentBottom="true"
android:layout_below="@id/network_catalog_summary"
android:layout_below="@id/add_custom_catalog_summary"
/>
</RelativeLayout>
<TextView
android:id="@+id/network_catalog_error"
android:id="@+id/add_custom_catalog_error"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
@ -137,5 +136,29 @@
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:orientation="horizontal"
>
<Button
android:id="@+id/add_custom_catalog_ok_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
/>
<Button
android:id="@+id/add_custom_catalog_cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -28,7 +28,6 @@ import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.WindowManager;
import android.view.Window;
import android.widget.RelativeLayout;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;

View file

@ -0,0 +1,287 @@
/*
* Copyright (C) 2010-2011 Geometer Plus <contact@geometerplus.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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.android.fbreader.network;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
import org.geometerplus.zlibrary.ui.android.R;
import org.geometerplus.fbreader.network.ICustomNetworkLink;
import org.geometerplus.fbreader.network.opds.OPDSLinkReader;
import org.geometerplus.android.util.UIUtil;
public class AddCustomCatalogActivity extends Activity {
private ZLResource myResource;
private Integer myCatalogId;
private String myIcon;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Thread.setDefaultUncaughtExceptionHandler(new org.geometerplus.zlibrary.ui.android.library.UncaughtExceptionHandler(this));
setContentView(R.layout.add_custom_catalog);
myResource = ZLResource.resource("dialog").getResource("CustomCatalogDialog");
setTitle(myResource.getResource("title").getValue());
setTextFromResource(R.id.add_custom_catalog_title_label, "catalogTitle");
setTextFromResource(R.id.add_custom_catalog_url_label, "catalogUrl");
setTextFromResource(R.id.add_custom_catalog_summary_label, "catalogSummary");
setTextFromResource(R.id.add_custom_catalog_title_example, "catalogTitleExample");
setTextFromResource(R.id.add_custom_catalog_url_example, "catalogUrlExample");
setTextFromResource(R.id.add_custom_catalog_summary_example, "catalogSummaryExample");
setupButton(
R.id.add_custom_catalog_ok_button, "ok", new View.OnClickListener() {
public void onClick(View view) {
final InputMethodManager imm =
(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(findViewById(R.id.add_custom_catalog_url).getWindowToken(), 0);
imm.hideSoftInputFromWindow(findViewById(R.id.add_custom_catalog_title).getWindowToken(), 0);
imm.hideSoftInputFromWindow(findViewById(R.id.add_custom_catalog_summary).getWindowToken(), 0);
onOkButton();
}
}
);
setupButton(
R.id.add_custom_catalog_cancel_button, "cancel", new View.OnClickListener() {
public void onClick(View view) {
finish();
}
}
);
final Intent intent = getIntent();
final Uri uri = intent.getData();
myCatalogId = ICustomNetworkLink.INVALID_ID;
if (uri != null) {
myCatalogId = intent.getIntExtra(
NetworkLibraryActivity.ADD_CATALOG_ID_KEY, myCatalogId
);
if (myCatalogId != ICustomNetworkLink.INVALID_ID) {
setTextById(R.id.add_custom_catalog_url, uri.toString());
setTextById(R.id.add_custom_catalog_title, intent.getStringExtra(NetworkLibraryActivity.ADD_CATALOG_TITLE_KEY));
setTextById(R.id.add_custom_catalog_summary, intent.getStringExtra(NetworkLibraryActivity.ADD_CATALOG_SUMMARY_KEY));
myIcon = intent.getStringExtra(NetworkLibraryActivity.ADD_CATALOG_ICON_KEY);
} else {
loadInfoByUri(uri);
}
setExtraFieldsVisibility(true);
} else {
setExtraFieldsVisibility(false);
}
}
private void onOkButton() {
final String textUrl = getTextById(R.id.add_custom_catalog_url);
if (isEmptyString(textUrl)) {
setErrorByKey("urlIsEmpty");
return;
}
final String title = getTextById(R.id.add_custom_catalog_title);
final String summary = getTextById(R.id.add_custom_catalog_summary);
Uri uri = null;
try {
uri = Uri.parse(textUrl);
if (isEmptyString(uri.getScheme())) {
uri = Uri.parse("http://" + textUrl);
}
if (isEmptyString(uri.getHost())) {
setErrorByKey("invalidUrl");
return;
}
} catch (Throwable t) {
setErrorByKey("invalidUrl");
return;
}
if (!getExtraFieldsVisibility()) {
loadInfoByUri(uri);
} else if (isEmptyString(title)) {
setErrorByKey("titleIsEmpty");
} else {
startActivity(
new Intent(
NetworkLibraryActivity.ADD_CATALOG,
uri,
AddCustomCatalogActivity.this,
NetworkLibraryActivity.class
)
.putExtra(NetworkLibraryActivity.ADD_CATALOG_TITLE_KEY, title)
.putExtra(NetworkLibraryActivity.ADD_CATALOG_SUMMARY_KEY, summary)
.putExtra(NetworkLibraryActivity.ADD_CATALOG_ICON_KEY, myIcon)
.putExtra(NetworkLibraryActivity.ADD_CATALOG_ID_KEY, myCatalogId)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
);
finish();
}
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
}
private boolean getExtraFieldsVisibility() {
return findViewById(R.id.add_custom_catalog_title_group).getVisibility() == View.VISIBLE;
}
private void setExtraFieldsVisibility(boolean show) {
final int visibility = show ? View.VISIBLE : View.GONE;
runOnUiThread(new Runnable() {
public void run() {
findViewById(R.id.add_custom_catalog_title_group).setVisibility(visibility);
findViewById(R.id.add_custom_catalog_summary_group).setVisibility(visibility);
}
});
}
private void setTextById(int id, String text) {
((TextView)findViewById(id)).setText(text);
}
private String getTextById(int id) {
final String text = ((TextView)findViewById(id)).getText().toString();
return text != null ? text.trim() : null;
}
private void setupButton(int id, String resourceKey, View.OnClickListener listener) {
final Button button = (Button)findViewById(id);
button.setText(
ZLResource.resource("dialog").getResource("button").getResource(resourceKey).getValue()
);
button.setOnClickListener(listener);
}
private void setTextFromResource(int id, String resourceKey) {
setTextById(id, myResource.getResource(resourceKey).getValue());
}
private void setErrorText(final String errorText) {
runOnUiThread(new Runnable() {
public void run() {
final TextView errorView = (TextView)findViewById(R.id.add_custom_catalog_error);
if (errorText != null) {
errorView.setText(errorText);
errorView.setVisibility(View.VISIBLE);
} else {
errorView.setVisibility(View.GONE);
}
}
});
}
private void setErrorByKey(final String resourceKey) {
setErrorText(myResource.getResource(resourceKey).getValue());
}
private void runErrorDialog(final String errorText) {
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
setExtraFieldsVisibility(true);
break;
case DialogInterface.BUTTON_NEUTRAL:
break;
case DialogInterface.BUTTON_NEGATIVE:
AddCustomCatalogActivity.this.finish();
break;
}
}
};
final ZLResource dialogResource = ZLResource.resource("dialog");
final ZLResource boxResource = dialogResource.getResource("networkError");
final ZLResource buttonResource = dialogResource.getResource("button");
new AlertDialog.Builder(this)
.setTitle(boxResource.getResource("title").getValue())
.setMessage(errorText)
.setIcon(0)
.setPositiveButton(buttonResource.getResource("continue").getValue(), listener)
.setNeutralButton(buttonResource.getResource("editUrl").getValue(), listener)
.setNegativeButton(buttonResource.getResource("cancel").getValue(), listener)
.create().show();
}
private void loadInfoByUri(Uri uri) {
String textUrl = uri.toString();
if (isEmptyString(uri.getScheme())) {
textUrl = "http://" + textUrl;
uri = Uri.parse(textUrl);
} else if ("opds".equals(uri.getScheme())) {
textUrl = "http" + uri.toString().substring(4);
}
setTextById(R.id.add_custom_catalog_url, textUrl);
String siteName = uri.getHost();
if (isEmptyString(siteName)) {
setErrorByKey("invalidUrl");
return;
}
if (siteName.startsWith("www.")) {
siteName = siteName.substring(4);
}
final ICustomNetworkLink link =
OPDSLinkReader.createCustomLink(siteName, null, null, null, textUrl);
final Runnable loadInfoRunnable = new Runnable() {
private String myError;
public void run() {
try {
myError = null;
link.reloadInfo();
} catch (ZLNetworkException e) {
myError = e.getMessage();
}
runOnUiThread(new Runnable() {
public void run() {
if (myError == null) {
setTextById(R.id.add_custom_catalog_title, link.getTitle());
setTextById(R.id.add_custom_catalog_summary, link.getSummary());
myIcon = link.getIcon();
setExtraFieldsVisibility(true);
} else {
runErrorDialog(myError);
myIcon = null;
}
}
});
setErrorText(myError);
}
};
UIUtil.wait("loadingCatalogInfo", loadInfoRunnable, this);
}
}

View file

@ -20,6 +20,7 @@
package org.geometerplus.android.fbreader.network;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.ContextMenu;
@ -70,6 +71,6 @@ class AddCustomCatalogItemActions extends NetworkTreeActions {
}
public static void addCustomCatalog(Activity activity) {
NetworkDialog.show(activity, NetworkDialog.DIALOG_CUSTOM_CATALOG, null, null);
activity.startActivity(new Intent(activity, AddCustomCatalogActivity.class));
}
}

View file

@ -1,238 +0,0 @@
/*
* Copyright (C) 2010-2011 Geometer Plus <contact@geometerplus.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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.geometerplus.android.fbreader.network;
import android.app.Dialog;
import android.app.AlertDialog;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
import android.content.DialogInterface;
import org.geometerplus.zlibrary.core.resources.ZLResource;
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
import org.geometerplus.zlibrary.ui.android.R;
import org.geometerplus.android.util.UIUtil;
import org.geometerplus.fbreader.network.*;
import org.geometerplus.fbreader.network.opds.OPDSLinkReader;
class CustomCatalogDialog extends NetworkDialog {
private String myTitle;
private String myUrl;
private String mySummary;
private boolean myLinkWithoutInfo;
public CustomCatalogDialog() {
super("CustomCatalogDialog");
}
@Override
protected void clearData() {
myTitle = myUrl = mySummary = null;
myLinkWithoutInfo = false;
}
@Override
protected View createLayout() {
final View layout = myActivity.getLayoutInflater().inflate(R.layout.network_custom_catalog_dialog, null);
((TextView) layout.findViewById(R.id.network_catalog_title_text)).setText(myResource.getResource("catalogTitle").getValue());
((TextView) layout.findViewById(R.id.network_catalog_url_text)).setText(myResource.getResource("catalogUrl").getValue());
((TextView) layout.findViewById(R.id.network_catalog_summary_text)).setText(myResource.getResource("catalogSummary").getValue());
((TextView) layout.findViewById(R.id.network_catalog_title_example)).setText(myResource.getResource("catalogTitleExample").getValue());
((TextView) layout.findViewById(R.id.network_catalog_url_example)).setText(myResource.getResource("catalogUrlExample").getValue());
((TextView) layout.findViewById(R.id.network_catalog_summary_example)).setText(myResource.getResource("catalogSummaryExample").getValue());
return layout;
}
@Override
protected void onPositive(DialogInterface dialog) {
AlertDialog alert = (AlertDialog) dialog;
myTitle = ((TextView) alert.findViewById(R.id.network_catalog_title)).getText().toString().trim();
myUrl = ((TextView) alert.findViewById(R.id.network_catalog_url)).getText().toString().trim();
mySummary = ((TextView) alert.findViewById(R.id.network_catalog_summary)).getText().toString().trim();
if (myTitle.length() == 0) {
myTitle = null;
if (myLink != null) {
final String err = myResource.getResource("titleIsEmpty").getValue();
sendError(true, false, err);
return;
}
}
if (myUrl.length() == 0) {
myUrl = null;
final String err = myResource.getResource("urlIsEmpty").getValue();
sendError(true, false, err);
return;
}
if (mySummary.length() == 0) {
mySummary = null;
}
Uri uri = Uri.parse(myUrl);
if (uri.getScheme() == null) {
myUrl = "http://" + myUrl;
uri = Uri.parse(myUrl);
}
String siteName = uri.getHost();
if (siteName == null) {
final String err = myResource.getResource("invalidUrl").getValue();
sendError(true, false, err);
return;
}
if (siteName.startsWith("www.")) {
siteName = siteName.substring(4);
}
final NetworkLibrary library = NetworkLibrary.Instance();
if (myLink != null && library.hasCustomLinkTitle(myTitle, myLink)) {
final String err = myResource.getResource("titleAlreadyExists").getValue();
sendError(true, false, err);
return;
}
if (library.hasCustomLinkSite(siteName, myLink)) {
final String err = myResource.getResource("siteAlreadyExists").getValue();
sendError(true, false, err);
return;
}
if (myLink != null) {
final ICustomNetworkLink link = (ICustomNetworkLink) myLink;
link.setSiteName(siteName);
link.setTitle(myTitle);
link.setSummary(mySummary);
link.setLink(INetworkLink.URL_MAIN, myUrl);
if (myLinkWithoutInfo) {
NetworkLibrary.Instance().addCustomLink(link);
myLinkWithoutInfo = false;
} else {
link.saveLink();
}
sendSuccess(true);
return;
}
myLinkWithoutInfo = true;
myLink = OPDSLinkReader.createCustomLinkWithoutInfo(siteName, myUrl);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
final String err = (String) msg.obj;
if (err != null) {
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
sendSuccess(true);
} else {
if (which == DialogInterface.BUTTON_NEUTRAL) {
myLinkWithoutInfo = false;
myLink = null;
}
sendError(true, false, null);
}
}
};
final ZLResource dialogResource = ZLResource.resource("dialog");
final ZLResource boxResource = dialogResource.getResource("networkError");
final ZLResource buttonResource = dialogResource.getResource("button");
new AlertDialog.Builder(myActivity)
.setTitle(boxResource.getResource("title").getValue())
.setMessage(err)
.setIcon(0)
.setPositiveButton(buttonResource.getResource("continue").getValue(), listener)
.setNeutralButton(buttonResource.getResource("editUrl").getValue(), listener)
.setNegativeButton(buttonResource.getResource("cancel").getValue(), listener)
.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
listener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
})
.create().show();
} else {
sendError(true, false, null);
}
}
};
final Runnable loadInfoRunnable = new Runnable() {
public void run() {
String error = null;
try {
((ICustomNetworkLink)myLink).reloadInfo();
} catch (ZLNetworkException e) {
error = e.getMessage();
}
handler.sendMessage(handler.obtainMessage(0, error));
}
};
UIUtil.wait("loadingCatalogInfo", loadInfoRunnable, myActivity);
}
@Override
protected void onNegative(DialogInterface dialog) {
sendCancel(false);
}
@Override
public void prepareDialogInternal(Dialog dialog) {
if (myLink != null) {
if (myTitle == null) myTitle = myLink.getTitle();
if (myUrl == null) myUrl = myLink.getLink(INetworkLink.URL_MAIN);
if (mySummary == null) mySummary = myLink.getSummary();
}
((TextView) dialog.findViewById(R.id.network_catalog_title)).setText(myTitle);
((TextView) dialog.findViewById(R.id.network_catalog_url)).setText(myUrl);
((TextView) dialog.findViewById(R.id.network_catalog_summary)).setText(mySummary);
final int examplesVisibility = (myLink == null || myLinkWithoutInfo) ? View.VISIBLE : View.GONE;
dialog.findViewById(R.id.network_catalog_title_example).setVisibility(examplesVisibility);
dialog.findViewById(R.id.network_catalog_url_example).setVisibility(examplesVisibility);
dialog.findViewById(R.id.network_catalog_summary_example).setVisibility(examplesVisibility);
final int groupsVisibility = (myLink != null) ? View.VISIBLE : View.GONE;
dialog.findViewById(R.id.network_catalog_title_group).setVisibility(groupsVisibility);
dialog.findViewById(R.id.network_catalog_summary_group).setVisibility(groupsVisibility);
final TextView error = (TextView) dialog.findViewById(R.id.network_catalog_error);
if (myErrorMessage == null) {
error.setVisibility(View.GONE);
error.setText("");
} else {
error.setVisibility(View.VISIBLE);
error.setText(myErrorMessage);
}
View dlgView = dialog.findViewById(R.id.network_custom_catalog_dialog);
dlgView.invalidate();
dlgView.requestLayout();
}
}

View file

@ -309,7 +309,7 @@ class NetworkBookActions extends NetworkTreeActions {
Uri.fromFile(new File(local)),
activity.getApplicationContext(),
FBReader.class
).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
);
}
}

View file

@ -23,6 +23,8 @@ import java.util.*;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Message;
import android.os.Handler;
import android.view.Menu;
@ -245,8 +247,22 @@ class NetworkCatalogActions extends NetworkTreeActions {
new RefillAccountActions().runStandalone(activity, ((RefillAccountTree)activity.getDefaultTree()).Link);
return true;
case CUSTOM_CATALOG_EDIT:
NetworkDialog.show(activity, NetworkDialog.DIALOG_CUSTOM_CATALOG, ((NetworkCatalogTree)tree).Item.Link, null);
{
final ICustomNetworkLink link =
(ICustomNetworkLink)((NetworkCatalogTree)tree).Item.Link;
final String textUrl = link.getLink(INetworkLink.URL_MAIN);
if (textUrl != null) {
activity.startActivity(
new Intent(activity, AddCustomCatalogActivity.class)
.setData(Uri.parse(textUrl))
.putExtra(NetworkLibraryActivity.ADD_CATALOG_TITLE_KEY, link.getTitle())
.putExtra(NetworkLibraryActivity.ADD_CATALOG_SUMMARY_KEY, link.getSummary())
.putExtra(NetworkLibraryActivity.ADD_CATALOG_ICON_KEY, link.getIcon())
.putExtra(NetworkLibraryActivity.ADD_CATALOG_ID_KEY, link.getId())
);
}
return true;
}
case CUSTOM_CATALOG_REMOVE:
removeCustomLink((ICustomNetworkLink)((NetworkCatalogTree)tree).Item.Link);
return true;

View file

@ -39,7 +39,6 @@ abstract class NetworkDialog {
// dialog identifiers
public static final int DIALOG_AUTHENTICATION = 0;
public static final int DIALOG_CUSTOM_CATALOG = 1;
private static final TreeMap<Integer, NetworkDialog> ourInstances = new TreeMap<Integer, NetworkDialog>();
@ -50,9 +49,6 @@ abstract class NetworkDialog {
case DIALOG_AUTHENTICATION:
dlg = new AuthenticationDialog();
break;
case DIALOG_CUSTOM_CATALOG:
dlg = new CustomCatalogDialog();
break;
}
if (dlg != null) {
dlg.myId = id;

View file

@ -24,6 +24,7 @@ import java.util.*;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -40,9 +41,19 @@ import org.geometerplus.android.util.UIUtil;
import org.geometerplus.fbreader.network.NetworkTree;
import org.geometerplus.fbreader.network.NetworkLibrary;
import org.geometerplus.fbreader.network.ICustomNetworkLink;
import org.geometerplus.fbreader.network.opds.OPDSLinkReader;
public class NetworkLibraryActivity extends NetworkBaseActivity {
final static String ADD_CATALOG = "android.fbreader.action.ADD_CATALOG";
final static String ADD_CATALOG_TITLE_KEY = "title";
final static String ADD_CATALOG_SUMMARY_KEY = "summary";
final static String ADD_CATALOG_ICON_KEY = "icon";
final static String ADD_CATALOG_ID_KEY = "id";
private NetworkTree myTree;
private volatile Intent myIntent;
@Override
public void onCreate(Bundle icicle) {
@ -50,6 +61,44 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
requestWindowFeature(Window.FEATURE_NO_TITLE);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
myIntent = getIntent();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent);
}
private void processIntent(Intent intent) {
final String action = intent.getAction();
if (ADD_CATALOG.equals(action)) {
final Uri uri = intent.getData();
final String title = intent.getStringExtra(ADD_CATALOG_TITLE_KEY);
final String summary = intent.getStringExtra(ADD_CATALOG_SUMMARY_KEY);
final String icon = intent.getStringExtra(ADD_CATALOG_ICON_KEY);
final int id = intent.getIntExtra(ADD_CATALOG_ID_KEY, ICustomNetworkLink.INVALID_ID);
if (uri == null || title == null) {
return;
}
final ICustomNetworkLink link = OPDSLinkReader.createCustomLink(
id, uri.getHost(), title, summary, icon, uri.toString()
);
if (link != null) {
runOnUiThread(new Runnable() {
public void run() {
final NetworkLibrary library = NetworkLibrary.Instance();
library.addCustomLink(link);
library.updateChildren();
library.synchronize();
NetworkView.Instance().fireModelChangedAsync();
getListView().invalidateViews();
}
});
}
}
}
private void prepareView() {
@ -74,6 +123,10 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
}
} else {
prepareView();
if (myIntent != null) {
processIntent(myIntent);
myIntent = null;
}
}
}
@ -114,6 +167,10 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
String error = null;
try {
NetworkView.Instance().initialize();
if (myActivity.myIntent != null) {
myActivity.processIntent(myActivity.myIntent);
myActivity.myIntent = null;
}
} catch (ZLNetworkException e) {
error = e.getMessage();
}

View file

@ -41,7 +41,7 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
private void migrate() {
final int version = myDatabase.getVersion();
final int currentCodeVersion = 1;
final int currentCodeVersion = 2;
if (version >= currentCodeVersion) {
return;
}
@ -49,6 +49,8 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
switch (version) {
case 0:
createTables();
case 1:
updateTables1();
}
myDatabase.setTransactionSuccessful();
myDatabase.endTransaction();
@ -155,7 +157,7 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
if (dbValue == null) {
if (myInsertCustomLinkUrlStatement == null) {
myInsertCustomLinkUrlStatement = myDatabase.compileStatement(
"INSERT INTO CustomLinkUrls(url,link_id,key) VALUES (?,?,?)");
"INSERT OR REPLACE INTO CustomLinkUrls(url,link_id,key) VALUES (?,?,?)");
}
urlStatement = myInsertCustomLinkUrlStatement;
} else if (!value.equals(dbValue)) {
@ -230,4 +232,17 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
"url TEXT NOT NULL," +
"CONSTRAINT CustomLinkUrls_PK PRIMARY KEY (key, link_id))");
}
private void updateTables1() {
myDatabase.execSQL("ALTER TABLE CustomLinks RENAME TO CustomLinks_Obsolete");
myDatabase.execSQL(
"CREATE TABLE CustomLinks(" +
"link_id INTEGER PRIMARY KEY," +
"title TEXT NOT NULL," +
"site_name TEXT NOT NULL," +
"summary TEXT," +
"icon TEXT)");
myDatabase.execSQL("INSERT INTO CustomLinks (link_id,title,site_name,summary,icon) SELECT link_id,title,site_name,summary,icon FROM CustomLinks_Obsolete");
myDatabase.execSQL("DROP TABLE CustomLinks_Obsolete");
}
}

View file

@ -22,19 +22,11 @@ package org.geometerplus.fbreader.network;
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
public interface ICustomNetworkLink extends INetworkLink {
public static final int INVALID_ID = -1;
int getId();
void setId(int id);
interface SaveLinkListener {
void onSaveLink(ICustomNetworkLink link);
}
void setSaveLinkListener(SaveLinkListener listener);
void saveLink();
void setSiteName(String name);
void setTitle(String title);
void setSummary(String summary);

View file

@ -182,7 +182,6 @@ public class NetworkLibrary {
final ICustomNetworkLink link = OPDSLinkReader.createCustomLink(id, siteName, title, summary, icon, links);
if (link != null) {
addLinkInternal(link);
link.setSaveLinkListener(myChangesListener);
}
}
}
@ -303,11 +302,6 @@ public class NetworkLibrary {
myUpdateVisibility = true;
}
private static boolean linksEqual(INetworkLink l1, INetworkLink l2) {
return l1 == l2 || l1.getSiteName().equals(l2.getSiteName());
}
private static boolean linkIsInvalid(INetworkLink link, INetworkLink nodeLink) {
if (link instanceof ICustomNetworkLink) {
if (link != nodeLink) {
@ -347,7 +341,7 @@ public class NetworkLibrary {
continue;
}
final INetworkLink nodeLink = ((NetworkCatalogTree) currentNode).Item.Link;
if (linksEqual(link, nodeLink)) {
if (link == nodeLink) {
if (linkIsInvalid(link, nodeLink)) {
toRemove.add(currentNode);
} else {
@ -360,7 +354,7 @@ public class NetworkLibrary {
INetworkLink newNodeLink = null;
for (int j = i; j < links.size(); ++j) {
final INetworkLink jlnk = links.get(j);
if (linksEqual(nodeLink, jlnk)) {
if (nodeLink == jlnk) {
newNodeLink = jlnk;
break;
}
@ -468,12 +462,6 @@ public class NetworkLibrary {
}
}
private ICustomNetworkLink.SaveLinkListener myChangesListener = new ICustomNetworkLink.SaveLinkListener() {
public void onSaveLink(ICustomNetworkLink link) {
NetworkDatabase.Instance().saveCustomLink(link);
}
};
private <T extends INetworkLink> void addLinkInternal(T link) {
synchronized (myLinks) {
myLinks.add(link);
@ -481,9 +469,20 @@ public class NetworkLibrary {
}
public void addCustomLink(ICustomNetworkLink link) {
final int id = link.getId();
if (id == ICustomNetworkLink.INVALID_ID) {
addLinkInternal(link);
link.setSaveLinkListener(myChangesListener);
link.saveLink();
} else {
for (int i = myLinks.size() - 1; i >= 0; --i) {
final INetworkLink l = myLinks.get(i);
if (l instanceof ICustomNetworkLink &&
((ICustomNetworkLink)l).getId() == id) {
myLinks.set(i, link);
break;
}
}
}
NetworkDatabase.Instance().saveCustomLink(link);
}
public void removeCustomLink(ICustomNetworkLink link) {
@ -491,7 +490,6 @@ public class NetworkLibrary {
myLinks.remove(link);
}
NetworkDatabase.Instance().deleteCustomLink(link);
link.setSaveLinkListener(null);
}
public boolean hasCustomLinkTitle(String title, INetworkLink exceptFor) {

View file

@ -33,11 +33,8 @@ import org.geometerplus.fbreader.network.ICustomNetworkLink;
import org.geometerplus.fbreader.network.INetworkLink;
import org.geometerplus.fbreader.network.NetworkException;
class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
private int myId;
private SaveLinkListener myListener;
private boolean myHasChanges;
@ -54,18 +51,6 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
myId = id;
}
public void setSaveLinkListener(SaveLinkListener listener) {
myListener = listener;
}
public void saveLink() {
if (myListener != null) {
myListener.onSaveLink(this);
} else {
throw new RuntimeException("Unable to save link: SaveLinkListener hasn't been set");
}
}
public boolean hasChanges() {
return myHasChanges;
}

View file

@ -46,10 +46,14 @@ public class OPDSLinkReader {
return new OPDSCustomLink(id, siteName, title, summary, icon, links);
}
public static ICustomNetworkLink createCustomLinkWithoutInfo(String siteName, String url) {
public static ICustomNetworkLink createCustomLink(int id, String siteName, String title, String summary, String icon, String url) {
final HashMap<String, String> links = new HashMap<String, String>();
links.put(INetworkLink.URL_MAIN, url);
return new OPDSCustomLink(ICustomNetworkLink.INVALID_ID, siteName, null, null, null, links);
return new OPDSCustomLink(id, siteName, title, summary, icon, links);
}
public static ICustomNetworkLink createCustomLink(String siteName, String title, String summary, String icon, String url) {
return createCustomLink(ICustomNetworkLink.INVALID_ID, siteName, title, summary, icon, url);
}
public static final int CACHE_LOAD = 0;