mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-06 03:50:19 +02:00
Merge branch 'master' into tts
This commit is contained in:
commit
a5cc9968d4
94 changed files with 1873 additions and 1312 deletions
|
@ -135,6 +135,7 @@
|
|||
<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.AuthenticationActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" android:theme="@android:style/Theme.Dialog"/>
|
||||
<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" />
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
<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.AuthenticationActivity" android:process=":networkLibrary" android:configChanges="orientation|keyboardHidden" android:theme="@android:style/Theme.Dialog"/>
|
||||
<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" />
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
===== 0.99.14 (??? ??, 2011) =====
|
||||
===== 0.99.14 (Mar ??, 2011) =====
|
||||
* Thai localization (by Samphan Pojanasophanakul)
|
||||
* Fixed TTF font style detection
|
||||
* opds:// URLs support has been implemented
|
||||
* Unexpected search call has been fixed
|
||||
* Ignore case comparison for zip entry names
|
||||
* Fixed custom OPDS link search
|
||||
* Periodical update of custom links information has been added
|
||||
|
||||
===== 0.99.13 (Feb 13, 2011) =====
|
||||
* Fixed book/position forgetting bug
|
||||
|
|
39
TODO.network
39
TODO.network
|
@ -1,3 +1,27 @@
|
|||
DONE show 'empty basket' message without opening of catalog
|
||||
* update basket view if basket content is changed
|
||||
* basket summary
|
||||
DONE show recommendation item if basket is not empty
|
||||
* new actions in main menu: clear; buy all
|
||||
* update recommendations list after each basket updating/purchasing
|
||||
* update recommendations list visibility after each basket updating/purchasing
|
||||
* remove book from basket on purchasing
|
||||
|
||||
* search item behaviour like search item in local library
|
||||
* separate search for each catalog (if search URL is presented)
|
||||
* menu search button should be available for all catalog levels
|
||||
|
||||
* float point numbers as series index
|
||||
* replace AuthenticationCatalog by AuthenticationActivity
|
||||
* 'recently visited catalogs' item
|
||||
* load search URL for catalogs from these catalogs, not from our generic file
|
||||
DONE show library name in network book activity
|
||||
|
||||
* litres: credit card top up
|
||||
* litres: terminal (?) top up
|
||||
* litres: similar books link
|
||||
|
||||
------------------------------
|
||||
|
||||
NP: оповещение об изменениях в namespace'ах происходит после того,
|
||||
как был обработан тег, объявляющий эти namespace'ы... Нужно сделать:
|
||||
|
@ -5,22 +29,8 @@ NP: оповещение об изменениях в namespace'ах проис
|
|||
2) вызов namespaceMapChangedHandler после вызова endElementHandler
|
||||
3) вызов namespaceMapChangedHandler для пустых тегов <tagname />
|
||||
|
||||
** Записать изменения в ChangeLog
|
||||
|
||||
DONE Network library: Объединять книги по сериям
|
||||
** в сериях книги нужно сортировать по индексу
|
||||
NP: а где это происходит???
|
||||
|
||||
DONE Возможность открывать локальные файлы из всяких файл-менеджеров
|
||||
DONE На этой странице есть ссылка на epub-файл "для ПК". http://www.zone4iphone.ru/index.php?p_id=7&b_id=18413
|
||||
Проверить скачивание книги браузером и возможность чтения из папки, куда файл был скачан.
|
||||
DONE добавлять в библиотеку (сделать таблицу добавленных вручную книг)
|
||||
|
||||
------------------------------
|
||||
|
||||
** пополнение счета в litres с помощью sms
|
||||
** сделать как "подкаталог" для элемента "пополнить счет"
|
||||
|
||||
** восстановление пароля (use default e-mail)
|
||||
** сделать отдельную ветку (?) для скачанных samples
|
||||
** (?) удалять sample при покупке/скачивании полного варианта
|
||||
|
@ -57,5 +67,4 @@ DELAYED что делать, когда мало памяти???
|
|||
-----------------------------
|
||||
|
||||
другое:
|
||||
DONE layout для китайских текстов
|
||||
* поддержка hufdic в mobipocket
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Odebrat z oblíbených"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Podle autora">
|
||||
<node name="summary" value="Knihy seřazeny podle autora"/>
|
||||
</node>
|
||||
<node name="byTitle" value="Podle názvu">
|
||||
<node name="summary" value="Knihy seřazeny podle názvu"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Otevřít katalog"/>
|
||||
<node name="showResults" value="Zobrazit výsledky"/>
|
||||
<node name="showBooks" value="Zobrazit knihy"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Odstranit ukázku"/>
|
||||
<node name="downloadDemo" value="Stáhnout ukázku"/>
|
||||
<node name="buy" value="Zakoupit (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Otevřít v prohlížeči" />
|
||||
<node name="stopLoading" value="Zastavit načítání" />
|
||||
<node name="stopSearching" value="Zastavit vyhledávání" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Série:" />
|
||||
<node name="indexInSeries" value="Díl v sérii:" />
|
||||
<node name="tags" value="Štítky:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Informace o knize" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="Požadovaná informace není uvedena v katalogu" />
|
||||
<node name="cacheDirectoryError" value="Nelze vytvořit adresář mezipaměti" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Informace" />
|
||||
<node name="message" value="Katalog je prázdný" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Výsledky vyhledávání" />
|
||||
<node name="message" value="Nebyly nalezeny žádné vhodné knihy" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Slovník není bohužel nainstalován"/>
|
||||
<node name="permissionDenied" value="Oprávnění bylo bohužel odmítnuto"/>
|
||||
<node name="noFavorites" value="Seznam oblíbených je bohužel prázdný"/>
|
||||
<node name="emptyCatalog" value="Katalog je prázdný"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Prohlížeč"/>
|
||||
|
|
|
@ -48,6 +48,18 @@
|
|||
<node name="removeFromFavorites" value="Remove from favorites" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Nach Autor">
|
||||
<node name="summary" value="Books sorted by author" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Katalog öffnen"/>
|
||||
<node name="showResults" value="Ergebnisse anzeigen"/>
|
||||
<node name="showBooks" value="Bücher anzeigen"/>
|
||||
|
@ -58,6 +70,8 @@
|
|||
<node name="deleteDemo" value="Leseprobe löschen"/>
|
||||
<node name="downloadDemo" value="Leseprobe herunterladen"/>
|
||||
<node name="buy" value="(%s) kaufen"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Im Browser öffnen" />
|
||||
<node name="stopLoading" value="Herunterladen abbrechen" />
|
||||
<node name="stopSearching" value="Suchen stoppen" />
|
||||
|
@ -110,6 +124,7 @@
|
|||
<node name="series" value="Serie:" />
|
||||
<node name="indexInSeries" value="Seriennummer:" />
|
||||
<node name="tags" value="Tags:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Buchinformation" />
|
||||
|
@ -560,10 +575,6 @@
|
|||
<node name="noRequiredInformation" value="Die benötigte Information ist in dem Katalog nicht spezifiziert." />
|
||||
<node name="cacheDirectoryError" value="Es kann kein Cache-Verzeichns angelegt werden." />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Information" />
|
||||
<node name="message" value="Der Katalog ist leer." />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Suchergebnisse" />
|
||||
<node name="message" value="Es wurden kein Bücher, die zu ihrer Eingabe passen, gefunden." />
|
||||
|
@ -611,6 +622,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Dictionary is not installed, sorry" toBeTranslated="true"/>
|
||||
<node name="permissionDenied" value="Permission denied, sorry" toBeTranslated="true"/>
|
||||
<node name="noFavorites" value="Your favorites list is empty, sorry" toBeTranslated="true"/>
|
||||
<node name="emptyCatalog" value="Der Katalog ist leer."/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Browser"/>
|
||||
|
|
|
@ -46,6 +46,18 @@
|
|||
<node name="removeFromFavorites" value="Remove from favorites"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="By author">
|
||||
<node name="summary" value="Books sorted by author"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title">
|
||||
<node name="summary" value="Books sorted by title"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date">
|
||||
<node name="summary" value="Books sorted by date of purchasing"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series">
|
||||
<node name="summary" value="Books sorted by series"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Open catalog"/>
|
||||
<node name="showResults" value="Show results"/>
|
||||
<node name="showBooks" value="Show books"/>
|
||||
|
@ -56,6 +68,8 @@
|
|||
<node name="deleteDemo" value="Delete sample"/>
|
||||
<node name="downloadDemo" value="Download sample"/>
|
||||
<node name="buy" value="Buy (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket"/>
|
||||
<node name="removeFromBasket" value="Remove from basket"/>
|
||||
<node name="openInBrowser" value="Open in browser" />
|
||||
<node name="stopLoading" value="Stop loading" />
|
||||
<node name="stopSearching" value="Stop searching" />
|
||||
|
@ -66,6 +80,8 @@
|
|||
<node name="refillViaSms" value="Text messages"/>
|
||||
<node name="refillViaBrowser" value="Open page in browser"/>
|
||||
<node name="refillSummary" value="Currently: %s"/>
|
||||
<node name="basket" value="Basket"/>
|
||||
<node name="basketSummary" value="Books I want to buy"/>
|
||||
<node name="alreadyDownloading" value="Book is being downloaded" />
|
||||
<node name="alreadyDownloadingDemo" value="Sample is being downloaded" />
|
||||
<node name="stoppingCatalogLoading" value="Stopping loading" />
|
||||
|
@ -97,6 +113,8 @@
|
|||
<node name="addCustomCatalog" value="Add catalog"/>
|
||||
<node name="refreshCatalogsList" value="Refresh catalogs"/>
|
||||
<node name="languages" value="Language filter"/>
|
||||
<node name="clearBasket" value="Clear basket"/>
|
||||
<node name="buyAllBooks" value="Buy all books"/>
|
||||
</node>
|
||||
</node>
|
||||
<node name="networkBookView">
|
||||
|
@ -108,6 +126,7 @@
|
|||
<node name="series" value="Series:" />
|
||||
<node name="indexInSeries" value="Index in series:" />
|
||||
<node name="tags" value="Tags:" />
|
||||
<node name="catalog" value="Catalog:" />
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Book Info" />
|
||||
|
@ -559,10 +578,6 @@
|
|||
<node name="noRequiredInformation" value="Required information is not specified in the catalog" />
|
||||
<node name="cacheDirectoryError" value="Unable to create cache directory" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Information" />
|
||||
<node name="message" value="Catalog is empty" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Search results" />
|
||||
<node name="message" value="There are no suitable books found" />
|
||||
|
@ -610,6 +625,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Dictionary is not installed, sorry"/>
|
||||
<node name="permissionDenied" value="Permission denied, sorry"/>
|
||||
<node name="noFavorites" value="Your favorites list is empty, sorry"/>
|
||||
<node name="emptyCatalog" value="Catalog is empty, sorry" />
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" />
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Browser"/>
|
||||
|
|
|
@ -50,6 +50,18 @@
|
|||
<node name="removeFromFavorites" value="Supprimer des favoris"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Par auteur">
|
||||
<node name="summary" value="Livres triés par auteur"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Ouvrir le catalogue"/>
|
||||
<node name="showResults" value="Afficher les résultats"/>
|
||||
<node name="showBooks" value="Afficher les livres"/>
|
||||
|
@ -60,6 +72,8 @@
|
|||
<node name="deleteDemo" value="Supprimer l'extrait"/>
|
||||
<node name="downloadDemo" value="Télécharger l'extrait"/>
|
||||
<node name="buy" value="Acheter (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Ouvrir dans un navigateur" />
|
||||
<node name="stopLoading" value="Arrêt du chargement" />
|
||||
<node name="stopSearching" value="Arrêt de la recherche" />
|
||||
|
@ -112,6 +126,7 @@
|
|||
<node name="series" value="Série:" />
|
||||
<node name="indexInSeries" value="Index dans les séries:" />
|
||||
<node name="tags" value="Tags:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Informations sur le livre" />
|
||||
|
@ -562,10 +577,6 @@
|
|||
<node name="noRequiredInformation" value="Certaines informations requises sont absentes du catalogue" />
|
||||
<node name="cacheDirectoryError" value="Impossible de créer le répertoire contenant le cache" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Information"/>
|
||||
<node name="message" value="Le catalogue est vide"/>
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Résultats de la recherche" />
|
||||
<node name="message" value="Aucun livre correspondant trouvé." />
|
||||
|
@ -613,6 +624,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Désolé mais le dictionnaire n'est pas installé"/>
|
||||
<node name="permissionDenied" value="Désolé, accès refusé"/>
|
||||
<node name="noFavorites" value="Votre liste de favoris est vide"/>
|
||||
<node name="emptyCatalog" value="Le catalogue est vide"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Navigateur"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Retirar de preferidos"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Por autor">
|
||||
<node name="summary" value="Libros ordenados por autor"/>
|
||||
</node>
|
||||
<node name="byTitle" value="Por título">
|
||||
<node name="summary" value="Libros ordenados por título"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Abrir o catalogo"/>
|
||||
<node name="showResults" value="Mostrar resultados"/>
|
||||
<node name="showBooks" value="Mostrar libros"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Eliminar mostra"/>
|
||||
<node name="downloadDemo" value="Descargar mostra"/>
|
||||
<node name="buy" value="Comprar (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Abrir no navegador" />
|
||||
<node name="stopLoading" value="Deter a carga" />
|
||||
<node name="stopSearching" value="Deter a busca" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Series:" />
|
||||
<node name="indexInSeries" value="Índices das series:" />
|
||||
<node name="tags" value="Etiquetas:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Información do libro" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="A información requirida non está indicada no catálogo" />
|
||||
<node name="cacheDirectoryError" value="Non é posíbel crear o cartafol da caché" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Información" />
|
||||
<node name="message" value="O catálogo está baleiro" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Resultados da busca" />
|
||||
<node name="message" value="Non se atopa ningún libro coincidente" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="O dicionario non está instalado"/>
|
||||
<node name="permissionDenied" value="Permiso denegado"/>
|
||||
<node name="noFavorites" value="A súa lista de preferencias está baleira"/>
|
||||
<node name="emptyCatalog" value="O catálogo está baleiro"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Navegador"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Eltávolítás a kedvencek közül"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Szerzők">
|
||||
<node name="summary" value="Könyvek szerzők szerint"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Katalógus megnyitása"/>
|
||||
<node name="showResults" value="Eredmények"/>
|
||||
<node name="showBooks" value="Könyvek"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Minta törlése"/>
|
||||
<node name="downloadDemo" value="Minta letöltése"/>
|
||||
<node name="buy" value="Vásárlás (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Megnyitás böngészőben" />
|
||||
<node name="stopLoading" value="Letöltés leállítása" />
|
||||
<node name="stopSearching" value="Keresés leállítása" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Sorozat:" />
|
||||
<node name="indexInSeries" value="Sorszám:" />
|
||||
<node name="tags" value="Címkék:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Könyv adatai" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="Szükséges információ nincs megadva a katalógusban" />
|
||||
<node name="cacheDirectoryError" value="Gyorsítótár létrehozása sikertelen" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Információ" />
|
||||
<node name="message" value="A katalógus üres" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Eredmények" />
|
||||
<node name="message" value="Nem található megfelelő könyv" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Sajnos nincs telepítve szótár"/>
|
||||
<node name="permissionDenied" value="Sanos nem engedélyezett"/>
|
||||
<node name="noFavorites" value="A Kedvencek listája üres"/>
|
||||
<node name="emptyCatalog" value="A katalógus üres"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Böngésző"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Remove from favorites" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Per autore">
|
||||
<node name="summary" value="Books sorted by author" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Apri catalogo"/>
|
||||
<node name="showResults" value="Mostra risultati"/>
|
||||
<node name="showBooks" value="Mostra libri"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Cancella esempio"/>
|
||||
<node name="downloadDemo" value="Scarica esempio"/>
|
||||
<node name="buy" value="Compra (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Apri nel browser" />
|
||||
<node name="stopLoading" value="Ferma caricamento" />
|
||||
<node name="stopSearching" value="Ferma ricerca" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Serie:" />
|
||||
<node name="indexInSeries" value="Indice in serie:" />
|
||||
<node name="tags" value="Etichette:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Info Libro" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" toBeTranslated="true" value="Required information is not specified in the catalog" />
|
||||
<node name="cacheDirectoryError" toBeTranslated="true" value="Unable to create cache directory" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Informazioni" />
|
||||
<node name="message" value="Il catalogo è vuoto" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Risultati ricerca" />
|
||||
<node name="message" value="Non sono stati trovati libri adatti" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Dictionary is not installed, sorry" toBeTranslated="true"/>
|
||||
<node name="permissionDenied" value="Permission denied, sorry" toBeTranslated="true"/>
|
||||
<node name="noFavorites" value="Your favorites list is empty, sorry" toBeTranslated="true"/>
|
||||
<node name="emptyCatalog" value="Il catalogo è vuoto"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Browser"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Verwijderen van favorieten"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Auteurs">
|
||||
<node name="summary" value="Boeken gesorteerd op auteur"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Open catalogus"/>
|
||||
<node name="showResults" value="Toon resulten"/>
|
||||
<node name="showBooks" value="Toon boeken"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Verwijder voorbeeld"/>
|
||||
<node name="downloadDemo" value="Download voorbeeld"/>
|
||||
<node name="buy" value="Koop (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Openen in de browser" />
|
||||
<node name="stopLoading" value="Stop loading" toBeTranslated="true" />
|
||||
<node name="stopSearching" value="Stop searching" toBeTranslated="true" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Serie:" />
|
||||
<node name="indexInSeries" value="Nummer in serie:" />
|
||||
<node name="tags" value="Trefwoorden:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Boekinformatie" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="Required information is not specified in the catalog" toBeTranslated="true" />
|
||||
<node name="cacheDirectoryError" value="Maken van de cache-directory is mislukt" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Informatie" />
|
||||
<node name="message" value="Catalogus is leeg" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Zoekresultaten" />
|
||||
<node name="message" value="Er zijn geen geschikte boeken gevonden" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Woordenboek is niet geïnstalleerd"/>
|
||||
<node name="permissionDenied" value="Toegang geweigerd"/>
|
||||
<node name="noFavorites" value="Je lijst met favorieten is leeg"/>
|
||||
<node name="emptyCatalog" value="Catalogus is leeg"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Browser"/>
|
||||
|
|
|
@ -46,6 +46,18 @@
|
|||
<node name="removeFromFavorites" value="Убрать из избранного"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Авторы">
|
||||
<node name="summary" value="Книги, разложенные по авторам"/>
|
||||
</node>
|
||||
<node name="byTitle" value="Названия">
|
||||
<node name="summary" value="Книги, разложенные по названиям"/>
|
||||
</node>
|
||||
<node name="byDate" value="Дата">
|
||||
<node name="summary" value="Книги, разложенные по дате покупки"/>
|
||||
</node>
|
||||
<node name="bySeries" value="По сериям">
|
||||
<node name="summary" value="Книги, разложенные по сериям"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Открыть каталог"/>
|
||||
<node name="showResults" value="Показать результаты"/>
|
||||
<node name="showBooks" value="Показать книги"/>
|
||||
|
@ -56,6 +68,8 @@
|
|||
<node name="deleteDemo" value="Удалить фрагмент"/>
|
||||
<node name="downloadDemo" value="Скачать фрагмент"/>
|
||||
<node name="buy" value="Купить (%s)"/>
|
||||
<node name="addToBasket" value="Добавить в корзину"/>
|
||||
<node name="removeFromBasket" value="Убрать из корзины"/>
|
||||
<node name="openInBrowser" value="Показать в браузере" />
|
||||
<node name="stopLoading" value="Остановить загрузку" />
|
||||
<node name="stopSearching" value="Остановить поиск" />
|
||||
|
@ -108,6 +122,7 @@
|
|||
<node name="series" value="Серия:" />
|
||||
<node name="indexInSeries" value="Номер в серии:" />
|
||||
<node name="tags" value="Категории:" />
|
||||
<node name="catalog" value="Каталог:" />
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Информация о книге" />
|
||||
|
@ -558,10 +573,6 @@
|
|||
<node name="noRequiredInformation" value="Информация нет в каталоге" />
|
||||
<node name="cacheDirectoryError" value="Не удается создать каталог для кэша" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Информация" />
|
||||
<node name="message" value="Каталог пуст" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Результаты поиска" />
|
||||
<node name="message" value="Подходящих книг не найдено" />
|
||||
|
@ -609,6 +620,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Не удалось запустить словарь"/>
|
||||
<node name="permissionDenied" value="Нет доступа к файлам" />
|
||||
<node name="noFavorites" value="Вы пока не добавили ни одной книги в «Избранное»"/>
|
||||
<node name="emptyCatalog" value="Каталог пуст"/>
|
||||
<node name="emptyBasket" value="В корзине нет книг"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="браузере"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="ลบจากหนังสือเล่มโปรด"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="ชื่อผู้แต่ง ">
|
||||
<node name="summary" value="เรียงตามชื่อผู้แต่ง"/>
|
||||
</node>
|
||||
<node name="byTitle" value="ชื่อหนังสือ">
|
||||
<node name="summary" value="เรียงตามชื่อหนังสือ"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="เปิดแคตตาล็อก"/>
|
||||
<node name="showResults" value="แสดงผลการค้นหา"/>
|
||||
<node name="showBooks" value="แสดงหนังสือ"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="ลบหนังสือตัวอย่าง"/>
|
||||
<node name="downloadDemo" value="ดาวน์โหลดหนังสือตัวอย่าง"/>
|
||||
<node name="buy" value="ซื้อ (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="เปิดในเว็บบราวเซอร์"/>
|
||||
<node name="stopLoading" value="หยุดการโหลด"/>
|
||||
<node name="stopSearching" value="หยุดการค้นหา"/>
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="ชุดหนังสือ:"/>
|
||||
<node name="indexInSeries" value="ดัชนีชุดหนังสือ:"/>
|
||||
<node name="tags" value="แท็ก:"/>
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="ข้อมูลหนังสือ"/>
|
||||
|
@ -237,12 +252,12 @@
|
|||
<node name="summaryOff" value="ไม่หมุนหน้าจอเมื่อหมุนตัวเครื่อง"/>
|
||||
</node>
|
||||
<node name="showStatusBar" value="แสดงแถบสถานะ">
|
||||
<node name="summaryOn" value="แสดงแถบสถานะเมื่อแสดงเมนู"/>
|
||||
<node name="summaryOff" value="ซ่อนแถบสถานะเมื่อแสดง"/>
|
||||
<node name="summaryOn" value="แสดงแถบสถานะขณะอ่านหนังสือ"/>
|
||||
<node name="summaryOff" value="ซ่อนแถบสถานะขณะอ่านหนังสือ"/>
|
||||
</node>
|
||||
<node name="showStatusBarWhenMenuIsActive" value="Show status bar when menu is active" toBeTranslated="true">
|
||||
<node name="summaryOn" value="Show status bar when menu becomes active" toBeTranslated="true"/>
|
||||
<node name="summaryOff" value="Don't show status bar when menu becomes active" toBeTranslated="true"/>
|
||||
<node name="showStatusBarWhenMenuIsActive" value="แสดงแถบสถานะเมื่อแสดงเมนู">
|
||||
<node name="summaryOn" value="แสดงแถบสถานะเมื่อแสดงเมนู" />
|
||||
<node name="summaryOff" value="ไม่แสดงแถบสถานะเมื่อแสดงเมนู" />
|
||||
</node>
|
||||
</node>
|
||||
<node name="text" value="ข้อความ">
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="ข้อมูลที่ต้องการไม่ได้ระบุในแคตตาล็อก"/>
|
||||
<node name="cacheDirectoryError" value="ไม่สามารถสร้างแคชสำหรับไดเรคทอรี"/>
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="ข้อมูล"/>
|
||||
<node name="message" value="แคตตาล็อกไม่มีข้อมูล"/>
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="ผลการค้นหา"/>
|
||||
<node name="message" value="ไม่พบหนังสือที่ต้องการค้นหา"/>
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="ขออภัย, พจนานุกรมไม่ได้รับการติดตั้ง"/>
|
||||
<node name="permissionDenied" value="ขออภัย, ไม่ได้รับการอนุญาต"/>
|
||||
<node name="noFavorites" value="ขออภัย, ไม่มีข้อมูลในรายการโปรดของคุณ"/>
|
||||
<node name="emptyCatalog" value="แคตตาล็อกไม่มีข้อมูล"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="เว็บเบราว์เซอร์"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Remove from favorites" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Автори">
|
||||
<node name="summary" value="Books sorted by author" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Відкрити теку"/>
|
||||
<node name="showResults" value="Показати результати"/>
|
||||
<node name="showBooks" value="Показати книжки"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Видалити уривок"/>
|
||||
<node name="downloadDemo" value="Завантажити уривок"/>
|
||||
<node name="buy" value="Придбати (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Показати у браузері" />
|
||||
<node name="stopLoading" value="Припинити завантаження" />
|
||||
<node name="stopSearching" value="Припинити пошук" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Серія:" />
|
||||
<node name="indexInSeries" value="Номер у серії:" />
|
||||
<node name="tags" value="Категорії:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Інформація про книгу" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="Необхідна інформація не знайдена в каталозі" />
|
||||
<node name="cacheDirectoryError" value="Не вдається створити каталог для кеша" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Інформація" />
|
||||
<node name="message" value="Каталог порожній" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Результати пошуку" />
|
||||
<node name="message" value="Відповідних книг не знайдено" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Dictionary is not installed, sorry" toBeTranslated="true"/>
|
||||
<node name="permissionDenied" value="Permission denied, sorry" toBeTranslated="true"/>
|
||||
<node name="noFavorites" value="Your favorites list is empty, sorry" toBeTranslated="true"/>
|
||||
<node name="emptyCatalog" value="Каталог порожній"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="браузері"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="Xóa khỏi yêu thích"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="Theo tác giả">
|
||||
<node name="summary" value="Sách được xếp theo tác giả"/>
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="Mở danh mục"/>
|
||||
<node name="showResults" value="Hiện kết quả"/>
|
||||
<node name="showBooks" value="Show books"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="Xóa bản thử"/>
|
||||
<node name="downloadDemo" value="Tải về bản thử"/>
|
||||
<node name="buy" value="Mua (%s)"/>
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="Mở trình duyệt" />
|
||||
<node name="stopLoading" value="Dừng tải" />
|
||||
<node name="stopSearching" value="Dừng tìm kiếm" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="Bộ sách:" />
|
||||
<node name="indexInSeries" value="Chỉ mục trong bộ:" />
|
||||
<node name="tags" value="Từ khóa:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="Thông tin sách" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="Thông tin yêu cầu không định vị được trong catalo" />
|
||||
<node name="cacheDirectoryError" value="Không thể tạo thư mục đệm" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="Thông tin" />
|
||||
<node name="message" value="Danh mục rỗng" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="Kết quả Tìm kiếm" />
|
||||
<node name="message" value="Không tìm thấy sách thích hợp" />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="Xin lỗi, từ điển chưa được cài"/>
|
||||
<node name="permissionDenied" value="Xin lỗi, từ chối cho phép "/>
|
||||
<node name="noFavorites" value="Xin lỗi, danh sách yêu thích của bạn đang trống"/>
|
||||
<node name="emptyCatalog" value="Danh mục rỗng"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="Trình duyệt"/>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
<node name="removeFromFavorites" value="从收藏中移除"/>
|
||||
</node>
|
||||
<node name="networkView">
|
||||
<node name="byAuthor" value="作者">
|
||||
<node name="summary" value="按作者排序" />
|
||||
</node>
|
||||
<node name="byTitle" value="By title" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by title" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="byDate" value="By date" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by date of purchasing" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bySeries" value="By series" toBeTranslated="true">
|
||||
<node name="summary" value="Books sorted by series" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="openCatalog" value="打开书库目录" />
|
||||
<node name="showResults" value="显示结果"/>
|
||||
<node name="showBooks" value="显示书籍"/>
|
||||
|
@ -57,6 +69,8 @@
|
|||
<node name="deleteDemo" value="删除试读本" />
|
||||
<node name="downloadDemo" value="下载试读本" />
|
||||
<node name="buy" value="购买(%s)" />
|
||||
<node name="addToBasket" value="Add to basket" toBeTranslated="true"/>
|
||||
<node name="removeFromBasket" value="Remove from basket" toBeTranslated="true"/>
|
||||
<node name="openInBrowser" value="在浏览器中打开" />
|
||||
<node name="stopLoading" value="停止加载" />
|
||||
<node name="stopSearching" value="停止搜索" />
|
||||
|
@ -109,6 +123,7 @@
|
|||
<node name="series" value="系列:" />
|
||||
<node name="indexInSeries" value="系列序号:" />
|
||||
<node name="tags" value="标签:" />
|
||||
<node name="catalog" value="Catalog:" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="bookInfo">
|
||||
<node name="bookInfo" value="书籍信息" />
|
||||
|
@ -559,10 +574,6 @@
|
|||
<node name="noRequiredInformation" value="书库目录中必须的信息没有定义" />
|
||||
<node name="cacheDirectoryError" value="无法创建缓存目录" />
|
||||
</node>
|
||||
<node name="emptyCatalogBox">
|
||||
<node name="title" value="信息" />
|
||||
<node name="message" value="空书库目录" />
|
||||
</node>
|
||||
<node name="emptySearchResults">
|
||||
<node name="title" value="搜索结果" />
|
||||
<node name="message" value="没有找到对应的书籍." />
|
||||
|
@ -610,6 +621,8 @@
|
|||
<node name="dictionaryIsNotInstalled" value="抱歉,你没有安装字典."/>
|
||||
<node name="permissionDenied" value="对不起,没有权限"/>
|
||||
<node name="noFavorites" value="对不起,你的收藏列表为空"/>
|
||||
<node name="emptyCatalog" value="空书库目录"/>
|
||||
<node name="emptyBasket" value="Your basket is empty, sorry" toBeTranslated="true"/>
|
||||
</node>
|
||||
<node name="external">
|
||||
<node name="browser" value="浏览器" />
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<node name="pt" value="โปรตุเกส"/>
|
||||
<node name="ru" value="รัสเซีย"/>
|
||||
<node name="sv" value="สวีเดน"/>
|
||||
<node name="th" value="Thai" toBeTranslated="true"/>
|
||||
<node name="th" value="ไทย" />
|
||||
<node name="tr" value="ตุรกี"/>
|
||||
<node name="uk" value="ยูเครน"/>
|
||||
<node name="vi" value="เวียดนาม"/>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
|
@ -101,116 +101,12 @@
|
|||
android:paddingRight="10dp"
|
||||
android:paddingTop="10dp"
|
||||
>
|
||||
<LinearLayout
|
||||
android:id="@+id/network_book_title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/network_book_title_key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/network_book_title_value"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/network_book_authors"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/network_book_authors_key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/network_book_authors_value"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/network_book_series"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/network_book_series_key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/network_book_series_value"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/network_book_series_index"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/network_book_series_index_key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/network_book_series_index_value"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/network_book_tags"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/network_book_tags_key"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/network_book_tags_value"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_title" />
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_authors" />
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_series_title" />
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_series_index" />
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_tags" />
|
||||
<include layout="@layout/book_info_pair" android:id="@+id/network_book_catalog" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/network_book_description_title"
|
||||
|
|
|
@ -21,7 +21,17 @@ public final class ZipFile {
|
|||
}
|
||||
|
||||
private final InputStreamHolder myStreamHolder;
|
||||
private final LinkedHashMap<String,LocalFileHeader> myFileHeaders = new LinkedHashMap<String,LocalFileHeader>();
|
||||
private final LinkedHashMap<String,LocalFileHeader> myFileHeaders = new LinkedHashMap<String,LocalFileHeader>() {
|
||||
@Override
|
||||
public LocalFileHeader get(Object key) {
|
||||
return super.get(((String)key).toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileHeader put(String key, LocalFileHeader value) {
|
||||
return super.put(key.toLowerCase(), value);
|
||||
}
|
||||
};
|
||||
|
||||
private boolean myAllFilesAreRead;
|
||||
|
||||
|
@ -50,7 +60,7 @@ public final class ZipFile {
|
|||
}
|
||||
if (header.FileName != null) {
|
||||
myFileHeaders.put(header.FileName, header);
|
||||
if (header.FileName.equals(fileToFind)) {
|
||||
if (header.FileName.equalsIgnoreCase(fileToFind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class BookInfoActivity extends Activity {
|
|||
}
|
||||
|
||||
private void setupInfoPair(int id, String key, CharSequence value) {
|
||||
LinearLayout layout = (LinearLayout)findViewById(id);
|
||||
final LinearLayout layout = (LinearLayout)findViewById(id);
|
||||
if (value == null || value.length() == 0) {
|
||||
layout.setVisibility(View.GONE);
|
||||
return;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.geometerplus.android.fbreader;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
@ -152,6 +153,7 @@ public final class FBReader extends ZLAndroidActivity {
|
|||
}
|
||||
};
|
||||
UIUtil.wait("search", runnable, this);
|
||||
startActivity(new Intent(this, getClass()));
|
||||
} else {
|
||||
super.onNewIntent(intent);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.geometerplus.zlibrary.text.view.ZLTextFixedPosition;
|
|||
import org.geometerplus.fbreader.library.*;
|
||||
|
||||
import org.geometerplus.android.util.UIUtil;
|
||||
import org.geometerplus.android.util.SQLiteUtil;
|
||||
|
||||
public final class SQLiteBooksDatabase extends BooksDatabase {
|
||||
private final String myInstanceId;
|
||||
|
@ -107,29 +108,6 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
}, context);
|
||||
}
|
||||
|
||||
private static void bindString(SQLiteStatement statement, int index, String value) {
|
||||
if (value != null) {
|
||||
statement.bindString(index, value);
|
||||
} else {
|
||||
statement.bindNull(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static void bindDate(SQLiteStatement statement, int index, Date value) {
|
||||
if (value != null) {
|
||||
statement.bindLong(index, value.getTime());
|
||||
} else {
|
||||
statement.bindNull(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static Date getDate(Cursor cursor, int index) {
|
||||
if (cursor.isNull(index)) {
|
||||
return null;
|
||||
}
|
||||
return new Date(cursor.getLong(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Book loadBook(long bookId) {
|
||||
Book book = null;
|
||||
|
@ -278,8 +256,8 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
);
|
||||
}
|
||||
myUpdateBookInfoStatement.bindLong(1, fileId);
|
||||
bindString(myUpdateBookInfoStatement, 2, encoding);
|
||||
bindString(myUpdateBookInfoStatement, 3, language);
|
||||
SQLiteUtil.bindString(myUpdateBookInfoStatement, 2, encoding);
|
||||
SQLiteUtil.bindString(myUpdateBookInfoStatement, 3, language);
|
||||
myUpdateBookInfoStatement.bindString(4, title);
|
||||
myUpdateBookInfoStatement.bindLong(5, bookId);
|
||||
myUpdateBookInfoStatement.execute();
|
||||
|
@ -292,8 +270,8 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
"INSERT OR IGNORE INTO Books (encoding,language,title,file_id) VALUES (?,?,?,?)"
|
||||
);
|
||||
}
|
||||
bindString(myInsertBookInfoStatement, 1, encoding);
|
||||
bindString(myInsertBookInfoStatement, 2, language);
|
||||
SQLiteUtil.bindString(myInsertBookInfoStatement, 1, encoding);
|
||||
SQLiteUtil.bindString(myInsertBookInfoStatement, 2, language);
|
||||
myInsertBookInfoStatement.bindString(3, title);
|
||||
final FileInfoSet infoSet = new FileInfoSet(file);
|
||||
myInsertBookInfoStatement.bindLong(4, infoSet.getId(file));
|
||||
|
@ -709,9 +687,9 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
cursor.getLong(1),
|
||||
cursor.getString(2),
|
||||
cursor.getString(3),
|
||||
getDate(cursor, 4),
|
||||
getDate(cursor, 5),
|
||||
getDate(cursor, 6),
|
||||
SQLiteUtil.getDate(cursor, 4),
|
||||
SQLiteUtil.getDate(cursor, 5),
|
||||
SQLiteUtil.getDate(cursor, 6),
|
||||
(int)cursor.getLong(7),
|
||||
cursor.getString(8),
|
||||
(int)cursor.getLong(9),
|
||||
|
@ -737,9 +715,9 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
cursor.getLong(1),
|
||||
cursor.getString(2),
|
||||
cursor.getString(3),
|
||||
getDate(cursor, 4),
|
||||
getDate(cursor, 5),
|
||||
getDate(cursor, 6),
|
||||
SQLiteUtil.getDate(cursor, 4),
|
||||
SQLiteUtil.getDate(cursor, 5),
|
||||
SQLiteUtil.getDate(cursor, 6),
|
||||
(int)cursor.getLong(7),
|
||||
cursor.getString(8),
|
||||
(int)cursor.getLong(9),
|
||||
|
@ -775,11 +753,11 @@ public final class SQLiteBooksDatabase extends BooksDatabase {
|
|||
|
||||
statement.bindLong(1, bookmark.getBookId());
|
||||
statement.bindString(2, bookmark.getText());
|
||||
bindDate(statement, 3, bookmark.getTime(Bookmark.CREATION));
|
||||
bindDate(statement, 4, bookmark.getTime(Bookmark.MODIFICATION));
|
||||
bindDate(statement, 5, bookmark.getTime(Bookmark.ACCESS));
|
||||
SQLiteUtil.bindDate(statement, 3, bookmark.getTime(Bookmark.CREATION));
|
||||
SQLiteUtil.bindDate(statement, 4, bookmark.getTime(Bookmark.MODIFICATION));
|
||||
SQLiteUtil.bindDate(statement, 5, bookmark.getTime(Bookmark.ACCESS));
|
||||
statement.bindLong(6, bookmark.getAccessCount());
|
||||
bindString(statement, 7, bookmark.ModelId);
|
||||
SQLiteUtil.bindString(statement, 7, bookmark.ModelId);
|
||||
statement.bindLong(8, bookmark.ParagraphIndex);
|
||||
statement.bindLong(9, bookmark.ElementIndex);
|
||||
statement.bindLong(10, bookmark.CharIndex);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ImageViewActivity extends Activity {
|
|||
setContentView(new ImageView());
|
||||
|
||||
final Uri uri = getIntent().getData();
|
||||
if ("imagefile".equals(uri.getScheme())) {
|
||||
if (ZLFileImage.SCHEME.equals(uri.getScheme())) {
|
||||
try {
|
||||
final String[] data = uri.getPath().split("\000");
|
||||
final ZLFileImage image = new ZLFileImage(
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -35,15 +37,14 @@ 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.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSCustomLink;
|
||||
|
||||
import org.geometerplus.android.util.UIUtil;
|
||||
|
||||
public class AddCustomCatalogActivity extends Activity {
|
||||
private ZLResource myResource;
|
||||
private Integer myCatalogId;
|
||||
private String myIcon;
|
||||
private volatile ICustomNetworkLink myLink;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -83,21 +84,16 @@ public class AddCustomCatalogActivity extends Activity {
|
|||
);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
myLink = NetworkLibraryActivity.getLinkFromIntent(intent);
|
||||
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);
|
||||
}
|
||||
|
||||
if (myLink != null) {
|
||||
setTextById(R.id.add_custom_catalog_url, myLink.getUrlInfo(INetworkLink.URL_MAIN).URL);
|
||||
setTextById(R.id.add_custom_catalog_title, myLink.getTitle());
|
||||
setTextById(R.id.add_custom_catalog_summary, myLink.getSummary());
|
||||
setExtraFieldsVisibility(true);
|
||||
} else if (uri != null) {
|
||||
loadInfoByUri(uri);
|
||||
} else {
|
||||
setExtraFieldsVisibility(false);
|
||||
}
|
||||
|
@ -126,24 +122,22 @@ public class AddCustomCatalogActivity extends Activity {
|
|||
setErrorByKey("invalidUrl");
|
||||
return;
|
||||
}
|
||||
if (!getExtraFieldsVisibility()) {
|
||||
if (myLink == null) {
|
||||
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)
|
||||
);
|
||||
myLink.setTitle(title);
|
||||
myLink.setSummary(summary);
|
||||
|
||||
Intent intent = new Intent(
|
||||
NetworkLibraryActivity.ADD_CATALOG,
|
||||
uri,
|
||||
AddCustomCatalogActivity.this,
|
||||
NetworkLibraryActivity.class
|
||||
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
NetworkLibraryActivity.addLinkToIntent(intent, myLink);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@ -152,10 +146,6 @@ public class AddCustomCatalogActivity extends Activity {
|
|||
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() {
|
||||
|
@ -244,17 +234,16 @@ public class AddCustomCatalogActivity extends Activity {
|
|||
}
|
||||
|
||||
setTextById(R.id.add_custom_catalog_url, textUrl);
|
||||
String siteName = uri.getHost();
|
||||
final 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 HashMap<String,UrlInfo> infos = new HashMap<String,UrlInfo>();
|
||||
infos.put(INetworkLink.URL_MAIN, new UrlInfo(textUrl));
|
||||
myLink = new OPDSCustomLink(
|
||||
ICustomNetworkLink.INVALID_ID, siteName, null, null, infos
|
||||
);
|
||||
|
||||
final Runnable loadInfoRunnable = new Runnable() {
|
||||
private String myError;
|
||||
|
@ -262,20 +251,19 @@ public class AddCustomCatalogActivity extends Activity {
|
|||
public void run() {
|
||||
try {
|
||||
myError = null;
|
||||
link.reloadInfo();
|
||||
myLink.reloadInfo(false);
|
||||
} 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();
|
||||
setTextById(R.id.add_custom_catalog_title, myLink.getTitle());
|
||||
setTextById(R.id.add_custom_catalog_summary, myLink.getSummary());
|
||||
setExtraFieldsVisibility(true);
|
||||
} else {
|
||||
runErrorDialog(myError);
|
||||
myIcon = null;
|
||||
myLink = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -25,10 +25,9 @@ import android.view.Menu;
|
|||
import android.view.ContextMenu;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
|
||||
import org.geometerplus.fbreader.network.tree.AddCustomCatalogItemTree;
|
||||
|
||||
class AddCustomCatalogItemActions extends NetworkTreeActions {
|
||||
|
||||
public static final int RUN_ITEM_ID = 0;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,44 +19,103 @@
|
|||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.geometerplus.zlibrary.ui.android.R;
|
||||
|
||||
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.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkLibrary;
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
import org.geometerplus.android.util.UIUtil;
|
||||
|
||||
class AuthenticationDialog {
|
||||
private static AuthenticationDialog ourDialog;
|
||||
|
||||
class AuthenticationDialog extends NetworkDialog {
|
||||
public AuthenticationDialog() {
|
||||
super("AuthenticationDialog");
|
||||
public static AuthenticationDialog getDialog() {
|
||||
if (ourDialog == null) {
|
||||
ourDialog = new AuthenticationDialog();
|
||||
}
|
||||
return ourDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearData() {
|
||||
private class DialogHandler extends Handler {
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
library.invalidateVisibility();
|
||||
library.synchronize();
|
||||
NetworkView.Instance().fireModelChanged();
|
||||
if (message.what == -1) {
|
||||
myErrorMessage = (String)message.obj;
|
||||
myActivity.showDialog(0);
|
||||
} else if (message.what == 1) {
|
||||
if (myOnSuccessRunnable != null) {
|
||||
myOnSuccessRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final ZLResource myResource =
|
||||
ZLResource.resource("dialog").getResource("AuthenticationDialog");
|
||||
|
||||
private INetworkLink myLink;
|
||||
private String myErrorMessage;
|
||||
private Runnable myOnSuccessRunnable;
|
||||
private Activity myActivity;
|
||||
|
||||
private final DialogHandler myHandler = new DialogHandler();
|
||||
|
||||
public static void show(Activity activity, INetworkLink link, Runnable onSuccessRunnable) {
|
||||
getDialog().showInternal(activity, link, onSuccessRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createLayout() {
|
||||
private void showInternal(Activity activity, INetworkLink link, Runnable onSuccessRunnable) {
|
||||
myLink = link;
|
||||
myErrorMessage = null;
|
||||
myOnSuccessRunnable = onSuccessRunnable;
|
||||
activity.showDialog(0);
|
||||
}
|
||||
|
||||
private void sendSuccess() {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(1, null));
|
||||
}
|
||||
|
||||
private void sendCancel() {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(0, null));
|
||||
}
|
||||
|
||||
private void sendError(String message) {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(-1, message));
|
||||
}
|
||||
|
||||
private View createLayout() {
|
||||
final View layout = myActivity.getLayoutInflater().inflate(R.layout.network_authentication_dialog, null);
|
||||
|
||||
((TextView) layout.findViewById(R.id.network_authentication_login_text)).setText(myResource.getResource("login").getValue());
|
||||
((TextView) layout.findViewById(R.id.network_authentication_password_text)).setText(myResource.getResource("password").getValue());
|
||||
((TextView)layout.findViewById(R.id.network_authentication_login_text)).setText(myResource.getResource("login").getValue());
|
||||
((TextView)layout.findViewById(R.id.network_authentication_password_text)).setText(myResource.getResource("password").getValue());
|
||||
|
||||
final TextView registerText = (TextView) layout.findViewById(R.id.network_authentication_register);
|
||||
final TextView registerText = (TextView)layout.findViewById(R.id.network_authentication_register);
|
||||
registerText.setText(myResource.getResource("register").getValue());
|
||||
registerText.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
//final NetworkAuthenticationManager mgr = myLink.authenticationManager();
|
||||
if (Util.isRegistrationSupported(myActivity, myLink)) {
|
||||
myActivity.dismissDialog(NetworkDialog.DIALOG_AUTHENTICATION);
|
||||
myActivity.dismissDialog(0);
|
||||
Util.runRegistrationDialog(myActivity, myLink);
|
||||
}
|
||||
}
|
||||
|
@ -64,15 +123,14 @@ class AuthenticationDialog extends NetworkDialog {
|
|||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPositive(DialogInterface dialog) {
|
||||
AlertDialog alert = (AlertDialog) dialog;
|
||||
final String login = ((TextView) alert.findViewById(R.id.network_authentication_login)).getText().toString().trim();
|
||||
final String password = ((TextView) alert.findViewById(R.id.network_authentication_password)).getText().toString();
|
||||
private void onPositive(DialogInterface dialog) {
|
||||
AlertDialog alert = (AlertDialog)dialog;
|
||||
final String login = ((TextView)alert.findViewById(R.id.network_authentication_login)).getText().toString().trim();
|
||||
final String password = ((TextView)alert.findViewById(R.id.network_authentication_password)).getText().toString();
|
||||
|
||||
if (login.length() == 0) {
|
||||
final String err = myResource.getResource("loginIsEmpty").getValue();
|
||||
sendError(true, false, err);
|
||||
sendError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,37 +145,64 @@ class AuthenticationDialog extends NetworkDialog {
|
|||
}
|
||||
} catch (ZLNetworkException e) {
|
||||
mgr.logOut();
|
||||
sendError(true, false, e.getMessage());
|
||||
sendError(e.getMessage());
|
||||
return;
|
||||
}
|
||||
sendSuccess(false);
|
||||
sendSuccess();
|
||||
}
|
||||
};
|
||||
UIUtil.wait("authentication", runnable, myActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNegative(DialogInterface dialog) {
|
||||
private void onNegative(DialogInterface dialog) {
|
||||
final NetworkAuthenticationManager mgr = myLink.authenticationManager();
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
if (mgr.mayBeAuthorised(false)) {
|
||||
mgr.logOut();
|
||||
sendCancel(false);
|
||||
sendCancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
UIUtil.wait("signOut", runnable, myActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareDialogInternal(Dialog dialog) {
|
||||
public final Dialog createDialog(final Activity activity) {
|
||||
myActivity = activity;
|
||||
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
onPositive(dialog);
|
||||
} else {
|
||||
onNegative(dialog);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final View layout = createLayout();
|
||||
final ZLResource buttonResource = ZLResource.resource("dialog").getResource("button");
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setView(layout)
|
||||
.setTitle(myResource.getResource("title").getValue())
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), listener)
|
||||
.setNegativeButton(buttonResource.getResource("cancel").getValue(), listener)
|
||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
onNegative(dialog);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
public final void prepareDialog(final Activity activity, Dialog dialog) {
|
||||
myActivity = activity;
|
||||
|
||||
final NetworkAuthenticationManager mgr = myLink.authenticationManager();
|
||||
|
||||
((TextView) dialog.findViewById(R.id.network_authentication_login)).setText(mgr.UserNameOption.getValue());
|
||||
((TextView) dialog.findViewById(R.id.network_authentication_password)).setText("");
|
||||
((TextView)dialog.findViewById(R.id.network_authentication_login)).setText(mgr.UserNameOption.getValue());
|
||||
((TextView)dialog.findViewById(R.id.network_authentication_password)).setText("");
|
||||
|
||||
final TextView error = (TextView) dialog.findViewById(R.id.network_authentication_error);
|
||||
final TextView error = (TextView)dialog.findViewById(R.id.network_authentication_error);
|
||||
if (myErrorMessage == null) {
|
||||
error.setVisibility(View.GONE);
|
||||
error.setText("");
|
||||
|
|
|
@ -29,7 +29,7 @@ import android.os.Message;
|
|||
import android.os.Handler;
|
||||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
import org.geometerplus.fbreader.network.NetworkItem;
|
||||
|
||||
|
||||
abstract class ItemsLoadingHandler extends Handler {
|
||||
|
@ -37,20 +37,20 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
private static final int WHAT_UPDATE_ITEMS = 0;
|
||||
private static final int WHAT_FINISHED = 1;
|
||||
|
||||
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
|
||||
private final HashMap<INetworkLink, LinkedList<NetworkLibraryItem>> myUncommitedItems = new HashMap<INetworkLink, LinkedList<NetworkLibraryItem>>();
|
||||
private final LinkedList<NetworkItem> myItems = new LinkedList<NetworkItem>();
|
||||
private final HashMap<INetworkLink, LinkedList<NetworkItem>> myUncommitedItems = new HashMap<INetworkLink, LinkedList<NetworkItem>>();
|
||||
private final Object myItemsMonitor = new Object();
|
||||
|
||||
private volatile boolean myFinishProcessed;
|
||||
private final Object myFinishMonitor = new Object();
|
||||
|
||||
|
||||
public final void addItem(INetworkLink link, NetworkLibraryItem item) {
|
||||
public final void addItem(INetworkLink link, NetworkItem item) {
|
||||
synchronized (myItemsMonitor) {
|
||||
myItems.add(item);
|
||||
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
|
||||
LinkedList<NetworkItem> uncommited = myUncommitedItems.get(link);
|
||||
if (uncommited == null) {
|
||||
uncommited = new LinkedList<NetworkLibraryItem>();
|
||||
uncommited = new LinkedList<NetworkItem>();
|
||||
myUncommitedItems.put(link, uncommited);
|
||||
}
|
||||
uncommited.add(item);
|
||||
|
@ -59,7 +59,7 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
|
||||
public final void commitItems(INetworkLink link) {
|
||||
synchronized (myItemsMonitor) {
|
||||
LinkedList<NetworkLibraryItem> uncommited = myUncommitedItems.get(link);
|
||||
LinkedList<NetworkItem> uncommited = myUncommitedItems.get(link);
|
||||
if (uncommited != null) {
|
||||
uncommited.clear();
|
||||
}
|
||||
|
@ -98,9 +98,9 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
}
|
||||
|
||||
private final void doProcessFinish(String errorMessage, boolean interrupted) {
|
||||
HashSet<NetworkLibraryItem> uncommitedItems = new HashSet<NetworkLibraryItem>();
|
||||
HashSet<NetworkItem> uncommitedItems = new HashSet<NetworkItem>();
|
||||
synchronized (myUncommitedItems) {
|
||||
for (LinkedList<NetworkLibraryItem> items: myUncommitedItems.values()) {
|
||||
for (LinkedList<NetworkItem> items: myUncommitedItems.values()) {
|
||||
uncommitedItems.addAll(items);
|
||||
}
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
|
||||
|
||||
// callbacks
|
||||
public abstract void onUpdateItems(List<NetworkLibraryItem> items);
|
||||
public abstract void onUpdateItems(List<NetworkItem> items);
|
||||
public abstract void afterUpdateItems();
|
||||
public abstract void onFinish(String errorMessage, boolean interrupted, Set<NetworkLibraryItem> uncommitedItems);
|
||||
public abstract void onFinish(String errorMessage, boolean interrupted, Set<NetworkItem> uncommitedItems);
|
||||
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
|||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkOperationData;
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
import org.geometerplus.fbreader.network.NetworkItem;
|
||||
|
||||
abstract class ItemsLoadingRunnable implements Runnable {
|
||||
private final ItemsLoadingHandler myHandler;
|
||||
|
@ -99,7 +99,7 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
doLoading(new NetworkOperationData.OnNewItemListener() {
|
||||
private long myUpdateTime;
|
||||
private int myItemsNumber;
|
||||
public void onNewItem(INetworkLink link, NetworkLibraryItem item) {
|
||||
public void onNewItem(INetworkLink link, NetworkItem item) {
|
||||
myHandler.addItem(link, item);
|
||||
++myItemsNumber;
|
||||
final long now = System.currentTimeMillis();
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.os.Message;
|
|||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
|
||||
public class ItemsLoadingService extends Service {
|
||||
|
||||
|
@ -53,7 +54,7 @@ public class ItemsLoadingService extends Service {
|
|||
super.onStart(intent, startId);
|
||||
doStart();
|
||||
|
||||
final String key = intent.getStringExtra(ITEMS_LOADING_RUNNABLE_KEY);
|
||||
final NetworkTree.Key key = (NetworkTree.Key)intent.getSerializableExtra(ITEMS_LOADING_RUNNABLE_KEY);
|
||||
if (key == null) {
|
||||
doStop();
|
||||
return;
|
||||
|
|
|
@ -38,11 +38,12 @@ import org.geometerplus.zlibrary.ui.android.image.ZLAndroidImageData;
|
|||
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkBookTree;
|
||||
import org.geometerplus.fbreader.network.tree.AddCustomCatalogItemTree;
|
||||
import org.geometerplus.fbreader.network.tree.SearchItemTree;
|
||||
|
||||
import org.geometerplus.android.fbreader.tree.ZLAndroidTree;
|
||||
|
||||
abstract class NetworkBaseActivity extends ListActivity implements NetworkView.EventListener {
|
||||
|
||||
protected final ZLResource myResource = ZLResource.resource("networkView");
|
||||
|
||||
public BookDownloaderServiceConnection Connection;
|
||||
|
@ -105,6 +106,14 @@ abstract class NetworkBaseActivity extends ListActivity implements NetworkView.E
|
|||
};
|
||||
|
||||
private void setupCover(final ImageView coverView, NetworkTree tree, int width, int height) {
|
||||
if (tree instanceof AddCustomCatalogItemTree) {
|
||||
coverView.setImageResource(R.drawable.ic_list_plus);
|
||||
return;
|
||||
}
|
||||
if (tree instanceof SearchItemTree) {
|
||||
coverView.setImageResource(R.drawable.ic_list_searchresult);
|
||||
return;
|
||||
}
|
||||
if (tree instanceof ZLAndroidTree) {
|
||||
coverView.setImageResource(((ZLAndroidTree)tree).getCoverResourceId());
|
||||
return;
|
||||
|
@ -178,42 +187,31 @@ abstract class NetworkBaseActivity extends ListActivity implements NetworkView.E
|
|||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
NetworkTree tree = null;
|
||||
System.err.println("onCreateContextMenu -1");
|
||||
if (menuInfo != null) {
|
||||
final int position = ((AdapterView.AdapterContextMenuInfo)menuInfo).position;
|
||||
tree = (NetworkTree)getListAdapter().getItem(position);
|
||||
} else {
|
||||
tree = getDefaultTree();
|
||||
}
|
||||
if (tree != null) {
|
||||
final NetworkTreeActions actions = NetworkView.Instance().getActions(tree);
|
||||
if (actions != null) {
|
||||
actions.buildContextMenu(this, menu, tree);
|
||||
final NetworkTree tree = (NetworkTree)getListAdapter().getItem(position);
|
||||
if (tree != null) {
|
||||
final NetworkTreeActions actions = NetworkView.Instance().getActions(tree);
|
||||
if (actions != null) {
|
||||
actions.buildContextMenu(this, menu, tree);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NetworkTree myDefaultTree;
|
||||
protected NetworkTree getDefaultTree() {
|
||||
return myDefaultTree;
|
||||
}
|
||||
protected void setDefaultTree(NetworkTree tree) {
|
||||
myDefaultTree = tree;
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
NetworkTree tree = null;
|
||||
if (item != null && item.getMenuInfo() != null) {
|
||||
final int position = ((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).position;
|
||||
tree = (NetworkTree)getListAdapter().getItem(position);
|
||||
} else {
|
||||
tree = getDefaultTree();
|
||||
}
|
||||
if (tree != null) {
|
||||
final NetworkTreeActions actions = NetworkView.Instance().getActions(tree);
|
||||
if (actions != null && actions.runAction(this, tree, item.getItemId())) {
|
||||
return true;
|
||||
final NetworkTree tree = (NetworkTree)getListAdapter().getItem(position);
|
||||
if (tree != null) {
|
||||
final NetworkTreeActions actions = NetworkView.Instance().getActions(tree);
|
||||
if (actions != null && actions.runAction(this, tree, item.getItemId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
|
@ -260,7 +258,7 @@ abstract class NetworkBaseActivity extends ListActivity implements NetworkView.E
|
|||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return null;
|
||||
}
|
||||
final NetworkDialog dlg = NetworkDialog.getDialog(id);
|
||||
final AuthenticationDialog dlg = AuthenticationDialog.getDialog();
|
||||
if (dlg != null) {
|
||||
return dlg.createDialog(this);
|
||||
}
|
||||
|
@ -271,10 +269,10 @@ abstract class NetworkBaseActivity extends ListActivity implements NetworkView.E
|
|||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
|
||||
final NetworkDialog dlg = NetworkDialog.getDialog(id);
|
||||
final AuthenticationDialog dlg = AuthenticationDialog.getDialog();
|
||||
if (dlg != null) {
|
||||
dlg.prepareDialog(this, dialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,8 +49,6 @@ import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationMan
|
|||
|
||||
|
||||
class NetworkBookActions extends NetworkTreeActions {
|
||||
private static final String PACKAGE = "org.geometerplus.android.fbreader.network";
|
||||
|
||||
public static final int DOWNLOAD_BOOK_ITEM_ID = 0;
|
||||
public static final int DOWNLOAD_DEMO_ITEM_ID = 1;
|
||||
public static final int READ_BOOK_ITEM_ID = 2;
|
||||
|
@ -60,8 +58,11 @@ class NetworkBookActions extends NetworkTreeActions {
|
|||
public static final int BUY_DIRECTLY_ITEM_ID = 6;
|
||||
public static final int BUY_IN_BROWSER_ITEM_ID = 7;
|
||||
public static final int SHOW_BOOK_ACTIVITY_ITEM_ID = 8;
|
||||
|
||||
public static final int SHOW_BOOKS_ITEM_ID = 9;
|
||||
public static final int ADD_BOOK_TO_BASKET = 10;
|
||||
public static final int REMOVE_BOOK_FROM_BASKET = 11;
|
||||
public static final int ADD_CATALOG_TO_FAVORITES = 12;
|
||||
public static final int REMOVE_CATALOG_FROM_FAVORITES = 13;
|
||||
|
||||
private static boolean useFullReferences(NetworkBookItem book) {
|
||||
return book.reference(BookReference.Type.DOWNLOAD_FULL) != null ||
|
||||
|
@ -184,6 +185,14 @@ class NetworkBookActions extends NetworkTreeActions {
|
|||
final String price = ((BuyBookReference) reference).Price;
|
||||
actions.add(new Action(id, "buy", price));
|
||||
}
|
||||
final Basket basket = book.Link.basket();
|
||||
if (basket != null) {
|
||||
if (basket.contains(book)) {
|
||||
actions.add(new Action(REMOVE_BOOK_FROM_BASKET, "removeFromBasket"));
|
||||
} else {
|
||||
actions.add(new Action(ADD_BOOK_TO_BASKET, "addToBasket"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
@ -215,28 +224,15 @@ class NetworkBookActions extends NetworkTreeActions {
|
|||
public boolean runAction(NetworkBaseActivity activity, NetworkTree tree, int actionCode) {
|
||||
if (tree instanceof NetworkAuthorTree || tree instanceof NetworkSeriesTree) {
|
||||
switch (actionCode) {
|
||||
case SHOW_BOOKS_ITEM_ID:
|
||||
showBooks(activity, tree);
|
||||
return true;
|
||||
case SHOW_BOOKS_ITEM_ID:
|
||||
NetworkView.Instance().openTree(activity, tree);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return runAction(activity, ((NetworkBookTree) tree).Book, actionCode);
|
||||
}
|
||||
|
||||
|
||||
private void showBooks(NetworkBaseActivity activity, NetworkTree tree) {
|
||||
String key = null;
|
||||
if (tree instanceof NetworkAuthorTree) {
|
||||
key = PACKAGE + ".Authors:" + ((NetworkAuthorTree) tree).Author.DisplayName;
|
||||
} else if (tree instanceof NetworkSeriesTree) {
|
||||
key = PACKAGE + ".Series:" + ((NetworkSeriesTree) tree).SeriesTitle;
|
||||
}
|
||||
if (key != null) {
|
||||
NetworkView.Instance().openTree(activity, tree, key);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean runAction(Activity activity, NetworkBookItem book, int actionCode) {
|
||||
switch (actionCode) {
|
||||
case DOWNLOAD_BOOK_ITEM_ID:
|
||||
|
@ -266,6 +262,12 @@ class NetworkBookActions extends NetworkTreeActions {
|
|||
case SHOW_BOOK_ACTIVITY_ITEM_ID:
|
||||
NetworkView.Instance().showBookInfoActivity(activity, book);
|
||||
return true;
|
||||
case ADD_BOOK_TO_BASKET:
|
||||
book.Link.basket().add(book);
|
||||
return true;
|
||||
case REMOVE_BOOK_FROM_BASKET:
|
||||
book.Link.basket().remove(book);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -450,7 +452,7 @@ class NetworkBookActions extends NetworkTreeActions {
|
|||
}
|
||||
} catch (ZLNetworkException e) {
|
||||
}
|
||||
NetworkDialog.show(activity, NetworkDialog.DIALOG_AUTHENTICATION, book.Link, buyRunnable);
|
||||
AuthenticationDialog.show(activity, book.Link, buyRunnable);
|
||||
}
|
||||
|
||||
private static void doBuyInBrowser(Activity activity, final NetworkBookItem book) {
|
||||
|
|
|
@ -29,6 +29,7 @@ import android.view.View;
|
|||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
|
@ -88,6 +89,14 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
return myMainView;
|
||||
}
|
||||
|
||||
private void setTextById(int id, CharSequence text) {
|
||||
((TextView)findViewById(id)).setText(text);
|
||||
}
|
||||
|
||||
private void setTextFromResource(int id, String resourceKey) {
|
||||
setTextById(id, myResource.getResource(resourceKey).getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (myConnection != null) {
|
||||
|
@ -99,7 +108,7 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
new RefillAccountActions().buildContextMenu(this, menu, new RefillAccountTree(myBook.Link));
|
||||
new RefillAccountActions().buildContextMenu(this, menu, myBook.Link);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,29 +118,39 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
}
|
||||
|
||||
private final void setupDescription() {
|
||||
((TextView) findViewById(R.id.network_book_description_title)).setText(myResource.getResource("description").getValue());
|
||||
setTextFromResource(R.id.network_book_description_title, "description");
|
||||
|
||||
final TextView descriptionView = (TextView) findViewById(R.id.network_book_description);
|
||||
final String description;
|
||||
if (myBook.Summary != null) {
|
||||
description = myBook.Summary;
|
||||
} else {
|
||||
description = myResource.getResource("noDescription").getValue();
|
||||
}
|
||||
descriptionView.setText(description);
|
||||
setTextById(R.id.network_book_description, description);
|
||||
}
|
||||
|
||||
private void setPairLabelTextFromResource(int id, String resourceKey) {
|
||||
final LinearLayout layout = (LinearLayout)findViewById(id);
|
||||
((TextView)layout.findViewById(R.id.book_info_key))
|
||||
.setText(myResource.getResource(resourceKey).getValue());
|
||||
}
|
||||
|
||||
private void setPairValueText(int id, CharSequence text) {
|
||||
final LinearLayout layout = (LinearLayout)findViewById(id);
|
||||
((TextView)layout.findViewById(R.id.book_info_value)).setText(text);
|
||||
}
|
||||
|
||||
private void setupInfo() {
|
||||
((TextView) findViewById(R.id.network_book_info_title)).setText(myResource.getResource("bookInfo").getValue());
|
||||
setTextFromResource(R.id.network_book_info_title, "bookInfo");
|
||||
|
||||
((TextView) findViewById(R.id.network_book_title_key)).setText(myResource.getResource("title").getValue());
|
||||
((TextView) findViewById(R.id.network_book_authors_key)).setText(myResource.getResource("authors").getValue());
|
||||
((TextView) findViewById(R.id.network_book_series_key)).setText(myResource.getResource("series").getValue());
|
||||
((TextView) findViewById(R.id.network_book_series_index_key)).setText(myResource.getResource("indexInSeries").getValue());
|
||||
((TextView) findViewById(R.id.network_book_tags_key)).setText(myResource.getResource("tags").getValue());
|
||||
setPairLabelTextFromResource(R.id.network_book_title, "title");
|
||||
setPairLabelTextFromResource(R.id.network_book_authors, "authors");
|
||||
setPairLabelTextFromResource(R.id.network_book_series_title, "series");
|
||||
setPairLabelTextFromResource(R.id.network_book_series_index, "indexInSeries");
|
||||
setPairLabelTextFromResource(R.id.network_book_tags, "tags");
|
||||
setPairLabelTextFromResource(R.id.network_book_catalog, "catalog");
|
||||
|
||||
|
||||
((TextView) findViewById(R.id.network_book_title_value)).setText(myBook.Title);
|
||||
setPairValueText(R.id.network_book_title, myBook.Title);
|
||||
|
||||
if (myBook.Authors.size() > 0) {
|
||||
findViewById(R.id.network_book_authors).setVisibility(View.VISIBLE);
|
||||
|
@ -142,22 +161,22 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
}
|
||||
authorsText.append(author.DisplayName);
|
||||
}
|
||||
((TextView) findViewById(R.id.network_book_authors_value)).setText(authorsText);
|
||||
setPairValueText(R.id.network_book_authors, authorsText);
|
||||
} else {
|
||||
findViewById(R.id.network_book_authors).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (myBook.SeriesTitle != null) {
|
||||
findViewById(R.id.network_book_series).setVisibility(View.VISIBLE);
|
||||
((TextView) findViewById(R.id.network_book_series_value)).setText(myBook.SeriesTitle);
|
||||
findViewById(R.id.network_book_series_title).setVisibility(View.VISIBLE);
|
||||
setPairValueText(R.id.network_book_series_title, myBook.SeriesTitle);
|
||||
if (myBook.IndexInSeries > 0) {
|
||||
((TextView) findViewById(R.id.network_book_series_index_value)).setText(String.valueOf(myBook.IndexInSeries));
|
||||
setPairValueText(R.id.network_book_series_index, String.valueOf(myBook.IndexInSeries));
|
||||
findViewById(R.id.network_book_series_index).setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
findViewById(R.id.network_book_series_index).setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
findViewById(R.id.network_book_series).setVisibility(View.GONE);
|
||||
findViewById(R.id.network_book_series_title).setVisibility(View.GONE);
|
||||
findViewById(R.id.network_book_series_index).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
@ -170,15 +189,17 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
}
|
||||
tagsText.append(tag);
|
||||
}
|
||||
((TextView) findViewById(R.id.network_book_tags_value)).setText(tagsText);
|
||||
setPairValueText(R.id.network_book_tags, tagsText);
|
||||
} else {
|
||||
findViewById(R.id.network_book_tags).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setPairValueText(R.id.network_book_catalog, myBook.Link.getTitle());
|
||||
}
|
||||
|
||||
private final void setupCover() {
|
||||
final View rootView = findViewById(R.id.network_book_root);
|
||||
final ImageView coverView = (ImageView) findViewById(R.id.network_book_cover);
|
||||
final ImageView coverView = (ImageView)findViewById(R.id.network_book_cover);
|
||||
|
||||
final DisplayMetrics metrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
|
@ -232,9 +253,11 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
};
|
||||
final Set<NetworkBookActions.Action> actions = NetworkBookActions.getContextMenuActions(myBook, myConnection);
|
||||
|
||||
final boolean skipSecondButton = actions.size() < buttons.length && (actions.size() % 2) == 1;
|
||||
final boolean skipSecondButton =
|
||||
actions.size() < buttons.length &&
|
||||
actions.size() % 2 == 1;
|
||||
int buttonNumber = 0;
|
||||
for (final NetworkBookActions.Action a: actions) {
|
||||
for (final NetworkBookActions.Action a : actions) {
|
||||
if (skipSecondButton && buttonNumber == 1) {
|
||||
++buttonNumber;
|
||||
}
|
||||
|
@ -250,7 +273,7 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
}
|
||||
|
||||
final int buttonId = buttons[buttonNumber++];
|
||||
TextView button = (TextView) findViewById(buttonId);
|
||||
TextView button = (TextView)findViewById(buttonId);
|
||||
button.setText(text);
|
||||
button.setVisibility(View.VISIBLE);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -305,7 +328,7 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return null;
|
||||
}
|
||||
final NetworkDialog dlg = NetworkDialog.getDialog(id);
|
||||
final AuthenticationDialog dlg = AuthenticationDialog.getDialog();
|
||||
if (dlg != null) {
|
||||
return dlg.createDialog(this);
|
||||
}
|
||||
|
@ -316,9 +339,9 @@ public class NetworkBookInfoActivity extends Activity implements NetworkView.Eve
|
|||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
|
||||
final NetworkDialog dlg = NetworkDialog.getDialog(id);
|
||||
final AuthenticationDialog dlg = AuthenticationDialog.getDialog();
|
||||
if (dlg != null) {
|
||||
dlg.prepareDialog(this, dialog);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.os.Handler;
|
|||
import android.view.Menu;
|
||||
import android.view.ContextMenu;
|
||||
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
import org.geometerplus.zlibrary.core.util.ZLBoolean3;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
|
@ -41,11 +40,11 @@ import org.geometerplus.fbreader.network.*;
|
|||
import org.geometerplus.fbreader.network.tree.NetworkTreeFactory;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkCatalogRootTree;
|
||||
import org.geometerplus.fbreader.network.opds.BasketItem;
|
||||
import org.geometerplus.fbreader.network.authentication.*;
|
||||
|
||||
|
||||
class NetworkCatalogActions extends NetworkTreeActions {
|
||||
|
||||
public static final int OPEN_CATALOG_ITEM_ID = 0;
|
||||
public static final int OPEN_IN_BROWSER_ITEM_ID = 1;
|
||||
public static final int RELOAD_ITEM_ID = 2;
|
||||
|
@ -57,6 +56,9 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
public static final int CUSTOM_CATALOG_EDIT = 7;
|
||||
public static final int CUSTOM_CATALOG_REMOVE = 8;
|
||||
|
||||
public static final int BASKET_CLEAR = 9;
|
||||
public static final int BASKET_BUY_ALL_BOOKS = 10;
|
||||
|
||||
@Override
|
||||
public boolean canHandleTree(NetworkTree tree) {
|
||||
return tree instanceof NetworkCatalogTree;
|
||||
|
@ -72,14 +74,15 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public void buildContextMenu(Activity activity, ContextMenu menu, NetworkTree tree) {
|
||||
final NetworkCatalogTree catalogTree = (NetworkCatalogTree) tree;
|
||||
final NetworkCatalogTree catalogTree = (NetworkCatalogTree)tree;
|
||||
final NetworkCatalogItem item = catalogTree.Item;
|
||||
menu.setHeaderTitle(tree.getName());
|
||||
|
||||
boolean hasItems = false;
|
||||
|
||||
final String catalogUrl = item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (catalogUrl != null) {
|
||||
if (catalogUrl != null &&
|
||||
(!(item instanceof BasketItem) || item.Link.basket().bookIds().size() > 0)) {
|
||||
addMenuItem(menu, OPEN_CATALOG_ITEM_ID, "openCatalog");
|
||||
hasItems = true;
|
||||
}
|
||||
|
@ -154,6 +157,10 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
addOptionsItem(menu, SIGNUP_ITEM_ID, "signUp");
|
||||
addOptionsItem(menu, SIGNOUT_ITEM_ID, "signOut", "");
|
||||
addOptionsItem(menu, REFILL_ACCOUNT_ITEM_ID, "refillAccount");
|
||||
if (((NetworkCatalogTree)tree).Item instanceof BasketItem) {
|
||||
addOptionsItem(menu, BASKET_CLEAR, "clearBasket");
|
||||
addOptionsItem(menu, BASKET_BUY_ALL_BOOKS, "buyAllBooks");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -162,11 +169,11 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
final NetworkCatalogTree catalogTree = (NetworkCatalogTree) tree;
|
||||
final NetworkCatalogItem item = catalogTree.Item;
|
||||
|
||||
final String catalogUrl = item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
final boolean isLoading = (catalogUrl != null) ?
|
||||
NetworkView.Instance().containsItemsLoadingRunnable(catalogUrl) : false;
|
||||
final boolean isLoading =
|
||||
NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey());
|
||||
|
||||
prepareOptionsItem(menu, RELOAD_ITEM_ID, catalogUrl != null && !isLoading);
|
||||
prepareOptionsItem(menu, RELOAD_ITEM_ID,
|
||||
item.URLByType.get(NetworkCatalogItem.URL_CATALOG) != null && !isLoading);
|
||||
|
||||
boolean signIn = false;
|
||||
boolean signOut = false;
|
||||
|
@ -202,7 +209,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
case B3_TRUE:
|
||||
return false;
|
||||
case B3_UNDEFINED:
|
||||
NetworkDialog.show(activity, NetworkDialog.DIALOG_AUTHENTICATION, ((NetworkCatalogTree)tree).Item.Link, new Runnable() {
|
||||
AuthenticationDialog.show(activity, ((NetworkCatalogTree)tree).Item.Link, new Runnable() {
|
||||
public void run() {
|
||||
if (catalogTree.Item.getVisibility() != ZLBoolean3.B3_TRUE) {
|
||||
return;
|
||||
|
@ -222,50 +229,56 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
if (consumeByVisibility(activity, tree, actionCode)) {
|
||||
return true;
|
||||
}
|
||||
final NetworkCatalogTree catalogTree = (NetworkCatalogTree)tree;
|
||||
switch (actionCode) {
|
||||
case OPEN_CATALOG_ITEM_ID:
|
||||
doExpandCatalog(activity, (NetworkCatalogTree)tree);
|
||||
return true;
|
||||
case OPEN_IN_BROWSER_ITEM_ID:
|
||||
Util.openInBrowser(
|
||||
activity,
|
||||
((NetworkCatalogTree)tree).Item.URLByType.get(NetworkCatalogItem.URL_HTML_PAGE)
|
||||
);
|
||||
return true;
|
||||
case RELOAD_ITEM_ID:
|
||||
doReloadCatalog(activity, (NetworkCatalogTree)tree);
|
||||
return true;
|
||||
case SIGNIN_ITEM_ID:
|
||||
NetworkDialog.show(activity, NetworkDialog.DIALOG_AUTHENTICATION, ((NetworkCatalogTree)tree).Item.Link, null);
|
||||
return true;
|
||||
case SIGNUP_ITEM_ID:
|
||||
Util.runRegistrationDialog(activity, ((NetworkCatalogTree)tree).Item.Link);
|
||||
return true;
|
||||
case SIGNOUT_ITEM_ID:
|
||||
doSignOut(activity, (NetworkCatalogTree)tree);
|
||||
return true;
|
||||
case REFILL_ACCOUNT_ITEM_ID:
|
||||
new RefillAccountActions().runStandalone(activity, ((RefillAccountTree)activity.getDefaultTree()).Link);
|
||||
return true;
|
||||
case CUSTOM_CATALOG_EDIT:
|
||||
{
|
||||
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())
|
||||
);
|
||||
final NetworkCatalogItem item = catalogTree.Item;
|
||||
if (item instanceof BasketItem && item.Link.basket().bookIds().size() == 0) {
|
||||
UIUtil.showErrorMessage(activity, "emptyBasket");
|
||||
} else {
|
||||
doExpandCatalog(activity, catalogTree);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case OPEN_IN_BROWSER_ITEM_ID:
|
||||
Util.openInBrowser(
|
||||
activity,
|
||||
catalogTree.Item.URLByType.get(NetworkCatalogItem.URL_HTML_PAGE)
|
||||
);
|
||||
return true;
|
||||
case RELOAD_ITEM_ID:
|
||||
doReloadCatalog(activity, catalogTree);
|
||||
return true;
|
||||
case SIGNIN_ITEM_ID:
|
||||
AuthenticationDialog.show(activity, catalogTree.Item.Link, null);
|
||||
return true;
|
||||
case SIGNUP_ITEM_ID:
|
||||
Util.runRegistrationDialog(activity, catalogTree.Item.Link);
|
||||
return true;
|
||||
case SIGNOUT_ITEM_ID:
|
||||
doSignOut(activity, catalogTree);
|
||||
return true;
|
||||
case REFILL_ACCOUNT_ITEM_ID:
|
||||
new RefillAccountActions().runStandalone(activity, catalogTree.Item.Link);
|
||||
return true;
|
||||
case CUSTOM_CATALOG_EDIT:
|
||||
{
|
||||
final Intent intent = new Intent(activity, AddCustomCatalogActivity.class);
|
||||
NetworkLibraryActivity.addLinkToIntent(
|
||||
intent,
|
||||
(ICustomNetworkLink)catalogTree.Item.Link
|
||||
);
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case CUSTOM_CATALOG_REMOVE:
|
||||
removeCustomLink((ICustomNetworkLink)((NetworkCatalogTree)tree).Item.Link);
|
||||
removeCustomLink((ICustomNetworkLink)catalogTree.Item.Link);
|
||||
return true;
|
||||
case BASKET_CLEAR:
|
||||
catalogTree.Item.Link.basket().clear();
|
||||
return true;
|
||||
case BASKET_BUY_ALL_BOOKS:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -273,18 +286,17 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
|
||||
|
||||
private static class ExpandCatalogHandler extends ItemsLoadingHandler {
|
||||
|
||||
private final String myKey;
|
||||
private final NetworkTree.Key myKey;
|
||||
private final NetworkCatalogTree myTree;
|
||||
|
||||
ExpandCatalogHandler(NetworkCatalogTree tree, String key) {
|
||||
ExpandCatalogHandler(NetworkCatalogTree tree, NetworkTree.Key key) {
|
||||
myTree = tree;
|
||||
myKey = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
||||
for (NetworkLibraryItem item: items) {
|
||||
public void onUpdateItems(List<NetworkItem> items) {
|
||||
for (NetworkItem item: items) {
|
||||
myTree.ChildrenItems.add(item);
|
||||
NetworkTreeFactory.createNetworkTree(myTree, item);
|
||||
}
|
||||
|
@ -299,7 +311,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public void onFinish(String errorMessage, boolean interrupted,
|
||||
Set<NetworkLibraryItem> uncommitedItems) {
|
||||
Set<NetworkItem> uncommitedItems) {
|
||||
if (interrupted &&
|
||||
(!myTree.Item.supportsResumeLoading() || errorMessage != null)) {
|
||||
myTree.ChildrenItems.clear();
|
||||
|
@ -320,30 +332,18 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
|
||||
private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) {
|
||||
final ZLResource dialogResource = ZLResource.resource("dialog");
|
||||
ZLResource boxResource = null;
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
final NetworkCatalogActivity activity = NetworkView.Instance().getOpenedActivity(myKey);
|
||||
if (activity == null) {
|
||||
return;
|
||||
}
|
||||
String msg = null;
|
||||
if (errorMessage != null) {
|
||||
boxResource = dialogResource.getResource("networkError");
|
||||
msg = errorMessage;
|
||||
UIUtil.showErrorMessageText(activity, errorMessage);
|
||||
} else if (childrenEmpty) {
|
||||
// TODO: make ListView's empty view instead
|
||||
boxResource = dialogResource.getResource("emptyCatalogBox");
|
||||
msg = boxResource.getResource("message").getValue();
|
||||
}
|
||||
if (msg != null) {
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
final NetworkCatalogActivity activity = NetworkView.Instance().getOpenedActivity(myKey);
|
||||
if (activity != null) {
|
||||
final ZLResource buttonResource = dialogResource.getResource("button");
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(boxResource.getResource("title").getValue())
|
||||
.setMessage(msg)
|
||||
.setIcon(0)
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), null)
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
UIUtil.showErrorMessage(activity, "emptyCatalog");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,12 +401,9 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
}
|
||||
|
||||
public void doExpandCatalog(final NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("That's impossible!!!");
|
||||
}
|
||||
NetworkView.Instance().tryResumeLoading(activity, tree, url, new Runnable() {
|
||||
private void doExpandCatalog(final NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
final NetworkTree.Key key = tree.getUniqueKey();
|
||||
NetworkView.Instance().tryResumeLoading(activity, tree, new Runnable() {
|
||||
public void run() {
|
||||
boolean resumeNotLoad = false;
|
||||
if (tree.hasChildren()) {
|
||||
|
@ -414,7 +411,7 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
if (tree.Item.supportsResumeLoading()) {
|
||||
resumeNotLoad = true;
|
||||
} else {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
NetworkView.Instance().openTree(activity, tree);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -424,15 +421,25 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
}
|
||||
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, url);
|
||||
/* FIXME: if catalog's loading will be very fast
|
||||
* then it is possible that loading message is lost
|
||||
* (see ExpandCatalogHandler.afterUpdateCatalog method).
|
||||
*
|
||||
* For example, this can be fixed via adding method
|
||||
* NetworkView.postCatalogLoadingResult, that will do the following:
|
||||
* 1) If there is activity, then show message
|
||||
* 2) If there is no activity, then save message, and show when activity is created
|
||||
* 3) Remove unused messages (say, by timeout)
|
||||
*/
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, key);
|
||||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
key,
|
||||
new ExpandCatalogRunnable(handler, tree, true, resumeNotLoad)
|
||||
);
|
||||
processExtraData(activity, tree.Item.extraData(), new Runnable() {
|
||||
public void run() {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
NetworkView.Instance().openTree(activity, tree);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -440,20 +447,17 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
|
||||
public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("That's impossible!!!");
|
||||
}
|
||||
if (NetworkView.Instance().containsItemsLoadingRunnable(url)) {
|
||||
final NetworkTree.Key key = tree.getUniqueKey();
|
||||
if (NetworkView.Instance().containsItemsLoadingRunnable(key)) {
|
||||
return;
|
||||
}
|
||||
tree.ChildrenItems.clear();
|
||||
tree.clear();
|
||||
NetworkView.Instance().fireModelChangedAsync();
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, url);
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, key);
|
||||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
key,
|
||||
new ExpandCatalogRunnable(handler, tree, false, false)
|
||||
);
|
||||
}
|
||||
|
@ -484,7 +488,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
private void removeCustomLink(ICustomNetworkLink link) {
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
library.removeCustomLink(link);
|
||||
library.updateChildren();
|
||||
library.synchronize();
|
||||
NetworkView.Instance().fireModelChangedAsync();
|
||||
}
|
||||
|
|
|
@ -28,17 +28,15 @@ import android.content.Intent;
|
|||
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
import org.geometerplus.fbreader.network.NetworkCatalogItem;
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.tree.*;
|
||||
import org.geometerplus.fbreader.tree.FBTree;
|
||||
|
||||
public class NetworkCatalogActivity extends NetworkBaseActivity implements UserRegistrationConstants {
|
||||
public static final String CATALOG_LEVEL_KEY = "org.geometerplus.android.fbreader.network.CatalogLevel";
|
||||
public static final String CATALOG_KEY_KEY = "org.geometerplus.android.fbreader.network.CatalogKey";
|
||||
|
||||
private NetworkTree myTree;
|
||||
private String myCatalogKey;
|
||||
private boolean myInProgress;
|
||||
private volatile boolean myInProgress;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@ -53,27 +51,49 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR
|
|||
}
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final int level = intent.getIntExtra(CATALOG_LEVEL_KEY, -1);
|
||||
if (level == -1) {
|
||||
throw new RuntimeException("Catalog's Level was not specified!!!");
|
||||
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
final NetworkTree.Key key = (NetworkTree.Key)intent.getSerializableExtra(CATALOG_KEY_KEY);
|
||||
myTree = library.getTreeByKey(key);
|
||||
|
||||
if (myTree == null) {
|
||||
throw new RuntimeException("Tree not found for key " + key);
|
||||
}
|
||||
|
||||
myCatalogKey = intent.getStringExtra(CATALOG_KEY_KEY);
|
||||
if (myCatalogKey == null) {
|
||||
throw new RuntimeException("Catalog's Key was not specified!!!");
|
||||
}
|
||||
|
||||
myTree = networkView.getOpenedTree(level);
|
||||
|
||||
networkView.setOpenedActivity(myCatalogKey, this);
|
||||
networkView.setOpenedActivity(key, this);
|
||||
|
||||
setListAdapter(new CatalogAdapter());
|
||||
getListView().invalidateViews();
|
||||
setupTitle();
|
||||
if (myTree instanceof NetworkCatalogTree &&
|
||||
Util.isAccountRefillingSupported(this, ((NetworkCatalogTree)myTree).Item.Link)) {
|
||||
setDefaultTree(new RefillAccountTree((NetworkCatalogTree)myTree));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
if (menuInfo == null && myTree instanceof NetworkCatalogTree) {
|
||||
final INetworkLink link = ((NetworkCatalogTree)myTree).Item.Link;
|
||||
if (Util.isAccountRefillingSupported(this, link)) {
|
||||
final RefillAccountActions actions = NetworkView.Instance().getTopUpActions();
|
||||
if (actions != null) {
|
||||
actions.buildContextMenu(this, menu, link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
if ((item == null || item.getMenuInfo() == null) && myTree instanceof NetworkCatalogTree) {
|
||||
final INetworkLink link = ((NetworkCatalogTree)myTree).Item.Link;
|
||||
if (Util.isAccountRefillingSupported(this, link)) {
|
||||
final RefillAccountActions actions = NetworkView.Instance().getTopUpActions();
|
||||
if (actions != null && actions.runAction(this, link, item.getItemId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,25 +132,10 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR
|
|||
setProgressBarIndeterminateVisibility(myInProgress);
|
||||
}
|
||||
|
||||
private static String getNetworkTreeKey(NetworkTree tree, boolean recursive) {
|
||||
if (tree instanceof NetworkCatalogTree) {
|
||||
return ((NetworkCatalogTree) tree).Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
} else if (tree instanceof SearchItemTree) {
|
||||
return NetworkSearchActivity.SEARCH_RUNNABLE_KEY;
|
||||
} else if (recursive && tree.Parent instanceof NetworkTree) {
|
||||
if (tree instanceof NetworkAuthorTree
|
||||
|| tree instanceof NetworkSeriesTree) {
|
||||
return getNetworkTreeKey((NetworkTree) tree.Parent, true);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (myTree != null && myCatalogKey != null && NetworkView.Instance().isInitialized()) {
|
||||
NetworkView.Instance().setOpenedActivity(myCatalogKey, null);
|
||||
if (myTree != null && NetworkView.Instance().isInitialized()) {
|
||||
NetworkView.Instance().setOpenedActivity(myTree.getUniqueKey(), null);
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
@ -141,44 +146,15 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR
|
|||
}
|
||||
|
||||
private final class CatalogAdapter extends BaseAdapter {
|
||||
|
||||
private ArrayList<NetworkTree> mySpecialItems;
|
||||
|
||||
public CatalogAdapter() {
|
||||
if (myTree instanceof NetworkCatalogRootTree) {
|
||||
final NetworkCatalogRootTree rootTree = (NetworkCatalogRootTree)myTree;
|
||||
mySpecialItems = new ArrayList<NetworkTree>();
|
||||
if (Util.isAccountRefillingSupported(NetworkCatalogActivity.this, rootTree.Item.Link)) {
|
||||
mySpecialItems.add(new RefillAccountTree(rootTree));
|
||||
}
|
||||
if (mySpecialItems.size() > 0) {
|
||||
mySpecialItems.trimToSize();
|
||||
} else {
|
||||
mySpecialItems = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final int getCount() {
|
||||
return myTree.subTrees().size() +
|
||||
((mySpecialItems != null && !myInProgress) ? mySpecialItems.size() : 0);
|
||||
return myTree.subTrees().size();
|
||||
}
|
||||
|
||||
public final NetworkTree getItem(int position) {
|
||||
if (position < 0) {
|
||||
if (position < 0 || position >= myTree.subTrees().size()) {
|
||||
return null;
|
||||
}
|
||||
if (position < myTree.subTrees().size()) {
|
||||
return (NetworkTree) myTree.subTrees().get(position);
|
||||
}
|
||||
if (myInProgress) {
|
||||
return null;
|
||||
}
|
||||
position -= myTree.subTrees().size();
|
||||
if (mySpecialItems != null && position < mySpecialItems.size()) {
|
||||
return mySpecialItems.get(position);
|
||||
}
|
||||
return null;
|
||||
return (NetworkTree)myTree.subTrees().get(position);
|
||||
}
|
||||
|
||||
public final long getItemId(int position) {
|
||||
|
@ -192,18 +168,26 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR
|
|||
|
||||
void onModelChanged() {
|
||||
notifyDataSetChanged();
|
||||
if (mySpecialItems != null) {
|
||||
for (NetworkTree tree: mySpecialItems) {
|
||||
tree.invalidateChildren(); // call to update secondString
|
||||
for (FBTree child : myTree.subTrees()) {
|
||||
if (child instanceof TopUpTree) {
|
||||
child.invalidateChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static NetworkTree.Key getLoadableNetworkTreeKey(NetworkTree tree) {
|
||||
if ((tree instanceof NetworkAuthorTree || tree instanceof NetworkSeriesTree)
|
||||
&& tree.Parent instanceof NetworkTree) {
|
||||
return getLoadableNetworkTreeKey((NetworkTree)tree.Parent);
|
||||
}
|
||||
return tree.getUniqueKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModelChanged() {
|
||||
final NetworkView networkView = NetworkView.Instance();
|
||||
final String key = getNetworkTreeKey(myTree, true);
|
||||
final NetworkTree.Key key = getLoadableNetworkTreeKey(myTree);
|
||||
myInProgress = key != null && networkView.isInitialized() && networkView.containsItemsLoadingRunnable(key);
|
||||
getListView().invalidateViews();
|
||||
|
||||
|
@ -227,9 +211,9 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR
|
|||
}
|
||||
|
||||
private void doStopLoading() {
|
||||
final String key = getNetworkTreeKey(myTree, false);
|
||||
if (key != null && NetworkView.Instance().isInitialized()) {
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(key);
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
final ItemsLoadingRunnable runnable =
|
||||
NetworkView.Instance().getItemsLoadingRunnable(myTree.getUniqueKey());
|
||||
if (runnable != null) {
|
||||
runnable.interruptLoading();
|
||||
}
|
||||
|
|
|
@ -1,184 +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 java.util.TreeMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.View;
|
||||
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkLibrary;
|
||||
|
||||
|
||||
abstract class NetworkDialog {
|
||||
|
||||
// dialog identifiers
|
||||
public static final int DIALOG_AUTHENTICATION = 0;
|
||||
|
||||
private static final TreeMap<Integer, NetworkDialog> ourInstances = new TreeMap<Integer, NetworkDialog>();
|
||||
|
||||
public static NetworkDialog getDialog(int id) {
|
||||
NetworkDialog dlg = ourInstances.get(Integer.valueOf(id));
|
||||
if (dlg == null) {
|
||||
switch (id) {
|
||||
case DIALOG_AUTHENTICATION:
|
||||
dlg = new AuthenticationDialog();
|
||||
break;
|
||||
}
|
||||
if (dlg != null) {
|
||||
dlg.myId = id;
|
||||
ourInstances.put(Integer.valueOf(id), dlg);
|
||||
}
|
||||
}
|
||||
return dlg;
|
||||
}
|
||||
|
||||
|
||||
private class DialogHandler extends Handler {
|
||||
|
||||
public Message obtainMessage(int code, boolean invalidateLibrary, String message) {
|
||||
return obtainMessage(code, invalidateLibrary ? 1 : 0, 0, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
if (message.arg1 != 0) {
|
||||
library.invalidateChildren();
|
||||
}
|
||||
library.invalidateVisibility();
|
||||
library.synchronize();
|
||||
NetworkView.Instance().fireModelChanged();
|
||||
if (message.what < 0) {
|
||||
if (message.what == -2) {
|
||||
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((String) message.obj)
|
||||
.setIcon(0)
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), null)
|
||||
.create().show();
|
||||
} else {
|
||||
myErrorMessage = (String) message.obj;
|
||||
myActivity.showDialog(myId);
|
||||
return;
|
||||
}
|
||||
} else if (message.what > 0) {
|
||||
if (myOnSuccessRunnable != null) {
|
||||
myOnSuccessRunnable.run();
|
||||
}
|
||||
}
|
||||
clearData();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
protected final ZLResource myResource;
|
||||
|
||||
protected int myId;
|
||||
|
||||
protected INetworkLink myLink;
|
||||
protected String myErrorMessage;
|
||||
protected Runnable myOnSuccessRunnable;
|
||||
protected Activity myActivity;
|
||||
|
||||
protected final DialogHandler myHandler = new DialogHandler();
|
||||
|
||||
public NetworkDialog(String key) {
|
||||
myResource = ZLResource.resource("dialog").getResource(key);
|
||||
}
|
||||
|
||||
public static void show(Activity activity, int id, INetworkLink link, Runnable onSuccessRunnable) {
|
||||
getDialog(id).showInternal(activity, link, onSuccessRunnable);
|
||||
}
|
||||
|
||||
private void showInternal(Activity activity, INetworkLink link, Runnable onSuccessRunnable) {
|
||||
myLink = link;
|
||||
myErrorMessage = null;
|
||||
myOnSuccessRunnable = onSuccessRunnable;
|
||||
activity.showDialog(myId);
|
||||
}
|
||||
|
||||
|
||||
protected void sendSuccess(boolean invalidateLibrary) {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(1, invalidateLibrary, null));
|
||||
}
|
||||
|
||||
protected void sendCancel(boolean invalidateLibrary) {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(0, invalidateLibrary, null));
|
||||
}
|
||||
|
||||
protected void sendError(boolean restart, boolean invalidateLibrary, String message) {
|
||||
myHandler.sendMessage(myHandler.obtainMessage(restart ? -1 : -2, invalidateLibrary, message));
|
||||
}
|
||||
|
||||
protected abstract View createLayout();
|
||||
protected abstract void clearData();
|
||||
|
||||
protected abstract void onPositive(DialogInterface dialog);
|
||||
protected abstract void onNegative(DialogInterface dialog);
|
||||
|
||||
public final Dialog createDialog(final Activity activity) {
|
||||
myActivity = activity;
|
||||
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
onPositive(dialog);
|
||||
} else {
|
||||
onNegative(dialog);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final View layout = createLayout();
|
||||
final ZLResource buttonResource = ZLResource.resource("dialog").getResource("button");
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setView(layout)
|
||||
.setTitle(myResource.getResource("title").getValue())
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), listener)
|
||||
.setNegativeButton(buttonResource.getResource("cancel").getValue(), listener)
|
||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
onNegative(dialog);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
public final void prepareDialog(final Activity activity, Dialog dialog) {
|
||||
myActivity = activity;
|
||||
prepareDialogInternal(dialog);
|
||||
}
|
||||
|
||||
protected abstract void prepareDialogInternal(Dialog dialog);
|
||||
}
|
|
@ -39,18 +39,41 @@ import org.geometerplus.zlibrary.ui.android.R;
|
|||
|
||||
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;
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSCustomLink;
|
||||
|
||||
public class NetworkLibraryActivity extends NetworkBaseActivity {
|
||||
final static String ADD_CATALOG = "android.fbreader.action.ADD_CATALOG";
|
||||
static final 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 static final String ADD_CATALOG_TITLE_KEY = "title";
|
||||
private static final String ADD_CATALOG_SUMMARY_KEY = "summary";
|
||||
private static final String ADD_CATALOG_ID_KEY = "id";
|
||||
private static final String ADD_CATALOG_URLS_MAP_KEY = "urls";
|
||||
|
||||
static void addLinkToIntent(Intent intent, ICustomNetworkLink link) {
|
||||
final String textUrl = link.getUrlInfo(INetworkLink.URL_MAIN).URL;
|
||||
intent.setData(Uri.parse(textUrl));
|
||||
intent
|
||||
.putExtra(ADD_CATALOG_TITLE_KEY, link.getTitle())
|
||||
.putExtra(ADD_CATALOG_SUMMARY_KEY, link.getSummary())
|
||||
.putExtra(ADD_CATALOG_ID_KEY, link.getId())
|
||||
.putExtra(ADD_CATALOG_URLS_MAP_KEY, link.urlInfoMap());
|
||||
}
|
||||
|
||||
static ICustomNetworkLink getLinkFromIntent(Intent intent) {
|
||||
final Uri uri = intent.getData();
|
||||
if (uri == null || !intent.hasExtra(ADD_CATALOG_ID_KEY)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new OPDSCustomLink(
|
||||
intent.getIntExtra(ADD_CATALOG_ID_KEY, ICustomNetworkLink.INVALID_ID),
|
||||
uri.getHost(),
|
||||
intent.getStringExtra(ADD_CATALOG_TITLE_KEY),
|
||||
intent.getStringExtra(ADD_CATALOG_SUMMARY_KEY),
|
||||
(HashMap<String,UrlInfo>)intent.getSerializableExtra(ADD_CATALOG_URLS_MAP_KEY)
|
||||
);
|
||||
}
|
||||
|
||||
private NetworkTree myTree;
|
||||
private volatile Intent myIntent;
|
||||
|
@ -73,25 +96,14 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
}
|
||||
|
||||
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 (ADD_CATALOG.equals(intent.getAction())) {
|
||||
final ICustomNetworkLink link = getLinkFromIntent(intent);
|
||||
System.err.println("LINK = " + link);
|
||||
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();
|
||||
|
@ -103,13 +115,13 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
|
||||
private void prepareView() {
|
||||
if (myTree == null) {
|
||||
myTree = NetworkLibrary.Instance().getTree();
|
||||
myTree = NetworkLibrary.Instance().getRootTree();
|
||||
setListAdapter(new LibraryAdapter());
|
||||
getListView().invalidateViews();
|
||||
}
|
||||
}
|
||||
|
||||
private static Initializator myInitializator;
|
||||
private static Initializator myInitializator;
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
|
@ -227,19 +239,11 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
return myTree.subTrees().size() + 2; // subtrees + <search item>
|
||||
return myTree.subTrees().size();
|
||||
}
|
||||
|
||||
public final NetworkTree getItem(int position) {
|
||||
final int size = myTree.subTrees().size();
|
||||
if (position == 0) {
|
||||
return NetworkView.Instance().getSearchItemTree();
|
||||
} else if (position > 0 && position <= size) {
|
||||
return (NetworkTree)myTree.subTrees().get(position - 1);
|
||||
} else if (position == size + 1) {
|
||||
return NetworkView.Instance().getAddCustomCatalogItemTree();
|
||||
}
|
||||
return null;
|
||||
return (NetworkTree)myTree.subTrees().get(position);
|
||||
}
|
||||
|
||||
public final long getItemId(int position) {
|
||||
|
@ -274,11 +278,16 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static boolean searchIsInProgress() {
|
||||
return NetworkView.Instance().containsItemsLoadingRunnable(
|
||||
NetworkLibrary.Instance().getSearchItemTree().getUniqueKey()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
final boolean searchInProgress = NetworkView.Instance().containsItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
menu.findItem(MENU_SEARCH).setEnabled(!searchInProgress);
|
||||
menu.findItem(MENU_SEARCH).setEnabled(!searchIsInProgress());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -316,7 +325,6 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
}
|
||||
}
|
||||
library.setActiveLanguageCodes(newActiveCodes);
|
||||
library.invalidateChildren();
|
||||
library.synchronize();
|
||||
NetworkView.Instance().fireModelChanged();
|
||||
}
|
||||
|
@ -346,7 +354,7 @@ public class NetworkLibraryActivity extends NetworkBaseActivity {
|
|||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
if (NetworkView.Instance().containsItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY)) {
|
||||
if (searchIsInProgress()) {
|
||||
return false;
|
||||
}
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
|
|
|
@ -32,12 +32,10 @@ import org.geometerplus.zlibrary.core.resources.ZLResource;
|
|||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.tree.SearchItemTree;
|
||||
|
||||
|
||||
public class NetworkSearchActivity extends Activity {
|
||||
|
||||
public static final String SEARCH_RUNNABLE_KEY = "org.geometerplus.android.fbreader.network.NetworkSearchActivity";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
@ -57,7 +55,6 @@ public class NetworkSearchActivity extends Activity {
|
|||
}
|
||||
|
||||
private class SearchHandler extends ItemsLoadingHandler {
|
||||
|
||||
private final SearchItemTree myTree;
|
||||
|
||||
public SearchHandler(SearchItemTree tree) {
|
||||
|
@ -65,11 +62,11 @@ public class NetworkSearchActivity extends Activity {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateItems(List<NetworkLibraryItem> items) {
|
||||
public void onUpdateItems(List<NetworkItem> items) {
|
||||
SearchResult result = myTree.getSearchResult();
|
||||
for (NetworkLibraryItem item: items) {
|
||||
for (NetworkItem item: items) {
|
||||
if (item instanceof NetworkBookItem) {
|
||||
result.addBook((NetworkBookItem) item);
|
||||
result.addBook((NetworkBookItem)item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,12 +81,12 @@ public class NetworkSearchActivity extends Activity {
|
|||
|
||||
@Override
|
||||
public void onFinish(String errorMessage, boolean interrupted,
|
||||
Set<NetworkLibraryItem> uncommitedItems) {
|
||||
Set<NetworkItem> uncommitedItems) {
|
||||
if (interrupted) {
|
||||
myTree.setSearchResult(null);
|
||||
} else {
|
||||
myTree.updateSubTrees();
|
||||
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
|
||||
afterUpdateCatalog(errorMessage, myTree.getSearchResult().isEmpty());
|
||||
}
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
NetworkView.Instance().fireModelChangedAsync();
|
||||
|
@ -99,27 +96,36 @@ public class NetworkSearchActivity extends Activity {
|
|||
private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) {
|
||||
final ZLResource dialogResource = ZLResource.resource("dialog");
|
||||
ZLResource boxResource = null;
|
||||
String msg = null;
|
||||
String msg;
|
||||
if (errorMessage != null) {
|
||||
boxResource = dialogResource.getResource("networkError");
|
||||
msg = errorMessage;
|
||||
} else if (childrenEmpty) {
|
||||
boxResource = dialogResource.getResource("emptySearchResults");
|
||||
msg = boxResource.getResource("message").getValue();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (msg != null) {
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
final NetworkCatalogActivity activity = NetworkView.Instance().getOpenedActivity(SEARCH_RUNNABLE_KEY);
|
||||
if (activity != null) {
|
||||
final ZLResource buttonResource = dialogResource.getResource("button");
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(boxResource.getResource("title").getValue())
|
||||
.setMessage(msg)
|
||||
.setIcon(0)
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), null)
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SearchItemTree tree = NetworkLibrary.Instance().getSearchItemTree();
|
||||
if (tree == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final NetworkCatalogActivity activity =
|
||||
NetworkView.Instance().getOpenedActivity(tree.getUniqueKey());
|
||||
if (activity != null) {
|
||||
final ZLResource buttonResource = dialogResource.getResource("button");
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(boxResource.getResource("title").getValue())
|
||||
.setMessage(msg)
|
||||
.setIcon(0)
|
||||
.setPositiveButton(buttonResource.getResource("ok").getValue(), null)
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,24 +154,24 @@ public class NetworkSearchActivity extends Activity {
|
|||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
library.NetworkSearchPatternOption.setValue(pattern);
|
||||
|
||||
if (NetworkView.Instance().containsItemsLoadingRunnable(SEARCH_RUNNABLE_KEY)) {
|
||||
final SearchItemTree tree = library.getSearchItemTree();
|
||||
if (tree == null ||
|
||||
NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String summary = ZLResource.resource("networkView").getResource("searchResults").getValue().replace("%s", pattern);
|
||||
final SearchResult result = new SearchResult(summary);
|
||||
|
||||
final SearchItemTree tree = NetworkView.Instance().getSearchItemTree();
|
||||
|
||||
tree.setSearchResult(result);
|
||||
NetworkView.Instance().fireModelChangedAsync();
|
||||
|
||||
final SearchHandler handler = new SearchHandler(tree);
|
||||
NetworkView.Instance().startItemsLoading(
|
||||
this,
|
||||
SEARCH_RUNNABLE_KEY,
|
||||
tree.getUniqueKey(),
|
||||
new SearchRunnable(handler, pattern)
|
||||
);
|
||||
NetworkView.Instance().openTree(this, tree, SEARCH_RUNNABLE_KEY);
|
||||
NetworkView.Instance().openTree(this, tree);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import android.view.Menu;
|
|||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
|
||||
|
||||
class NetworkView {
|
||||
private static NetworkView ourInstance;
|
||||
|
@ -44,12 +45,13 @@ class NetworkView {
|
|||
return ourInstance;
|
||||
}
|
||||
|
||||
private volatile boolean myInitialized;
|
||||
private final ArrayList<NetworkTreeActions> myActions = new ArrayList<NetworkTreeActions>();
|
||||
private RefillAccountActions myTopUpActions;
|
||||
|
||||
private NetworkView() {
|
||||
}
|
||||
|
||||
|
||||
private volatile boolean myInitialized;
|
||||
|
||||
public boolean isInitialized() {
|
||||
return myInitialized;
|
||||
}
|
||||
|
@ -64,7 +66,8 @@ class NetworkView {
|
|||
myActions.add(new NetworkBookActions());
|
||||
myActions.add(new NetworkCatalogActions());
|
||||
myActions.add(new SearchItemActions());
|
||||
myActions.add(new RefillAccountActions());
|
||||
myTopUpActions = new RefillAccountActions();
|
||||
myActions.add(myTopUpActions);
|
||||
myActions.add(new AddCustomCatalogItemActions());
|
||||
myActions.trimToSize();
|
||||
|
||||
|
@ -85,10 +88,12 @@ class NetworkView {
|
|||
}
|
||||
|
||||
/*
|
||||
* NetworkLibraryItem's actions
|
||||
* NetworkItem's actions
|
||||
*/
|
||||
|
||||
private final ArrayList<NetworkTreeActions> myActions = new ArrayList<NetworkTreeActions>();
|
||||
public RefillAccountActions getTopUpActions() {
|
||||
return myTopUpActions;
|
||||
}
|
||||
|
||||
public NetworkTreeActions getActions(NetworkTree tree) {
|
||||
for (NetworkTreeActions actions: myActions) {
|
||||
|
@ -140,9 +145,10 @@ class NetworkView {
|
|||
* Code for loading network items (running items-loading service and managing items-loading runnables).
|
||||
*/
|
||||
|
||||
private final HashMap<String, ItemsLoadingRunnable> myItemsLoadingRunnables = new HashMap<String, ItemsLoadingRunnable>();
|
||||
private final HashMap<NetworkTree.Key,ItemsLoadingRunnable> myItemsLoadingRunnables =
|
||||
new HashMap<NetworkTree.Key,ItemsLoadingRunnable>();
|
||||
|
||||
public void startItemsLoading(Context context, String key, ItemsLoadingRunnable runnable) {
|
||||
public void startItemsLoading(Context context, NetworkTree.Key key, ItemsLoadingRunnable runnable) {
|
||||
boolean doDownload = false;
|
||||
synchronized (myItemsLoadingRunnables) {
|
||||
if (!myItemsLoadingRunnables.containsKey(key)) {
|
||||
|
@ -158,13 +164,13 @@ class NetworkView {
|
|||
}
|
||||
}
|
||||
|
||||
ItemsLoadingRunnable getItemsLoadingRunnable(String key) {
|
||||
ItemsLoadingRunnable getItemsLoadingRunnable(NetworkTree.Key key) {
|
||||
synchronized (myItemsLoadingRunnables) {
|
||||
return myItemsLoadingRunnables.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
void removeItemsLoadingRunnable(String key) {
|
||||
void removeItemsLoadingRunnable(NetworkTree.Key key) {
|
||||
synchronized (myItemsLoadingRunnables) {
|
||||
ItemsLoadingRunnable runnable = myItemsLoadingRunnables.remove(key);
|
||||
if (runnable != null) {
|
||||
|
@ -173,14 +179,14 @@ class NetworkView {
|
|||
}
|
||||
}
|
||||
|
||||
public final boolean containsItemsLoadingRunnable(String key) {
|
||||
public final boolean containsItemsLoadingRunnable(NetworkTree.Key key) {
|
||||
return getItemsLoadingRunnable(key) != null;
|
||||
}
|
||||
|
||||
public void tryResumeLoading(NetworkBaseActivity activity, NetworkTree tree, String key, Runnable expandRunnable) {
|
||||
final ItemsLoadingRunnable runnable = getItemsLoadingRunnable(key);
|
||||
public void tryResumeLoading(NetworkBaseActivity activity, NetworkCatalogTree tree, Runnable expandRunnable) {
|
||||
final ItemsLoadingRunnable runnable = getItemsLoadingRunnable(tree.getUniqueKey());
|
||||
if (runnable != null && runnable.tryResumeLoading()) {
|
||||
openTree(activity, tree, key);
|
||||
openTree(activity, tree);
|
||||
return;
|
||||
}
|
||||
if (runnable == null) {
|
||||
|
@ -264,30 +270,17 @@ class NetworkView {
|
|||
* Opening Catalogs & managing opened catalogs stack
|
||||
*/
|
||||
|
||||
private final LinkedList<NetworkTree> myOpenedStack = new LinkedList<NetworkTree>();
|
||||
private final HashMap<String, NetworkCatalogActivity> myOpenedActivities = new HashMap<String, NetworkCatalogActivity>();
|
||||
|
||||
public void openTree(Context context, NetworkTree tree, String key) {
|
||||
final int level = tree.Level - 1; // tree.Level == 1 for catalog's root element
|
||||
if (level > myOpenedStack.size()) {
|
||||
throw new RuntimeException("Unable to open catalog with Level greater than the number of opened catalogs.\n"
|
||||
+ "Catalog: " + tree.getName() + "\n"
|
||||
+ "Level: " + level + "\n"
|
||||
+ "Opened catalogs: " + myOpenedStack.size());
|
||||
}
|
||||
while (level < myOpenedStack.size()) {
|
||||
myOpenedStack.removeLast();
|
||||
}
|
||||
myOpenedStack.add(tree);
|
||||
private final HashMap<NetworkTree.Key,NetworkCatalogActivity> myOpenedActivities =
|
||||
new HashMap<NetworkTree.Key,NetworkCatalogActivity>();
|
||||
|
||||
public void openTree(Context context, NetworkTree tree) {
|
||||
context.startActivity(
|
||||
new Intent(context.getApplicationContext(), NetworkCatalogActivity.class)
|
||||
.putExtra(NetworkCatalogActivity.CATALOG_LEVEL_KEY, level)
|
||||
.putExtra(NetworkCatalogActivity.CATALOG_KEY_KEY, key)
|
||||
.putExtra(NetworkCatalogActivity.CATALOG_KEY_KEY, tree.getUniqueKey())
|
||||
);
|
||||
}
|
||||
|
||||
void setOpenedActivity(String key, NetworkCatalogActivity activity) {
|
||||
void setOpenedActivity(NetworkTree.Key key, NetworkCatalogActivity activity) {
|
||||
if (activity == null) {
|
||||
myOpenedActivities.remove(key);
|
||||
} else {
|
||||
|
@ -295,29 +288,7 @@ class NetworkView {
|
|||
}
|
||||
}
|
||||
|
||||
public NetworkCatalogActivity getOpenedActivity(String key) {
|
||||
public NetworkCatalogActivity getOpenedActivity(NetworkTree.Key key) {
|
||||
return myOpenedActivities.get(key);
|
||||
}
|
||||
|
||||
public NetworkTree getOpenedTree(int level) {
|
||||
if (level < 0 || level >= myOpenedStack.size()) {
|
||||
return null;
|
||||
}
|
||||
return myOpenedStack.get(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special view items item
|
||||
*/
|
||||
|
||||
private final SearchItemTree mySearchItem = new SearchItemTree();
|
||||
private final AddCustomCatalogItemTree myAddCustomCatalogItem = new AddCustomCatalogItemTree();
|
||||
|
||||
public SearchItemTree getSearchItemTree() {
|
||||
return mySearchItem;
|
||||
}
|
||||
|
||||
public AddCustomCatalogItemTree getAddCustomCatalogItemTree() {
|
||||
return myAddCustomCatalogItem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ import android.view.ContextMenu;
|
|||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
import org.geometerplus.fbreader.network.tree.TopUpTree;
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
|
||||
class RefillAccountActions extends NetworkTreeActions {
|
||||
public static final int REFILL_VIA_SMS_ITEM_ID = 0;
|
||||
public static final int REFILL_VIA_BROWSER_ITEM_ID = 1;
|
||||
|
@ -36,14 +36,17 @@ class RefillAccountActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public boolean canHandleTree(NetworkTree tree) {
|
||||
return tree instanceof RefillAccountTree;
|
||||
return tree instanceof TopUpTree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildContextMenu(Activity activity, ContextMenu menu, NetworkTree tree) {
|
||||
buildContextMenu(activity, menu, ((TopUpTree)tree).Item.Link);
|
||||
}
|
||||
|
||||
public void buildContextMenu(Activity activity, ContextMenu menu, INetworkLink link) {
|
||||
menu.setHeaderTitle(getTitleValue("refillTitle"));
|
||||
|
||||
final INetworkLink link = ((RefillAccountTree)tree).Link;
|
||||
if (Util.isSmsAccountRefillingSupported(activity, link)) {
|
||||
addMenuItem(menu, REFILL_VIA_SMS_ITEM_ID, "refillViaSms");
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ class RefillAccountActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public int getDefaultActionCode(NetworkBaseActivity activity, NetworkTree tree) {
|
||||
return getDefaultActionCode(activity, ((RefillAccountTree)tree).Link);
|
||||
return getDefaultActionCode(activity, ((TopUpTree)tree).Item.Link);
|
||||
}
|
||||
private int getDefaultActionCode(Activity activity, INetworkLink link) {
|
||||
final boolean sms = Util.isSmsAccountRefillingSupported(activity, link);
|
||||
|
@ -86,9 +89,10 @@ class RefillAccountActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public boolean runAction(NetworkBaseActivity activity, NetworkTree tree, int actionCode) {
|
||||
final INetworkLink link = ((RefillAccountTree)tree).Link;
|
||||
final INetworkLink link = ((TopUpTree)tree).Item.Link;
|
||||
return runAction(activity, link, actionCode);
|
||||
}
|
||||
|
||||
public boolean runAction(Activity activity, INetworkLink link, int actionCode) {
|
||||
Runnable refillRunnable = null;
|
||||
switch (actionCode) {
|
||||
|
@ -131,7 +135,7 @@ class RefillAccountActions extends NetworkTreeActions {
|
|||
if (mgr.mayBeAuthorised(false)) {
|
||||
refiller.run();
|
||||
} else {
|
||||
NetworkDialog.show(activity, NetworkDialog.DIALOG_AUTHENTICATION, link, new Runnable() {
|
||||
AuthenticationDialog.show(activity, link, new Runnable() {
|
||||
public void run() {
|
||||
if (mgr.mayBeAuthorised(false)) {
|
||||
refiller.run();
|
||||
|
|
|
@ -30,6 +30,9 @@ import org.geometerplus.zlibrary.ui.android.library.ZLAndroidApplication;
|
|||
|
||||
import org.geometerplus.fbreader.network.ICustomNetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkDatabase;
|
||||
import org.geometerplus.fbreader.network.UrlInfo;
|
||||
|
||||
import org.geometerplus.android.util.SQLiteUtil;
|
||||
|
||||
class SQLiteNetworkDatabase extends NetworkDatabase {
|
||||
private final SQLiteDatabase myDatabase;
|
||||
|
@ -41,7 +44,7 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
|
||||
private void migrate() {
|
||||
final int version = myDatabase.getVersion();
|
||||
final int currentCodeVersion = 2;
|
||||
final int currentCodeVersion = 3;
|
||||
if (version >= currentCodeVersion) {
|
||||
return;
|
||||
}
|
||||
|
@ -51,6 +54,8 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
createTables();
|
||||
case 1:
|
||||
updateTables1();
|
||||
case 2:
|
||||
updateTables2();
|
||||
}
|
||||
myDatabase.setTransactionSuccessful();
|
||||
myDatabase.endTransaction();
|
||||
|
@ -69,33 +74,30 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
private static void bindString(SQLiteStatement statement, int index, String value) {
|
||||
if (value != null) {
|
||||
statement.bindString(index, value);
|
||||
} else {
|
||||
statement.bindNull(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadCustomLinks(ICustomLinksHandler handler) {
|
||||
final Cursor cursor = myDatabase.rawQuery("SELECT link_id,title,site_name,summary,icon FROM CustomLinks", null);
|
||||
final HashMap<String,String> linksMap = new HashMap<String,String>();
|
||||
final Cursor cursor = myDatabase.rawQuery("SELECT link_id,title,site_name,summary FROM Links", null);
|
||||
final HashMap<String,UrlInfo> linksMap = new HashMap<String,UrlInfo>();
|
||||
while (cursor.moveToNext()) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String title = cursor.getString(1);
|
||||
final String siteName = cursor.getString(2);
|
||||
final String summary = cursor.getString(3);
|
||||
final String icon = cursor.getString(4);
|
||||
|
||||
linksMap.clear();
|
||||
final Cursor linksCursor = myDatabase.rawQuery("SELECT key,url FROM CustomLinkUrls WHERE link_id = " + id, null);
|
||||
final Cursor linksCursor = myDatabase.rawQuery("SELECT key,url,update_time FROM LinkUrls WHERE link_id = " + id, null);
|
||||
while (linksCursor.moveToNext()) {
|
||||
linksMap.put(linksCursor.getString(0), linksCursor.getString(1));
|
||||
linksMap.put(
|
||||
linksCursor.getString(0),
|
||||
new UrlInfo(
|
||||
linksCursor.getString(1),
|
||||
SQLiteUtil.getDate(linksCursor, 2)
|
||||
)
|
||||
);
|
||||
}
|
||||
linksCursor.close();
|
||||
|
||||
handler.handleCustomLinkData(id, siteName, title, summary, icon, linksMap);
|
||||
handler.handleCustomLinkData(id, siteName, title, summary, linksMap);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
@ -113,14 +115,14 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
if (link.getId() == ICustomNetworkLink.INVALID_ID) {
|
||||
if (myInsertCustomLinkStatement == null) {
|
||||
myInsertCustomLinkStatement = myDatabase.compileStatement(
|
||||
"INSERT INTO CustomLinks (title,site_name,summary,icon) VALUES (?,?,?,?)"
|
||||
"INSERT INTO Links (title,site_name,summary) VALUES (?,?,?)"
|
||||
);
|
||||
}
|
||||
statement = myInsertCustomLinkStatement;
|
||||
} else {
|
||||
if (myUpdateCustomLinkStatement == null) {
|
||||
myUpdateCustomLinkStatement = myDatabase.compileStatement(
|
||||
"UPDATE CustomLinks SET title = ?, site_name = ?, summary =?, icon = ? "
|
||||
"UPDATE Links SET title = ?, site_name = ?, summary =? "
|
||||
+ "WHERE link_id = ?"
|
||||
);
|
||||
}
|
||||
|
@ -129,55 +131,61 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
|
||||
statement.bindString(1, link.getTitle());
|
||||
statement.bindString(2, link.getSiteName());
|
||||
bindString(statement, 3, link.getSummary());
|
||||
bindString(statement, 4, link.getIcon());
|
||||
SQLiteUtil.bindString(statement, 3, link.getSummary());
|
||||
|
||||
final long id;
|
||||
final HashMap<String,String> linksMap = new HashMap<String,String>();
|
||||
final HashMap<String,UrlInfo> linksMap = new HashMap<String,UrlInfo>();
|
||||
|
||||
if (statement == myInsertCustomLinkStatement) {
|
||||
id = statement.executeInsert();
|
||||
link.setId((int) id);
|
||||
} else {
|
||||
id = link.getId();
|
||||
statement.bindLong(5, id);
|
||||
statement.bindLong(4, id);
|
||||
statement.execute();
|
||||
|
||||
final Cursor linksCursor = myDatabase.rawQuery("SELECT key,url FROM CustomLinkUrls WHERE link_id = " + link.getId(), null);
|
||||
final Cursor linksCursor = myDatabase.rawQuery("SELECT key,url,update_time FROM LinkUrls WHERE link_id = " + link.getId(), null);
|
||||
while (linksCursor.moveToNext()) {
|
||||
linksMap.put(linksCursor.getString(0), linksCursor.getString(1));
|
||||
linksMap.put(
|
||||
linksCursor.getString(0),
|
||||
new UrlInfo(
|
||||
linksCursor.getString(1),
|
||||
SQLiteUtil.getDate(linksCursor, 2)
|
||||
)
|
||||
);
|
||||
}
|
||||
linksCursor.close();
|
||||
}
|
||||
|
||||
for (String key: link.getLinkKeys()) {
|
||||
final String value = link.getLink(key);
|
||||
final String dbValue = linksMap.remove(key);
|
||||
for (String key : link.getUrlKeys()) {
|
||||
final UrlInfo info = link.getUrlInfo(key);
|
||||
final UrlInfo dbInfo = linksMap.remove(key);
|
||||
final SQLiteStatement urlStatement;
|
||||
if (dbValue == null) {
|
||||
if (dbInfo == null) {
|
||||
if (myInsertCustomLinkUrlStatement == null) {
|
||||
myInsertCustomLinkUrlStatement = myDatabase.compileStatement(
|
||||
"INSERT OR REPLACE INTO CustomLinkUrls(url,link_id,key) VALUES (?,?,?)");
|
||||
"INSERT OR REPLACE INTO LinkUrls(url,update_time,link_id,key) VALUES (?,?,?,?)");
|
||||
}
|
||||
urlStatement = myInsertCustomLinkUrlStatement;
|
||||
} else if (!value.equals(dbValue)) {
|
||||
} else if (!info.equals(dbInfo)) {
|
||||
if (myUpdateCustomLinkUrlStatement == null) {
|
||||
myUpdateCustomLinkUrlStatement = myDatabase.compileStatement(
|
||||
"UPDATE CustomLinkUrls SET url = ? WHERE link_id = ? AND key = ?");
|
||||
"UPDATE LinkUrls SET url = ?, update_time = ? WHERE link_id = ? AND key = ?");
|
||||
}
|
||||
urlStatement = myUpdateCustomLinkUrlStatement;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
urlStatement.bindString(1, value);
|
||||
urlStatement.bindLong(2, id);
|
||||
urlStatement.bindString(3, key);
|
||||
SQLiteUtil.bindString(urlStatement, 1, info.URL);
|
||||
SQLiteUtil.bindDate(urlStatement, 2, info.Updated);
|
||||
urlStatement.bindLong(3, id);
|
||||
urlStatement.bindString(4, key);
|
||||
urlStatement.execute();
|
||||
}
|
||||
for (String key: linksMap.keySet()) {
|
||||
if (myDeleteCustomLinkUrlStatement == null) {
|
||||
myDeleteCustomLinkUrlStatement = myDatabase.compileStatement(
|
||||
"DELETE FROM CustomLinkUrls WHERE link_id = ? AND key = ?");
|
||||
"DELETE FROM LinkUrls WHERE link_id = ? AND key = ?");
|
||||
}
|
||||
myDeleteCustomLinkUrlStatement.bindLong(1, id);
|
||||
myDeleteCustomLinkUrlStatement.bindString(2, key);
|
||||
|
@ -199,14 +207,14 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
final long id = link.getId();
|
||||
if (myDeleteAllCustomLinksStatement == null) {
|
||||
myDeleteAllCustomLinksStatement = myDatabase.compileStatement(
|
||||
"DELETE FROM CustomLinkUrls WHERE link_id = ?");
|
||||
"DELETE FROM LinkUrls WHERE link_id = ?");
|
||||
}
|
||||
myDeleteAllCustomLinksStatement.bindLong(1, id);
|
||||
myDeleteAllCustomLinksStatement.execute();
|
||||
|
||||
if (myDeleteCustomLinkStatement == null) {
|
||||
myDeleteCustomLinkStatement = myDatabase.compileStatement(
|
||||
"DELETE FROM CustomLinks WHERE link_id = ?"
|
||||
"DELETE FROM Links WHERE link_id = ?"
|
||||
);
|
||||
}
|
||||
myDeleteCustomLinkStatement.bindLong(1, id);
|
||||
|
@ -244,5 +252,34 @@ class SQLiteNetworkDatabase extends NetworkDatabase {
|
|||
"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");
|
||||
|
||||
myDatabase.execSQL(
|
||||
"CREATE TABLE LinkUrls(" +
|
||||
"key TEXT NOT NULL," +
|
||||
"link_id INTEGER NOT NULL REFERENCES CustomLinks(link_id)," +
|
||||
"url TEXT," +
|
||||
"update_time INTEGER," +
|
||||
"CONSTRAINT LinkUrls_PK PRIMARY KEY (key, link_id))");
|
||||
myDatabase.execSQL("INSERT INTO LinkUrls (key,link_id,url) SELECT key,link_id,url FROM CustomLinkUrls");
|
||||
myDatabase.execSQL("DROP TABLE CustomLinkUrls");
|
||||
}
|
||||
|
||||
private void updateTables2() {
|
||||
myDatabase.execSQL(
|
||||
"CREATE TABLE Links(" +
|
||||
"link_id INTEGER PRIMARY KEY," +
|
||||
"title TEXT NOT NULL," +
|
||||
"site_name TEXT NOT NULL," +
|
||||
"summary TEXT)");
|
||||
myDatabase.execSQL("INSERT INTO Links (link_id,title,site_name,summary) SELECT link_id,title,site_name,summary FROM CustomLinks");
|
||||
final Cursor cursor = myDatabase.rawQuery("SELECT link_id,icon FROM CustomLinks", null);
|
||||
while (cursor.moveToNext()) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String url = cursor.getString(1);
|
||||
myDatabase.execSQL("INSERT INTO LinkUrls (key,link_id,url) VALUES " +
|
||||
"('icon'," + id + ",'" + url + "')");
|
||||
}
|
||||
cursor.close();
|
||||
myDatabase.execSQL("DROP TABLE CustomLinks");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import android.view.ContextMenu;
|
|||
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
import org.geometerplus.fbreader.network.SearchResult;
|
||||
|
||||
import org.geometerplus.fbreader.network.tree.SearchItemTree;
|
||||
|
||||
class SearchItemActions extends NetworkTreeActions {
|
||||
|
||||
|
@ -39,7 +39,7 @@ class SearchItemActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public String getTreeTitle(NetworkTree tree) {
|
||||
final SearchResult result = ((SearchItemTree) tree).getSearchResult();
|
||||
final SearchResult result = ((SearchItemTree)tree).getSearchResult();
|
||||
if (result != null) {
|
||||
return result.Summary;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class SearchItemActions extends NetworkTreeActions {
|
|||
public void buildContextMenu(Activity activity, ContextMenu menu, NetworkTree tree) {
|
||||
menu.setHeaderTitle(tree.getName());
|
||||
|
||||
final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey());
|
||||
|
||||
if (!isLoading) {
|
||||
addMenuItem(menu, RUN_SEARCH_ITEM_ID, "search");
|
||||
|
@ -61,7 +61,7 @@ class SearchItemActions extends NetworkTreeActions {
|
|||
|
||||
@Override
|
||||
public int getDefaultActionCode(NetworkBaseActivity activity, NetworkTree tree) {
|
||||
final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey());
|
||||
if (!isLoading) {
|
||||
return RUN_SEARCH_ITEM_ID;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ abstract class Util implements UserRegistrationConstants {
|
|||
return testService(
|
||||
activity,
|
||||
REGISTRATION_ACTION,
|
||||
link.getLink(INetworkLink.URL_SIGN_UP)
|
||||
link.getUrlInfo(INetworkLink.URL_SIGN_UP).URL
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -57,12 +57,12 @@ abstract class Util implements UserRegistrationConstants {
|
|||
try {
|
||||
final Intent intent = new Intent(
|
||||
REGISTRATION_ACTION,
|
||||
Uri.parse(link.getLink(INetworkLink.URL_SIGN_UP))
|
||||
Uri.parse(link.getUrlInfo(INetworkLink.URL_SIGN_UP).URL)
|
||||
);
|
||||
if (PackageUtil.canBeStarted(activity, intent)) {
|
||||
activity.startActivityForResult(new Intent(
|
||||
REGISTRATION_ACTION,
|
||||
Uri.parse(link.getLink(INetworkLink.URL_SIGN_UP))
|
||||
Uri.parse(link.getUrlInfo(INetworkLink.URL_SIGN_UP).URL)
|
||||
), USER_REGISTRATION_REQUEST_CODE);
|
||||
}
|
||||
} catch (ActivityNotFoundException e) {
|
||||
|
@ -93,7 +93,7 @@ abstract class Util implements UserRegistrationConstants {
|
|||
return testService(
|
||||
activity,
|
||||
SMS_REFILLING_ACTION,
|
||||
link.getLink(INetworkLink.URL_MAIN)
|
||||
link.getUrlInfo(INetworkLink.URL_MAIN).URL
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ abstract class Util implements UserRegistrationConstants {
|
|||
try {
|
||||
final Intent intent = new Intent(
|
||||
SMS_REFILLING_ACTION,
|
||||
Uri.parse(link.getLink(INetworkLink.URL_MAIN))
|
||||
Uri.parse(link.getUrlInfo(INetworkLink.URL_MAIN).URL)
|
||||
);
|
||||
final NetworkAuthenticationManager mgr = link.authenticationManager();
|
||||
if (mgr != null) {
|
||||
|
@ -117,7 +117,7 @@ abstract class Util implements UserRegistrationConstants {
|
|||
}
|
||||
|
||||
static boolean isBrowserAccountRefillingSupported(Activity activity, INetworkLink link) {
|
||||
return link.getLink(INetworkLink.URL_REFILL_ACCOUNT) != null;
|
||||
return link.getUrlInfo(INetworkLink.URL_REFILL_ACCOUNT).URL != null;
|
||||
}
|
||||
|
||||
static void openInBrowser(Context context, String url) {
|
||||
|
|
50
src/org/geometerplus/android/util/SQLiteUtil.java
Normal file
50
src/org/geometerplus/android/util/SQLiteUtil.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2009-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.util;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.database.Cursor;
|
||||
|
||||
public abstract class SQLiteUtil {
|
||||
public static void bindString(SQLiteStatement statement, int index, String value) {
|
||||
if (value != null) {
|
||||
statement.bindString(index, value);
|
||||
} else {
|
||||
statement.bindNull(index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindDate(SQLiteStatement statement, int index, Date value) {
|
||||
if (value != null) {
|
||||
statement.bindLong(index, value.getTime());
|
||||
} else {
|
||||
statement.bindNull(index);
|
||||
}
|
||||
}
|
||||
|
||||
public static Date getDate(Cursor cursor, int index) {
|
||||
if (cursor.isNull(index)) {
|
||||
return null;
|
||||
}
|
||||
return new Date(cursor.getLong(index));
|
||||
}
|
||||
}
|
|
@ -110,19 +110,21 @@ public abstract class UIUtil {
|
|||
runner.start();
|
||||
}
|
||||
|
||||
public static void showErrorMessageText(Context context, String text) {
|
||||
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static void showErrorMessage(Context context, String resourceKey) {
|
||||
Toast.makeText(
|
||||
showErrorMessageText(
|
||||
context,
|
||||
ZLResource.resource("errorMessage").getResource(resourceKey).getValue(),
|
||||
Toast.LENGTH_SHORT
|
||||
).show();
|
||||
ZLResource.resource("errorMessage").getResource(resourceKey).getValue()
|
||||
);
|
||||
}
|
||||
|
||||
public static void showErrorMessage(Context context, String resourceKey, String parameter) {
|
||||
Toast.makeText(
|
||||
showErrorMessageText(
|
||||
context,
|
||||
ZLResource.resource("errorMessage").getResource(resourceKey).getValue().replace("%s", parameter),
|
||||
Toast.LENGTH_SHORT
|
||||
).show();
|
||||
ZLResource.resource("errorMessage").getResource(resourceKey).getValue().replace("%s", parameter)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class OEBAnnotationReader extends ZLXMLReaderAdapter implements XMLNamespaces {
|
|||
private static final int READ_DESCRIPTION = 1;
|
||||
private int myReadState;
|
||||
|
||||
private final StringBuffer myBuffer = new StringBuffer();
|
||||
private final StringBuilder myBuffer = new StringBuilder();
|
||||
|
||||
String readAnnotation(ZLFile file) {
|
||||
myReadState = READ_NONE;
|
||||
|
|
|
@ -83,7 +83,7 @@ class OEBMetaInfoReader extends ZLXMLReaderAdapter implements XMLNamespaces {
|
|||
private int myReadState;
|
||||
private boolean myReadMetaData;
|
||||
|
||||
private final StringBuffer myBuffer = new StringBuffer();
|
||||
private final StringBuilder myBuffer = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public boolean processNamespaces() {
|
||||
|
|
|
@ -19,19 +19,19 @@
|
|||
|
||||
package org.geometerplus.fbreader.network;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
|
||||
import org.geometerplus.zlibrary.core.util.ZLMiscUtil;
|
||||
import org.geometerplus.zlibrary.core.options.ZLStringListOption;
|
||||
|
||||
public abstract class AbstractNetworkLink implements INetworkLink {
|
||||
public abstract class AbstractNetworkLink implements INetworkLink, Basket {
|
||||
protected String mySiteName;
|
||||
protected String myTitle;
|
||||
protected String mySummary;
|
||||
protected String myIcon;
|
||||
protected final String myLanguage;
|
||||
protected final TreeMap<String, String> myLinks;
|
||||
protected final TreeMap<String,UrlInfo> myInfos;
|
||||
|
||||
private ZLStringListOption myBooksInBasketOption;
|
||||
|
||||
/**
|
||||
* Creates new NetworkLink instance.
|
||||
|
@ -39,65 +39,114 @@ public abstract class AbstractNetworkLink implements INetworkLink {
|
|||
* @param siteName name of the corresponding website. Must be not <code>null</code>.
|
||||
* @param title title of the corresponding library item. Must be not <code>null</code>.
|
||||
* @param summary description of the corresponding library item. Can be <code>null</code>.
|
||||
* @param icon string contains link's icon data/url. Can be <code>null</code>.
|
||||
* @param language language of the catalog. If <code>null</code> we assume this catalog is multilanguage.
|
||||
* @param links map contains URLs with their identifiers; must always contain one URL with <code>URL_MAIN</code> identifier
|
||||
* @param infos map contains URL infos with their identifiers; must always contain one URL with <code>URL_MAIN</code> identifier
|
||||
*/
|
||||
public AbstractNetworkLink(String siteName, String title, String summary, String icon, String language, Map<String, String> links) {
|
||||
public AbstractNetworkLink(String siteName, String title, String summary, String language, Map<String,UrlInfo> infos) {
|
||||
mySiteName = siteName;
|
||||
myTitle = title;
|
||||
mySummary = summary;
|
||||
myIcon = icon;
|
||||
myLanguage = language != null ? language : "multi";
|
||||
myLinks = new TreeMap<String, String>(links);
|
||||
myInfos = new TreeMap<String,UrlInfo>(infos);
|
||||
}
|
||||
|
||||
public String getSiteName() {
|
||||
public final String getSiteName() {
|
||||
return mySiteName;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
public final String getTitle() {
|
||||
return myTitle;
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
public final String getSummary() {
|
||||
return mySummary;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return myIcon;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
public final String getLanguage() {
|
||||
return myLanguage;
|
||||
}
|
||||
|
||||
public String getLink(String urlKey) {
|
||||
return myLinks.get(urlKey);
|
||||
public final HashMap<String,UrlInfo> urlInfoMap() {
|
||||
return new HashMap(myInfos);
|
||||
}
|
||||
|
||||
public Set<String> getLinkKeys() {
|
||||
return myLinks.keySet();
|
||||
public final UrlInfo getUrlInfo(String urlKey) {
|
||||
final UrlInfo info = myInfos.get(urlKey);
|
||||
return info != null ? info : UrlInfo.NULL;
|
||||
}
|
||||
|
||||
public NetworkOperationData createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener) {
|
||||
return new NetworkOperationData(link, listener);
|
||||
public final Set<String> getUrlKeys() {
|
||||
return myInfos.keySet();
|
||||
}
|
||||
|
||||
public final void setSupportsBasket() {
|
||||
if (myBooksInBasketOption == null) {
|
||||
myBooksInBasketOption = new ZLStringListOption(mySiteName, "Basket", null);
|
||||
}
|
||||
}
|
||||
|
||||
public final Basket basket() {
|
||||
return myBooksInBasketOption != null ? this : null;
|
||||
}
|
||||
|
||||
// method from Basket interface
|
||||
public final void add(NetworkBookItem book) {
|
||||
if (book.Id != null && !"".equals(book.Id)) {
|
||||
List<String> ids = myBooksInBasketOption.getValue();
|
||||
if (!ids.contains(book.Id)) {
|
||||
ids = new ArrayList(ids);
|
||||
ids.add(book.Id);
|
||||
myBooksInBasketOption.setValue(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// method from Basket interface
|
||||
public final void remove(NetworkBookItem book) {
|
||||
if (book.Id != null && !"".equals(book.Id)) {
|
||||
List<String> ids = myBooksInBasketOption.getValue();
|
||||
if (ids.contains(book.Id)) {
|
||||
ids = new ArrayList(ids);
|
||||
ids.remove(book.Id);
|
||||
myBooksInBasketOption.setValue(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// method from Basket interface
|
||||
public final void clear() {
|
||||
myBooksInBasketOption.setValue(null);
|
||||
}
|
||||
|
||||
// method from Basket interface
|
||||
public final boolean contains(NetworkBookItem book) {
|
||||
return myBooksInBasketOption.getValue().contains(book.Id);
|
||||
}
|
||||
|
||||
// method from Basket interface
|
||||
public final List<String> bookIds() {
|
||||
return myBooksInBasketOption.getValue();
|
||||
}
|
||||
|
||||
public NetworkOperationData createOperationData(NetworkOperationData.OnNewItemListener listener) {
|
||||
return new NetworkOperationData(this, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String icon = myIcon;
|
||||
if (icon.length() > 64) {
|
||||
icon = icon.substring(0, 61) + "...";
|
||||
String icon = getUrlInfo(URL_ICON).URL;
|
||||
if (icon != null) {
|
||||
if (icon.length() > 64) {
|
||||
icon = icon.substring(0, 61) + "...";
|
||||
}
|
||||
icon = icon.replaceAll("\n", "");
|
||||
}
|
||||
icon = icon.replaceAll("\n", "");
|
||||
return "AbstractNetworkLink: {"
|
||||
+ "siteName=" + mySiteName
|
||||
+ "; title=" + myTitle
|
||||
+ "; summary=" + mySummary
|
||||
+ "; icon=" + icon
|
||||
+ "; links=" + myLinks
|
||||
+ "; infos=" + myInfos
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
@ -114,8 +163,7 @@ public abstract class AbstractNetworkLink implements INetworkLink {
|
|||
if (!mySiteName.equals(lnk.mySiteName)
|
||||
|| !myTitle.equals(lnk.myTitle)
|
||||
|| !ZLMiscUtil.equals(mySummary, lnk.mySummary)
|
||||
|| !ZLMiscUtil.equals(myIcon, lnk.myIcon)
|
||||
|| !ZLMiscUtil.mapsEquals(myLinks, lnk.myLinks)) {
|
||||
|| !ZLMiscUtil.mapsEquals(myInfos, lnk.myInfos)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
30
src/org/geometerplus/fbreader/network/Basket.java
Normal file
30
src/org/geometerplus/fbreader/network/Basket.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.fbreader.network;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public interface Basket {
|
||||
void add(NetworkBookItem book);
|
||||
void remove(NetworkBookItem book);
|
||||
boolean contains(NetworkBookItem book);
|
||||
List<String> bookIds();
|
||||
void clear();
|
||||
}
|
|
@ -21,6 +21,8 @@ package org.geometerplus.fbreader.network;
|
|||
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface ICustomNetworkLink extends INetworkLink {
|
||||
public static final int INVALID_ID = -1;
|
||||
|
||||
|
@ -30,12 +32,13 @@ public interface ICustomNetworkLink extends INetworkLink {
|
|||
void setSiteName(String name);
|
||||
void setTitle(String title);
|
||||
void setSummary(String summary);
|
||||
void setIcon(String icon);
|
||||
|
||||
void setLink(String urlKey, String url);
|
||||
void removeLink(String urlKey);
|
||||
HashMap<String,UrlInfo> urlInfoMap();
|
||||
void setUrl(String urlKey, String url);
|
||||
void removeUrl(String urlKey);
|
||||
|
||||
void reloadInfo() throws ZLNetworkException;
|
||||
boolean isObsolete(long milliSeconds);
|
||||
void reloadInfo(boolean urlsOnly) throws ZLNetworkException;
|
||||
|
||||
// returns true if next methods have changed link's data:
|
||||
// setSiteName, setTitle, setSummary, setIcon, setLink, removeLink
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
package org.geometerplus.fbreader.network;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
||||
|
||||
|
@ -27,9 +27,9 @@ import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationMan
|
|||
|
||||
|
||||
public interface INetworkLink {
|
||||
|
||||
String URL_MAIN = "main";
|
||||
String URL_SEARCH = "search";
|
||||
String URL_ICON = "icon";
|
||||
String URL_SIGN_IN = "signIn";
|
||||
String URL_SIGN_OUT = "signOut";
|
||||
String URL_SIGN_UP = "signUp";
|
||||
|
@ -39,14 +39,20 @@ public interface INetworkLink {
|
|||
String getSiteName();
|
||||
String getTitle();
|
||||
String getSummary();
|
||||
String getIcon();
|
||||
String getLink(String urlKey);
|
||||
|
||||
UrlInfo getUrlInfo(String urlKey);
|
||||
Set<String> getUrlKeys();
|
||||
|
||||
/**
|
||||
* @return 2-letters language code or special token "multi"
|
||||
*/
|
||||
String getLanguage();
|
||||
|
||||
Set<String> getLinkKeys();
|
||||
|
||||
NetworkOperationData createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener);
|
||||
/**
|
||||
* @param listener Network operation listener
|
||||
* @return instance, which represents the state of the network operation.
|
||||
*/
|
||||
NetworkOperationData createOperationData(NetworkOperationData.OnNewItemListener listener);
|
||||
|
||||
ZLNetworkRequest simpleSearchRequest(String pattern, NetworkOperationData data);
|
||||
ZLNetworkRequest resume(NetworkOperationData data);
|
||||
|
@ -54,5 +60,7 @@ public interface INetworkLink {
|
|||
NetworkCatalogItem libraryItem();
|
||||
NetworkAuthenticationManager authenticationManager();
|
||||
|
||||
Basket basket();
|
||||
|
||||
String rewriteUrl(String url, boolean isUrlExternal);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.io.File;
|
|||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
|
||||
public final class NetworkBookItem extends NetworkLibraryItem {
|
||||
public final class NetworkBookItem extends NetworkItem {
|
||||
|
||||
public static class AuthorData implements Comparable<AuthorData> {
|
||||
public final String DisplayName;
|
||||
|
@ -59,7 +59,7 @@ public final class NetworkBookItem extends NetworkLibraryItem {
|
|||
return false;
|
||||
}
|
||||
final AuthorData data = (AuthorData) o;
|
||||
return SortKey == data.SortKey && DisplayName == data.DisplayName;
|
||||
return SortKey.equals(data.SortKey) && DisplayName.equals(data.DisplayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,7 +80,7 @@ public final class NetworkBookItem extends NetworkLibraryItem {
|
|||
private final LinkedList<BookReference> myReferences;
|
||||
|
||||
/**
|
||||
* Creates new NetworkLibraryItem instance.
|
||||
* Creates new NetworkItem instance.
|
||||
*
|
||||
* @param link corresponding NetworkLink object. Must be not <code>null</code>.
|
||||
* @param id string that uniquely identifies this book item. Must be not <code>null</code>.
|
||||
|
|
|
@ -22,10 +22,8 @@ package org.geometerplus.fbreader.network;
|
|||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
|
||||
public final class NetworkBookItemComparator implements Comparator<NetworkLibraryItem> {
|
||||
|
||||
public int compare(NetworkLibraryItem item0, NetworkLibraryItem item1) {
|
||||
public final class NetworkBookItemComparator implements Comparator<NetworkItem> {
|
||||
public int compare(NetworkItem item0, NetworkItem item1) {
|
||||
final boolean item0isABook = item0 instanceof NetworkBookItem;
|
||||
final boolean item1isABook = item1 instanceof NetworkBookItem;
|
||||
|
||||
|
|
|
@ -23,10 +23,12 @@ import java.util.*;
|
|||
|
||||
import org.geometerplus.zlibrary.core.util.ZLBoolean3;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkManager;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
||||
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
public abstract class NetworkCatalogItem extends NetworkLibraryItem {
|
||||
public abstract class NetworkCatalogItem extends NetworkItem {
|
||||
|
||||
// catalog types:
|
||||
public static enum CatalogType {
|
||||
|
@ -65,21 +67,6 @@ public abstract class NetworkCatalogItem extends NetworkLibraryItem {
|
|||
this(link, title, summary, cover, urlByType, Accessibility.ALWAYS, CatalogType.OTHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new NetworkCatalogItem instance with specified accessibility and <code>CatalogType.OTHER</code> type.
|
||||
*
|
||||
* @param link corresponding NetworkLink object. Must be not <code>null</code>.
|
||||
* @param title title of this library item. Must be not <code>null</code>.
|
||||
* @param summary description of this library item. Can be <code>null</code>.
|
||||
* @param cover cover url. Can be <code>null</code>.
|
||||
* @param urlByType map contains URLs and their types. Must be not <code>null</code>.
|
||||
* @param accessibility value defines when this library item will be accessible
|
||||
* in the network library view.
|
||||
*/
|
||||
public NetworkCatalogItem(INetworkLink link, String title, String summary, String cover, Map<Integer, String> urlByType, Accessibility accessibility) {
|
||||
this(link, title, summary, cover, urlByType, accessibility, CatalogType.OTHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new NetworkCatalogItem instance with specified accessibility and type.
|
||||
*
|
||||
|
@ -144,11 +131,44 @@ public abstract class NetworkCatalogItem extends NetworkLibraryItem {
|
|||
return ZLBoolean3.B3_UNDEFINED;
|
||||
}
|
||||
case HAS_BOOKS:
|
||||
if (mgr != null && mgr.purchasedBooks().size() > 0) {
|
||||
if ((Link.basket() != null && Link.basket().bookIds().size() > 0) ||
|
||||
(mgr != null && mgr.purchasedBooks().size() > 0)) {
|
||||
return ZLBoolean3.B3_TRUE;
|
||||
} else {
|
||||
return ZLBoolean3.B3_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs all necessary operations with NetworkOperationData and NetworkRequest
|
||||
* to complete loading children items.
|
||||
*
|
||||
* @param data Network operation data instance
|
||||
* @param networkRequest initial network request
|
||||
*
|
||||
* @throws ZLNetworkException when network operation couldn't be completed
|
||||
*/
|
||||
protected final void doLoadChildren(NetworkOperationData data,
|
||||
ZLNetworkRequest networkRequest) throws ZLNetworkException {
|
||||
while (networkRequest != null) {
|
||||
ZLNetworkManager.Instance().perform(networkRequest);
|
||||
if (data.Listener.confirmInterrupt()) {
|
||||
return;
|
||||
}
|
||||
networkRequest = data.resume();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method if result of the request depends not only from URL
|
||||
* (e.g. result of the POST request depends from the URL and the body of the request).
|
||||
*
|
||||
* @return unique String for corresponding network request, for which:
|
||||
* {@code item1.getFullRequestString().equals(item2.getFullRequestString())}
|
||||
* iff network requests for items {@code item1} and {@code item2} are the same.
|
||||
*/
|
||||
public String getFullRequestString() {
|
||||
return URLByType.get(URL_CATALOG);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public abstract class NetworkDatabase {
|
|||
protected abstract void executeAsATransaction(Runnable actions);
|
||||
|
||||
public interface ICustomLinksHandler {
|
||||
void handleCustomLinkData(int id, String siteName, String title, String summary, String icon, Map<String, String> links);
|
||||
void handleCustomLinkData(int id, String siteName, String title, String summary, Map<String,UrlInfo> infos);
|
||||
}
|
||||
|
||||
protected abstract void loadCustomLinks(ICustomLinksHandler handler);
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
package org.geometerplus.fbreader.network;
|
||||
|
||||
public abstract class NetworkLibraryItem {
|
||||
|
||||
public abstract class NetworkItem {
|
||||
public final INetworkLink Link;
|
||||
public final String Title;
|
||||
public final String Summary;
|
||||
|
@ -29,14 +28,14 @@ public abstract class NetworkLibraryItem {
|
|||
//public org.geometerplus.fbreader.network.atom.ATOMEntry dbgEntry;
|
||||
|
||||
/**
|
||||
* Creates new NetworkLibraryItem instance.
|
||||
* Creates new NetworkItem instance.
|
||||
*
|
||||
* @param link corresponding NetworkLink object. Must be not <code>null</code>.
|
||||
* @param title title of this library item. Must be not <code>null</code>.
|
||||
* @param summary description of this library item. Can be <code>null</code>.
|
||||
* @param cover cover url. Can be <code>null</code>.
|
||||
*/
|
||||
protected NetworkLibraryItem(INetworkLink link, String title, String summary, String cover) {
|
||||
protected NetworkItem(INetworkLink link, String title, String summary, String cover) {
|
||||
Link = link;
|
||||
Title = title;
|
||||
Summary = summary;
|
|
@ -31,9 +31,9 @@ import org.geometerplus.zlibrary.core.language.ZLLanguageUtil;
|
|||
|
||||
import org.geometerplus.fbreader.tree.FBTree;
|
||||
import org.geometerplus.fbreader.network.tree.*;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSCustomLink;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSLinkReader;
|
||||
|
||||
|
||||
public class NetworkLibrary {
|
||||
private static NetworkLibrary ourInstance;
|
||||
|
||||
|
@ -119,6 +119,7 @@ public class NetworkLibrary {
|
|||
allCodes.removeAll(languageCodes());
|
||||
allCodes.addAll(codes);
|
||||
activeLanguageCodesOption().setValue(commaSeparatedString(allCodes));
|
||||
invalidateChildren();
|
||||
}
|
||||
|
||||
private String commaSeparatedString(Collection<String> codes) {
|
||||
|
@ -148,9 +149,9 @@ public class NetworkLibrary {
|
|||
}
|
||||
|
||||
private final RootTree myRootTree = new RootTree();
|
||||
private SearchItemTree mySearchItemTree;
|
||||
|
||||
private boolean myUpdateChildren = true;
|
||||
private boolean myInvalidateChildren;
|
||||
private boolean myChildrenAreInvalid = true;
|
||||
private boolean myUpdateVisibility;
|
||||
|
||||
private NetworkLibrary() {
|
||||
|
@ -178,9 +179,13 @@ public class NetworkLibrary {
|
|||
db.loadCustomLinks(
|
||||
new NetworkDatabase.ICustomLinksHandler() {
|
||||
public void handleCustomLinkData(int id, String siteName,
|
||||
String title, String summary, String icon, Map<String, String> links) {
|
||||
final ICustomNetworkLink link = OPDSLinkReader.createCustomLink(id, siteName, title, summary, icon, links);
|
||||
if (link != null) {
|
||||
String title, String summary, Map<String,UrlInfo> infos) {
|
||||
if (title != null &&
|
||||
siteName != null &&
|
||||
infos.get(INetworkLink.URL_MAIN) != null) {
|
||||
final ICustomNetworkLink link = new OPDSCustomLink(
|
||||
id, siteName, title, summary, infos
|
||||
);
|
||||
addLinkInternal(link);
|
||||
}
|
||||
}
|
||||
|
@ -188,24 +193,6 @@ public class NetworkLibrary {
|
|||
);
|
||||
}
|
||||
|
||||
/*testDate(new ATOMUpdated(2010, 1, 1, 1, 0, 0, 0, 2, 0),
|
||||
new ATOMUpdated(2009, 12, 31, 23, 0, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2010, 12, 31, 23, 40, 0, 0, -1, -30),
|
||||
new ATOMUpdated(2011, 1, 1, 1, 10, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2010, 1, 31, 23, 40, 0, 0, -1, -30),
|
||||
new ATOMUpdated(2010, 2, 1, 1, 10, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2010, 2, 28, 23, 40, 0, 0, -1, -30),
|
||||
new ATOMUpdated(2010, 3, 1, 1, 10, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2012, 2, 28, 23, 40, 0, 0, -1, -30),
|
||||
new ATOMUpdated(2012, 2, 29, 1, 10, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2012, 2, 15, 23, 40, 0, 0, -1, -30),
|
||||
new ATOMUpdated(2012, 2, 16, 1, 10, 0, 0, 0, 0));
|
||||
testDate(new ATOMUpdated(2012, 2, 15, 23, 40, 1, 0, 3, 30),
|
||||
new ATOMUpdated(2012, 2, 15, 23, 40, 0, 0, 3, 30));
|
||||
testDate(new ATOMUpdated(2012, 2, 15, 23, 40, 0, 0, 3, 30),
|
||||
new ATOMUpdated(2012, 2, 15, 23, 40, 1, 0, 3, 30));
|
||||
testDate(new ATOMUpdated(2012, 2, 15, 23, 40, 0, 0.001f, 3, 30),
|
||||
new ATOMUpdated(2012, 2, 15, 23, 40, 0, 0, 3, 30));*/
|
||||
myIsAlreadyInitialized = true;
|
||||
}
|
||||
|
||||
|
@ -257,6 +244,15 @@ public class NetworkLibrary {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (INetworkLink link : myLinks) {
|
||||
if (link instanceof ICustomNetworkLink) {
|
||||
final ICustomNetworkLink customLink = (ICustomNetworkLink)link;
|
||||
if (customLink.isObsolete(12 * 60 * 60 * 1000)) { // 12 hours
|
||||
customLink.reloadInfo(true);
|
||||
NetworkDatabase.Instance().saveCustomLink(customLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,13 +262,12 @@ public class NetworkLibrary {
|
|||
// synchronize() method MUST be called after this method
|
||||
public void finishBackgroundUpdate() {
|
||||
synchronized (myBackgroundLock) {
|
||||
if (myBackgroundLinks == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (myLinks) {
|
||||
removeAllLoadedLinks();
|
||||
myLinks.addAll(myBackgroundLinks);
|
||||
updateChildren();
|
||||
if (myBackgroundLinks != null) {
|
||||
removeAllLoadedLinks();
|
||||
myLinks.addAll(myBackgroundLinks);
|
||||
}
|
||||
invalidateChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,31 +285,23 @@ public class NetworkLibrary {
|
|||
return url;
|
||||
}
|
||||
|
||||
public void invalidateChildren() {
|
||||
myInvalidateChildren = true;
|
||||
}
|
||||
|
||||
public void updateChildren() {
|
||||
myUpdateChildren = true;
|
||||
private void invalidateChildren() {
|
||||
myChildrenAreInvalid = true;
|
||||
}
|
||||
|
||||
public void invalidateVisibility() {
|
||||
myUpdateVisibility = true;
|
||||
}
|
||||
|
||||
private static boolean linkIsInvalid(INetworkLink link, INetworkLink nodeLink) {
|
||||
if (link instanceof ICustomNetworkLink) {
|
||||
if (link != nodeLink) {
|
||||
throw new RuntimeException("Two equal custom links!!! That's impossible");
|
||||
}
|
||||
return ((ICustomNetworkLink) link).hasChanges();
|
||||
}
|
||||
return !link.equals(nodeLink);
|
||||
private static boolean linkIsChanged(INetworkLink link) {
|
||||
return
|
||||
link instanceof ICustomNetworkLink &&
|
||||
((ICustomNetworkLink)link).hasChanges();
|
||||
}
|
||||
|
||||
private static void makeValid(INetworkLink link) {
|
||||
if (link instanceof ICustomNetworkLink) {
|
||||
((ICustomNetworkLink) link).resetChanges();
|
||||
((ICustomNetworkLink)link).resetChanges();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,13 +323,14 @@ public class NetworkLibrary {
|
|||
currentNode = nodeIterator.next();
|
||||
}
|
||||
if (!(currentNode instanceof NetworkCatalogTree)) {
|
||||
toRemove.add(currentNode);
|
||||
currentNode = null;
|
||||
++nodeCount;
|
||||
continue;
|
||||
}
|
||||
final INetworkLink nodeLink = ((NetworkCatalogTree) currentNode).Item.Link;
|
||||
final INetworkLink nodeLink = ((NetworkCatalogTree)currentNode).Item.Link;
|
||||
if (link == nodeLink) {
|
||||
if (linkIsInvalid(link, nodeLink)) {
|
||||
if (linkIsChanged(link)) {
|
||||
toRemove.add(currentNode);
|
||||
} else {
|
||||
processed = true;
|
||||
|
@ -359,7 +347,7 @@ public class NetworkLibrary {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (newNodeLink == null || linkIsInvalid(newNodeLink, nodeLink)) {
|
||||
if (newNodeLink == null || linkIsChanged(nodeLink)) {
|
||||
toRemove.add(currentNode);
|
||||
currentNode = null;
|
||||
++nodeCount;
|
||||
|
@ -381,30 +369,28 @@ public class NetworkLibrary {
|
|||
if (currentNode == null) {
|
||||
currentNode = nodeIterator.next();
|
||||
}
|
||||
if (currentNode instanceof NetworkCatalogTree) {
|
||||
toRemove.add(currentNode);
|
||||
}
|
||||
toRemove.add(currentNode);
|
||||
currentNode = null;
|
||||
}
|
||||
|
||||
for (FBTree tree : toRemove) {
|
||||
tree.removeSelf();
|
||||
}
|
||||
new AddCustomCatalogItemTree(myRootTree);
|
||||
mySearchItemTree = new SearchItemTree(myRootTree, 0);
|
||||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
for (FBTree tree : myRootTree.subTrees()) {
|
||||
if (!(tree instanceof NetworkCatalogTree)) {
|
||||
continue;
|
||||
if (tree instanceof NetworkCatalogTree) {
|
||||
((NetworkCatalogTree)tree).updateVisibility();
|
||||
}
|
||||
((NetworkCatalogTree) tree).updateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public void synchronize() {
|
||||
if (myUpdateChildren || myInvalidateChildren) {
|
||||
myUpdateChildren = false;
|
||||
myInvalidateChildren = false;
|
||||
if (myChildrenAreInvalid) {
|
||||
myChildrenAreInvalid = false;
|
||||
makeUpToDate();
|
||||
}
|
||||
if (myUpdateVisibility) {
|
||||
|
@ -413,17 +399,37 @@ public class NetworkLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
public NetworkTree getTree() {
|
||||
public NetworkTree getRootTree() {
|
||||
return myRootTree;
|
||||
}
|
||||
|
||||
public SearchItemTree getSearchItemTree() {
|
||||
return mySearchItemTree;
|
||||
}
|
||||
|
||||
public NetworkTree getTreeByKey(NetworkTree.Key key) {
|
||||
if (key.Parent == null) {
|
||||
return key.equals(myRootTree.getUniqueKey()) ? myRootTree : null;
|
||||
}
|
||||
final NetworkTree parentTree = getTreeByKey(key.Parent);
|
||||
if (parentTree == null) {
|
||||
return null;
|
||||
}
|
||||
for (FBTree tree : parentTree.subTrees()) {
|
||||
final NetworkTree nTree = (NetworkTree)tree;
|
||||
if (key.equals(nTree.getUniqueKey())) {
|
||||
return nTree;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void simpleSearch(String pattern, final NetworkOperationData.OnNewItemListener listener) throws ZLNetworkException {
|
||||
LinkedList<ZLNetworkRequest> requestList = new LinkedList<ZLNetworkRequest>();
|
||||
LinkedList<NetworkOperationData> dataList = new LinkedList<NetworkOperationData>();
|
||||
|
||||
final NetworkOperationData.OnNewItemListener synchronizedListener = new NetworkOperationData.OnNewItemListener() {
|
||||
public synchronized void onNewItem(INetworkLink link, NetworkLibraryItem item) {
|
||||
public synchronized void onNewItem(INetworkLink link, NetworkItem item) {
|
||||
listener.onNewItem(link, item);
|
||||
}
|
||||
public synchronized boolean confirmInterrupt() {
|
||||
|
@ -436,7 +442,7 @@ public class NetworkLibrary {
|
|||
|
||||
synchronized (myLinks) {
|
||||
for (INetworkLink link : activeLinks()) {
|
||||
final NetworkOperationData data = link.createOperationData(link, synchronizedListener);
|
||||
final NetworkOperationData data = link.createOperationData(synchronizedListener);
|
||||
final ZLNetworkRequest request = link.simpleSearchRequest(pattern, data);
|
||||
if (request != null) {
|
||||
dataList.add(data);
|
||||
|
@ -483,6 +489,7 @@ public class NetworkLibrary {
|
|||
}
|
||||
}
|
||||
NetworkDatabase.Instance().saveCustomLink(link);
|
||||
invalidateChildren();
|
||||
}
|
||||
|
||||
public void removeCustomLink(ICustomNetworkLink link) {
|
||||
|
@ -490,27 +497,6 @@ public class NetworkLibrary {
|
|||
myLinks.remove(link);
|
||||
}
|
||||
NetworkDatabase.Instance().deleteCustomLink(link);
|
||||
}
|
||||
|
||||
public boolean hasCustomLinkTitle(String title, INetworkLink exceptFor) {
|
||||
synchronized (myLinks) {
|
||||
for (INetworkLink link : myLinks) {
|
||||
if (link != exceptFor && link.getTitle().equals(title)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasCustomLinkSite(String siteName, INetworkLink exceptFor) {
|
||||
synchronized (myLinks) {
|
||||
for (INetworkLink link : myLinks) {
|
||||
if (link != exceptFor && link.getSiteName().equals(siteName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
invalidateChildren();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,16 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
|||
public class NetworkOperationData {
|
||||
|
||||
public interface OnNewItemListener {
|
||||
void onNewItem(INetworkLink link, NetworkLibraryItem item);
|
||||
void onNewItem(INetworkLink link, NetworkItem item);
|
||||
|
||||
void commitItems(INetworkLink link);
|
||||
|
||||
// returns true to confirm interrupt reading; return false to continue reading.
|
||||
// once true has been returned, all next calls must return true.
|
||||
/**
|
||||
* @return <code>true</code> to confirm interrupt reading;
|
||||
* <code>false</code> to continue reading.
|
||||
* Once <code>true</code> has been returned,
|
||||
* all next calls MUST return <code>true</code>.
|
||||
*/
|
||||
boolean confirmInterrupt();
|
||||
}
|
||||
|
||||
|
@ -43,11 +47,11 @@ public class NetworkOperationData {
|
|||
Listener = listener;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
protected void clear() {
|
||||
ResumeURI = null;
|
||||
}
|
||||
|
||||
public ZLNetworkRequest resume() {
|
||||
public final ZLNetworkRequest resume() {
|
||||
final ZLNetworkRequest request = Link.resume(this);
|
||||
clear();
|
||||
return request;
|
||||
|
|
|
@ -21,15 +21,48 @@ package org.geometerplus.fbreader.network;
|
|||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.geometerplus.zlibrary.core.constants.MimeTypes;
|
||||
import org.geometerplus.zlibrary.core.image.ZLImage;
|
||||
import org.geometerplus.zlibrary.core.util.ZLMiscUtil;
|
||||
|
||||
import org.geometerplus.fbreader.tree.FBTree;
|
||||
|
||||
public abstract class NetworkTree extends FBTree {
|
||||
protected NetworkTree(int level) {
|
||||
super(level);
|
||||
public static class Key implements Serializable {
|
||||
final Key Parent;
|
||||
final String Id;
|
||||
|
||||
private Key(Key parent, String id) {
|
||||
if (id == null) {
|
||||
throw new IllegalArgumentException("NetworkTree string id must be non-null");
|
||||
}
|
||||
Parent = parent;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof NetworkTree.Key)) {
|
||||
return false;
|
||||
}
|
||||
final NetworkTree.Key key = (NetworkTree.Key)other;
|
||||
return Id.equals(key.Id) && ZLMiscUtil.equals(Parent, key.Parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Parent == null ? Id : Parent.toString() + " :: " + Id;
|
||||
}
|
||||
}
|
||||
|
||||
protected NetworkTree() {
|
||||
|
@ -44,7 +77,7 @@ public abstract class NetworkTree extends FBTree {
|
|||
super(parent, position);
|
||||
}
|
||||
|
||||
public static ZLImage createCover(NetworkLibraryItem item) {
|
||||
public static ZLImage createCover(NetworkItem item) {
|
||||
if (item.Cover == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -88,15 +121,38 @@ public abstract class NetworkTree extends FBTree {
|
|||
}
|
||||
|
||||
|
||||
public abstract NetworkLibraryItem getHoldedItem();
|
||||
public abstract NetworkItem getHoldedItem();
|
||||
|
||||
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||
private Key myKey;
|
||||
/**
|
||||
* Returns unique identifier which can be used in NetworkView methods
|
||||
* @return unique Key instance
|
||||
*/
|
||||
public final Key getUniqueKey() {
|
||||
if (myKey == null) {
|
||||
//final ZLTree parentTree = getParent();
|
||||
final Key parentKey = Parent instanceof NetworkTree ?
|
||||
((NetworkTree)Parent).getUniqueKey() : null;
|
||||
myKey = new Key(parentKey, getStringId());
|
||||
}
|
||||
return myKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns id used as a part of unique key above. This string must be
|
||||
* not null
|
||||
* and
|
||||
* be unique for all children of same tree
|
||||
*/
|
||||
protected abstract String getStringId();
|
||||
|
||||
public void removeItems(Set<NetworkItem> items) {
|
||||
if (items.isEmpty() || subTrees().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final LinkedList<FBTree> treesList = new LinkedList<FBTree>();
|
||||
for (FBTree tree: subTrees()) {
|
||||
final NetworkLibraryItem treeItem = ((NetworkTree)tree).getHoldedItem();
|
||||
final NetworkItem treeItem = ((NetworkTree)tree).getHoldedItem();
|
||||
if (treeItem != null && items.contains(treeItem)) {
|
||||
treesList.add(tree);
|
||||
items.remove(treeItem);
|
||||
|
|
|
@ -23,13 +23,12 @@ import java.util.LinkedHashMap;
|
|||
import java.util.LinkedList;
|
||||
|
||||
public class SearchResult {
|
||||
|
||||
public final String Summary;
|
||||
public final LinkedHashMap<NetworkBookItem.AuthorData, LinkedList<NetworkBookItem>> BooksMap;
|
||||
public final LinkedHashMap<NetworkBookItem.AuthorData, LinkedList<NetworkBookItem>> BooksMap =
|
||||
new LinkedHashMap<NetworkBookItem.AuthorData, LinkedList<NetworkBookItem>>();
|
||||
|
||||
public SearchResult(String summary) {
|
||||
Summary = summary;
|
||||
BooksMap = new LinkedHashMap<NetworkBookItem.AuthorData, LinkedList<NetworkBookItem>>();
|
||||
}
|
||||
|
||||
public void addBook(NetworkBookItem book) {
|
||||
|
@ -43,7 +42,7 @@ public class SearchResult {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean empty() {
|
||||
public boolean isEmpty() {
|
||||
return BooksMap.size() == 0;
|
||||
}
|
||||
}
|
||||
|
|
33
src/org/geometerplus/fbreader/network/TopUpItem.java
Normal file
33
src/org/geometerplus/fbreader/network/TopUpItem.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.fbreader.network;
|
||||
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
|
||||
public class TopUpItem extends NetworkItem {
|
||||
public TopUpItem(INetworkLink link, String cover) {
|
||||
super(
|
||||
link,
|
||||
ZLResource.resource("networkView").getResource("refillTitle").getValue(),
|
||||
ZLResource.resource("networkView").getResource("refillSummary").getValue(),
|
||||
cover
|
||||
);
|
||||
}
|
||||
}
|
59
src/org/geometerplus/fbreader/network/UrlInfo.java
Normal file
59
src/org/geometerplus/fbreader/network/UrlInfo.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.fbreader.network;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.geometerplus.zlibrary.core.util.ZLMiscUtil;
|
||||
|
||||
public final class UrlInfo implements Serializable {
|
||||
public static final UrlInfo NULL = new UrlInfo(null, null);
|
||||
|
||||
public final String URL;
|
||||
public final Date Updated;
|
||||
|
||||
public UrlInfo(String url, Date updated) {
|
||||
URL = url;
|
||||
Updated = updated;
|
||||
}
|
||||
|
||||
public UrlInfo(String url) {
|
||||
this(url, new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof UrlInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final UrlInfo info = (UrlInfo)o;
|
||||
return ZLMiscUtil.equals(URL, info.URL) && ZLMiscUtil.equals(Updated, info.Updated);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ZLMiscUtil.hashCode(URL) + ZLMiscUtil.hashCode(Updated);
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
|
||||
private String myInitializedDataSid;
|
||||
private String myAccount;
|
||||
private final HashMap<String, NetworkLibraryItem> myPurchasedBooks = new HashMap<String, NetworkLibraryItem>();
|
||||
private final HashMap<String, NetworkItem> myPurchasedBooks = new HashMap<String, NetworkItem>();
|
||||
|
||||
public LitResAuthenticationManager(INetworkLink link, String sslCertificate) {
|
||||
super(link, sslCertificate);
|
||||
|
@ -89,7 +89,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
sid = mySidOption.getValue();
|
||||
}
|
||||
|
||||
String url = Link.getLink(INetworkLink.URL_SIGN_IN);
|
||||
String url = Link.getUrlInfo(INetworkLink.URL_SIGN_IN).URL;
|
||||
if (url == null) {
|
||||
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
|
||||
@Override
|
||||
public void authorise(String password) throws ZLNetworkException {
|
||||
String url = Link.getLink(INetworkLink.URL_SIGN_IN);
|
||||
String url = Link.getUrlInfo(INetworkLink.URL_SIGN_IN).URL;
|
||||
if (url == null) {
|
||||
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
if (sid.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
final String url = Link.getLink(INetworkLink.URL_REFILL_ACCOUNT);
|
||||
final String url = Link.getUrlInfo(INetworkLink.URL_REFILL_ACCOUNT).URL;
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
return new LitResNetworkRequest(
|
||||
LitResUtil.url(Link, query),
|
||||
SSLCertificate,
|
||||
new LitResXMLReader(Link, new LinkedList<NetworkLibraryItem>())
|
||||
new LitResXMLReader(Link, new LinkedList<NetworkItem>())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
private void loadPurchasedBooksOnSuccess(LitResNetworkRequest purchasedBooksRequest) {
|
||||
LitResXMLReader reader = (LitResXMLReader)purchasedBooksRequest.Reader;
|
||||
myPurchasedBooks.clear();
|
||||
for (NetworkLibraryItem item: reader.Books) {
|
||||
for (NetworkItem item: reader.Books) {
|
||||
if (item instanceof NetworkBookItem) {
|
||||
NetworkBookItem book = (NetworkBookItem)item;
|
||||
myPurchasedBooks.put(book.Id, book);
|
||||
|
@ -401,7 +401,7 @@ public class LitResAuthenticationManager extends NetworkAuthenticationManager {
|
|||
|
||||
@Override
|
||||
public void recoverPassword(String email) throws ZLNetworkException {
|
||||
String url = Link.getLink(INetworkLink.URL_RECOVER_PASSWORD);
|
||||
String url = Link.getUrlInfo(INetworkLink.URL_RECOVER_PASSWORD).URL;
|
||||
if (url == null) {
|
||||
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
|
|
@ -21,15 +21,127 @@ package org.geometerplus.fbreader.network.authentication.litres;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
|
||||
import org.geometerplus.fbreader.network.*;
|
||||
|
||||
abstract class SortedCatalogItem extends NetworkCatalogItem {
|
||||
private final List<NetworkItem> myChildren = new LinkedList<NetworkItem>();
|
||||
|
||||
private SortedCatalogItem(NetworkCatalogItem parent, ZLResource resource, List<NetworkItem> children) {
|
||||
super(parent.Link, resource.getValue(), resource.getResource("summary").getValue(), "", parent.URLByType);
|
||||
for (NetworkItem child : children) {
|
||||
if (accepts(child)) {
|
||||
myChildren.add(child);
|
||||
}
|
||||
}
|
||||
final Comparator<NetworkItem> comparator = getComparator();
|
||||
if (comparator != null) {
|
||||
Collections.sort(myChildren, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myChildren.isEmpty();
|
||||
}
|
||||
|
||||
protected abstract Comparator<NetworkItem> getComparator();
|
||||
protected boolean accepts(NetworkItem item) {
|
||||
return item instanceof NetworkBookItem;
|
||||
}
|
||||
|
||||
public SortedCatalogItem(NetworkCatalogItem parent, String resourceKey, List<NetworkItem> children) {
|
||||
this(parent, ZLResource.resource("networkView").getResource(resourceKey), children);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayItem() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChildren(NetworkOperationData.OnNewItemListener listener) throws ZLNetworkException {
|
||||
for (NetworkItem child : myChildren) {
|
||||
listener.onNewItem(Link, child);
|
||||
}
|
||||
listener.commitItems(Link);
|
||||
}
|
||||
}
|
||||
|
||||
class ByAuthorCatalogItem extends SortedCatalogItem {
|
||||
ByAuthorCatalogItem(NetworkCatalogItem parent, List<NetworkItem> children) {
|
||||
super(parent, "byAuthor", children);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<NetworkItem> getComparator() {
|
||||
return new NetworkBookItemComparator();
|
||||
}
|
||||
}
|
||||
|
||||
class ByTitleCatalogItem extends SortedCatalogItem {
|
||||
ByTitleCatalogItem(NetworkCatalogItem parent, List<NetworkItem> children) {
|
||||
super(parent, "byTitle", children);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<NetworkItem> getComparator() {
|
||||
return new Comparator<NetworkItem>() {
|
||||
public int compare(NetworkItem item0, NetworkItem item1) {
|
||||
return item0.Title.compareTo(item1.Title);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ByDateCatalogItem extends SortedCatalogItem {
|
||||
ByDateCatalogItem(NetworkCatalogItem parent, List<NetworkItem> children) {
|
||||
super(parent, "byDate", children);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<NetworkItem> getComparator() {
|
||||
return new Comparator<NetworkItem>() {
|
||||
public int compare(NetworkItem item0, NetworkItem item1) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class BySeriesCatalogItem extends SortedCatalogItem {
|
||||
BySeriesCatalogItem(NetworkCatalogItem parent, List<NetworkItem> children) {
|
||||
super(parent, "bySeries", children);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<NetworkItem> getComparator() {
|
||||
return new Comparator<NetworkItem>() {
|
||||
public int compare(NetworkItem item0, NetworkItem item1) {
|
||||
final NetworkBookItem book0 = (NetworkBookItem)item0;
|
||||
final NetworkBookItem book1 = (NetworkBookItem)item1;
|
||||
int diff = book0.SeriesTitle.compareTo(book1.SeriesTitle);
|
||||
if (diff == 0) {
|
||||
diff = book0.IndexInSeries - book1.IndexInSeries;
|
||||
}
|
||||
return diff != 0 ? diff : book0.Title.compareTo(book1.Title);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accepts(NetworkItem item) {
|
||||
return
|
||||
item instanceof NetworkBookItem &&
|
||||
((NetworkBookItem)item).SeriesTitle != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class LitResBookshelfItem extends NetworkCatalogItem {
|
||||
private boolean myForceReload;
|
||||
|
||||
public LitResBookshelfItem(INetworkLink link, String title, String summary, String cover, Map<Integer, String> urlByType, Accessibility accessibility) {
|
||||
super(link, title, summary, cover, urlByType, accessibility);
|
||||
super(link, title, summary, cover, urlByType, accessibility, CatalogType.OTHER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,11 +166,21 @@ public class LitResBookshelfItem extends NetworkCatalogItem {
|
|||
} finally {
|
||||
myForceReload = true;
|
||||
// TODO: implement asynchronous loading
|
||||
ArrayList<NetworkBookItem> children =
|
||||
new ArrayList<NetworkBookItem>(mgr.purchasedBooks());
|
||||
Collections.sort(children, new NetworkBookItemComparator());
|
||||
for (NetworkLibraryItem item : children) {
|
||||
listener.onNewItem(Link, item);
|
||||
ArrayList<NetworkItem> children =
|
||||
new ArrayList<NetworkItem>(mgr.purchasedBooks());
|
||||
if (children.size() <= 5) {
|
||||
Collections.sort(children, new NetworkBookItemComparator());
|
||||
for (NetworkItem item : children) {
|
||||
listener.onNewItem(Link, item);
|
||||
}
|
||||
} else {
|
||||
listener.onNewItem(Link, new ByDateCatalogItem(this, children));
|
||||
listener.onNewItem(Link, new ByAuthorCatalogItem(this, children));
|
||||
listener.onNewItem(Link, new ByTitleCatalogItem(this, children));
|
||||
final BySeriesCatalogItem bySeries = new BySeriesCatalogItem(this, children);
|
||||
if (!bySeries.isEmpty()) {
|
||||
listener.onNewItem(Link, bySeries);
|
||||
}
|
||||
}
|
||||
listener.commitItems(Link);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,10 @@ import java.util.Map;
|
|||
import org.geometerplus.zlibrary.core.util.ZLNetworkUtil;
|
||||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.Basket;
|
||||
import org.geometerplus.fbreader.network.NetworkBookItem;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSCatalogItem;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSNetworkLink;
|
||||
|
||||
public class LitResRecommendationsItem extends OPDSCatalogItem {
|
||||
public LitResRecommendationsItem(INetworkLink link, String title, String summary, String cover, Map<Integer,String> urlByType, Accessibility accessibility) {
|
||||
|
@ -46,6 +48,17 @@ public class LitResRecommendationsItem extends OPDSCatalogItem {
|
|||
}
|
||||
builder.append(book.Id);
|
||||
}
|
||||
final Basket basket = Link.basket();
|
||||
if (basket != null) {
|
||||
for (String bookId : basket.bookIds()) {
|
||||
if (flag) {
|
||||
builder.append(',');
|
||||
} else {
|
||||
flag = true;
|
||||
}
|
||||
builder.append(bookId);
|
||||
}
|
||||
}
|
||||
|
||||
return ZLNetworkUtil.appendParameter(URLByType.get(URL_CATALOG), "ids", builder.toString());
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.geometerplus.fbreader.network.opds.HtmlToString;
|
|||
class LitResXMLReader extends LitResAuthenticationXMLReader {
|
||||
|
||||
public final INetworkLink Link;
|
||||
public final List<NetworkLibraryItem> Books;
|
||||
public final List<NetworkItem> Books;
|
||||
|
||||
private int myIndex;
|
||||
|
||||
|
@ -55,7 +55,7 @@ class LitResXMLReader extends LitResAuthenticationXMLReader {
|
|||
private HashMap<Integer, String> myURLByType = new HashMap<Integer, String>(); // TODO: remove
|
||||
private LinkedList<BookReference> myReferences = new LinkedList<BookReference>();
|
||||
|
||||
public LitResXMLReader(INetworkLink link, List<NetworkLibraryItem> books) {
|
||||
public LitResXMLReader(INetworkLink link, List<NetworkItem> books) {
|
||||
super(link.getSiteName());
|
||||
Link = link;
|
||||
Books = books;
|
||||
|
|
52
src/org/geometerplus/fbreader/network/opds/BasketItem.java
Normal file
52
src/org/geometerplus/fbreader/network/opds/BasketItem.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.fbreader.network.opds;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.geometerplus.zlibrary.core.util.ZLNetworkUtil;
|
||||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkBookItem;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSNetworkLink;
|
||||
import org.geometerplus.fbreader.network.opds.OPDSCatalogItem;
|
||||
|
||||
public class BasketItem extends OPDSCatalogItem {
|
||||
BasketItem(OPDSNetworkLink link, String title, String summary, String cover, Map<Integer,String> urlByType, Accessibility accessibility) {
|
||||
super(link, title, summary, cover, urlByType, accessibility, CatalogType.BY_SERIES);
|
||||
link.setSupportsBasket();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUrl() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
boolean flag = false;
|
||||
for (String bookId : Link.basket().bookIds()) {
|
||||
if (flag) {
|
||||
builder.append(',');
|
||||
} else {
|
||||
flag = true;
|
||||
}
|
||||
builder.append(bookId);
|
||||
}
|
||||
|
||||
return ZLNetworkUtil.appendParameter(URLByType.get(URL_CATALOG), "ids", builder.toString());
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader, OPDSConstants, MimeTypes
|
|||
private int myItemsToLoad = -1;
|
||||
|
||||
/**
|
||||
* Creates new OPDSFeedReader instance that can be used to get NetworkLibraryItem objects from OPDS feeds.
|
||||
* Creates new OPDSFeedReader instance that can be used to get NetworkItem objects from OPDS feeds.
|
||||
*
|
||||
* @param baseURL string that contains URL of the OPDS feed, that will be read using this instance of the reader
|
||||
* @param result network results buffer. Must be created using OPDSNetworkLink corresponding to the OPDS feed,
|
||||
|
@ -203,7 +203,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader, OPDSConstants, MimeTypes
|
|||
}
|
||||
}
|
||||
|
||||
NetworkLibraryItem item;
|
||||
NetworkItem item;
|
||||
if (hasBookLink) {
|
||||
item = readBookItem(entry);
|
||||
} else {
|
||||
|
@ -218,7 +218,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader, OPDSConstants, MimeTypes
|
|||
private static final String AuthorPrefix = "author:";
|
||||
private static final String AuthorsPrefix = "authors:";
|
||||
|
||||
private NetworkLibraryItem readBookItem(OPDSEntry entry) {
|
||||
private NetworkItem readBookItem(OPDSEntry entry) {
|
||||
final OPDSNetworkLink opdsNetworkLink = (OPDSNetworkLink)myData.Link;
|
||||
/*final String date;
|
||||
if (entry.DCIssued != null) {
|
||||
|
@ -368,7 +368,7 @@ class NetworkOPDSFeedReader implements OPDSFeedReader, OPDSConstants, MimeTypes
|
|||
}
|
||||
}
|
||||
|
||||
private NetworkLibraryItem readCatalogItem(OPDSEntry entry) {
|
||||
private NetworkItem readCatalogItem(OPDSEntry entry) {
|
||||
final OPDSNetworkLink opdsLink = (OPDSNetworkLink)myData.Link;
|
||||
String coverURL = null;
|
||||
String url = null;
|
||||
|
@ -457,6 +457,20 @@ class NetworkOPDSFeedReader implements OPDSFeedReader, OPDSConstants, MimeTypes
|
|||
urlMap,
|
||||
opdsLink.getCondition(entry.Id.Uri)
|
||||
);
|
||||
} else if (REL_BASKET.equals(litresRel)) {
|
||||
return null;
|
||||
/*
|
||||
return new BasketItem(
|
||||
opdsLink,
|
||||
entry.Title,
|
||||
annotation,
|
||||
coverURL,
|
||||
urlMap,
|
||||
opdsLink.getCondition(entry.Id.Uri)
|
||||
);
|
||||
*/
|
||||
} else if (REL_TOPUP.equals(litresRel)) {
|
||||
return new TopUpItem(opdsLink, coverURL);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.geometerplus.fbreader.network.opds;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkManager;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
||||
|
||||
|
@ -49,19 +48,12 @@ public class OPDSCatalogItem extends NetworkCatalogItem {
|
|||
myExtraData = null;
|
||||
}
|
||||
|
||||
private void doLoadChildren(NetworkOperationData.OnNewItemListener listener,
|
||||
ZLNetworkRequest networkRequest) throws ZLNetworkException {
|
||||
while (networkRequest != null) {
|
||||
try {
|
||||
ZLNetworkManager.Instance().perform(networkRequest);
|
||||
} catch (ZLNetworkException e) {
|
||||
myLoadingState = null;
|
||||
throw e;
|
||||
}
|
||||
if (listener.confirmInterrupt()) {
|
||||
return;
|
||||
}
|
||||
networkRequest = myLoadingState.resume();
|
||||
private void doLoadChildren(ZLNetworkRequest networkRequest) throws ZLNetworkException {
|
||||
try {
|
||||
super.doLoadChildren(myLoadingState, networkRequest);
|
||||
} catch (ZLNetworkException e) {
|
||||
myLoadingState = null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,12 +70,12 @@ public class OPDSCatalogItem extends NetworkCatalogItem {
|
|||
public final void loadChildren(NetworkOperationData.OnNewItemListener listener) throws ZLNetworkException {
|
||||
OPDSNetworkLink opdsLink = (OPDSNetworkLink) Link;
|
||||
|
||||
myLoadingState = opdsLink.createOperationData(Link, listener);
|
||||
myLoadingState = opdsLink.createOperationData(listener);
|
||||
|
||||
ZLNetworkRequest networkRequest =
|
||||
opdsLink.createNetworkData(getUrl(), myLoadingState);
|
||||
|
||||
doLoadChildren(listener, networkRequest);
|
||||
doLoadChildren(networkRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,7 +88,7 @@ public class OPDSCatalogItem extends NetworkCatalogItem {
|
|||
if (myLoadingState != null) {
|
||||
myLoadingState.Listener = listener;
|
||||
ZLNetworkRequest networkRequest = myLoadingState.resume();
|
||||
doLoadChildren(listener, networkRequest);
|
||||
doLoadChildren(networkRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ interface OPDSConstants {
|
|||
// Feed level
|
||||
String REL_BOOKSHELF = "http://data.fbreader.org/rel/bookshelf";
|
||||
String REL_RECOMMENDATIONS = "http://data.fbreader.org/rel/recommendations";
|
||||
String REL_BASKET = "http://data.fbreader.org/rel/basket";
|
||||
String REL_TOPUP = "http://data.fbreader.org/rel/topup";
|
||||
//String REL_SUBSCRIPTIONS = "http://opds-spec.org/subscriptions";
|
||||
|
||||
// Entry level / catalog types
|
||||
|
|
|
@ -32,14 +32,22 @@ import org.geometerplus.zlibrary.core.util.ZLMiscUtil;
|
|||
import org.geometerplus.fbreader.network.ICustomNetworkLink;
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkException;
|
||||
import org.geometerplus.fbreader.network.UrlInfo;
|
||||
|
||||
class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
||||
public class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
||||
private int myId;
|
||||
|
||||
private boolean myHasChanges;
|
||||
|
||||
OPDSCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) {
|
||||
super(siteName, title, summary, icon, null, links, false);
|
||||
private static String removeWWWPrefix(String siteName) {
|
||||
if (siteName != null && siteName.startsWith("www.")) {
|
||||
return siteName.substring(4);
|
||||
}
|
||||
return siteName;
|
||||
}
|
||||
|
||||
public OPDSCustomLink(int id, String siteName, String title, String summary, Map<String,UrlInfo> infos) {
|
||||
super(removeWWWPrefix(siteName), title, summary, null, infos, false);
|
||||
myId = id;
|
||||
}
|
||||
|
||||
|
@ -59,12 +67,6 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
|||
myHasChanges = false;
|
||||
}
|
||||
|
||||
|
||||
public final void setIcon(String icon) {
|
||||
myHasChanges = myHasChanges || !ZLMiscUtil.equals(myIcon, icon);
|
||||
myIcon = icon;
|
||||
}
|
||||
|
||||
public final void setSiteName(String name) {
|
||||
myHasChanges = myHasChanges || !ZLMiscUtil.equals(mySiteName, name);
|
||||
mySiteName = name;
|
||||
|
@ -80,28 +82,39 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
|||
myTitle = title;
|
||||
}
|
||||
|
||||
public final void setLink(String urlKey, String url) {
|
||||
if (url == null) {
|
||||
removeLink(urlKey);
|
||||
} else {
|
||||
final String oldUrl = myLinks.put(urlKey, url);
|
||||
myHasChanges = myHasChanges || !url.equals(oldUrl);
|
||||
}
|
||||
public final void setUrl(String urlKey, String url) {
|
||||
myInfos.put(urlKey, new UrlInfo(url, new Date()));
|
||||
myHasChanges = true;
|
||||
}
|
||||
|
||||
public final void removeLink(String urlKey) {
|
||||
final String oldUrl = myLinks.remove(urlKey);
|
||||
public final void removeUrl(String urlKey) {
|
||||
final UrlInfo oldUrl = myInfos.remove(urlKey);
|
||||
myHasChanges = myHasChanges || oldUrl != null;
|
||||
}
|
||||
|
||||
public boolean isObsolete(long milliSeconds) {
|
||||
final long old = System.currentTimeMillis() - milliSeconds;
|
||||
|
||||
final Date searchUpdateDate = getUrlInfo(URL_SEARCH).Updated;
|
||||
if (searchUpdateDate == null || searchUpdateDate.getTime() < old) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void reloadInfo() throws ZLNetworkException {
|
||||
final Date iconUpdateDate = getUrlInfo(URL_ICON).Updated;
|
||||
if (iconUpdateDate == null || iconUpdateDate.getTime() < old) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reloadInfo(final boolean urlsOnly) throws ZLNetworkException {
|
||||
final LinkedList<String> opensearchDescriptionURLs = new LinkedList<String>();
|
||||
final List<OpenSearchDescription> descriptions = Collections.synchronizedList(new LinkedList<OpenSearchDescription>());
|
||||
|
||||
ZLNetworkException error = null;
|
||||
try {
|
||||
ZLNetworkManager.Instance().perform(new ZLNetworkRequest(getLink(INetworkLink.URL_MAIN)) {
|
||||
ZLNetworkManager.Instance().perform(new ZLNetworkRequest(getUrlInfo(URL_MAIN).URL) {
|
||||
@Override
|
||||
public void handleStream(URLConnection connection, InputStream inputStream) throws IOException, ZLNetworkException {
|
||||
final CatalogInfoReader info = new CatalogInfoReader(URL, OPDSCustomLink.this, opensearchDescriptionURLs);
|
||||
|
@ -113,16 +126,14 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
|||
if (info.Title == null) {
|
||||
throw new ZLNetworkException(NetworkException.ERROR_NO_REQUIRED_INFORMATION);
|
||||
}
|
||||
myTitle = info.Title;
|
||||
if (info.Icon != null) {
|
||||
myIcon = info.Icon;
|
||||
}
|
||||
if (info.Summary != null) {
|
||||
mySummary = info.Summary;
|
||||
}
|
||||
setUrl(URL_ICON, info.Icon);
|
||||
if (info.DirectOpenSearchDescription != null) {
|
||||
descriptions.add(info.DirectOpenSearchDescription);
|
||||
}
|
||||
if (!urlsOnly) {
|
||||
myTitle = info.Title;
|
||||
mySummary = info.Summary;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (ZLNetworkException e) {
|
||||
|
@ -136,7 +147,7 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
|||
requests.add(new ZLNetworkRequest(url) {
|
||||
@Override
|
||||
public void handleStream(URLConnection connection, InputStream inputStream) throws IOException, ZLNetworkException {
|
||||
new OpenSearchXMLReader(URL, descriptions, 20).read(inputStream);
|
||||
new OpenSearchXMLReader(URL, descriptions).read(inputStream);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -151,7 +162,9 @@ class OPDSCustomLink extends OPDSNetworkLink implements ICustomNetworkLink {
|
|||
|
||||
if (!descriptions.isEmpty()) {
|
||||
// TODO: May be do not use '%s'??? Use Description instead??? (this needs to rewrite SEARCH engine logic a little)
|
||||
setLink(URL_SEARCH, descriptions.get(0).makeQuery("%s"));
|
||||
setUrl(URL_SEARCH, descriptions.get(0).makeQuery("%s"));
|
||||
} else {
|
||||
setUrl(URL_SEARCH, null);
|
||||
}
|
||||
if (error != null) {
|
||||
throw error;
|
||||
|
|
|
@ -39,23 +39,6 @@ import org.geometerplus.fbreader.network.atom.ATOMUpdated;
|
|||
public class OPDSLinkReader {
|
||||
static final String CATALOGS_URL = "http://data.fbreader.org/catalogs/generic-1.2.xml";
|
||||
|
||||
public static ICustomNetworkLink createCustomLink(int id, String siteName, String title, String summary, String icon, Map<String, String> links) {
|
||||
if (siteName == null || title == null || links.get(INetworkLink.URL_MAIN) == null) {
|
||||
return null;
|
||||
}
|
||||
return new OPDSCustomLink(id, siteName, title, summary, icon, links);
|
||||
}
|
||||
|
||||
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(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;
|
||||
public static final int CACHE_UPDATE = 1;
|
||||
public static final int CACHE_CLEAR = 2;
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
|||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkLibrary;
|
||||
import org.geometerplus.fbreader.network.NetworkCatalogItem;
|
||||
import org.geometerplus.fbreader.network.UrlInfo;
|
||||
import org.geometerplus.fbreader.network.atom.ATOMLink;
|
||||
import org.geometerplus.fbreader.network.atom.ATOMUpdated;
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
@ -98,8 +99,7 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants, MimeType
|
|||
final String summary = entry.Content;
|
||||
final String language = entry.DCLanguage;
|
||||
|
||||
String icon = null;
|
||||
final HashMap<String,String> links = new HashMap<String,String>();
|
||||
final HashMap<String,UrlInfo> infos = new HashMap<String,UrlInfo>();
|
||||
final HashMap<String,NetworkCatalogItem.Accessibility> urlConditions =
|
||||
new HashMap<String,NetworkCatalogItem.Accessibility>();
|
||||
for (ATOMLink link: entry.Links) {
|
||||
|
@ -108,34 +108,35 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants, MimeType
|
|||
final String rel = link.getRel();
|
||||
if (rel == REL_IMAGE_THUMBNAIL || rel == REL_THUMBNAIL) {
|
||||
if (type == MIME_IMAGE_PNG || type == MIME_IMAGE_JPEG) {
|
||||
icon = href;
|
||||
infos.put(INetworkLink.URL_ICON, new UrlInfo(href));
|
||||
}
|
||||
} else if ((rel != null && rel.startsWith(REL_IMAGE_PREFIX)) || rel == REL_COVER) {
|
||||
if (icon == null && (type == MIME_IMAGE_PNG || type == MIME_IMAGE_JPEG)) {
|
||||
icon = href;
|
||||
if (infos.get(INetworkLink.URL_ICON) == null &&
|
||||
(type == MIME_IMAGE_PNG || type == MIME_IMAGE_JPEG)) {
|
||||
infos.put(INetworkLink.URL_ICON, new UrlInfo(href));
|
||||
}
|
||||
} else if (rel == null) {
|
||||
if (type == MIME_APP_ATOM) {
|
||||
links.put(INetworkLink.URL_MAIN, href);
|
||||
infos.put(INetworkLink.URL_MAIN, new UrlInfo(href));
|
||||
}
|
||||
} else if (rel == "search") {
|
||||
if (type == MIME_APP_ATOM) {
|
||||
final OpenSearchDescription descr = OpenSearchDescription.createDefault(href);
|
||||
if (descr.isValid()) {
|
||||
// TODO: May be do not use '%s'??? Use Description instead??? (this needs to rewrite SEARCH engine logic a little)
|
||||
links.put(INetworkLink.URL_SEARCH, descr.makeQuery("%s"));
|
||||
infos.put(INetworkLink.URL_SEARCH, new UrlInfo(descr.makeQuery("%s")));
|
||||
}
|
||||
}
|
||||
} else if (rel == REL_LINK_SIGN_IN) {
|
||||
links.put(INetworkLink.URL_SIGN_IN, href);
|
||||
infos.put(INetworkLink.URL_SIGN_IN, new UrlInfo(href));
|
||||
} else if (rel == REL_LINK_SIGN_OUT) {
|
||||
links.put(INetworkLink.URL_SIGN_OUT, href);
|
||||
infos.put(INetworkLink.URL_SIGN_OUT, new UrlInfo(href));
|
||||
} else if (rel == REL_LINK_SIGN_UP) {
|
||||
links.put(INetworkLink.URL_SIGN_UP, href);
|
||||
infos.put(INetworkLink.URL_SIGN_UP, new UrlInfo(href));
|
||||
} else if (rel == REL_LINK_REFILL_ACCOUNT) {
|
||||
links.put(INetworkLink.URL_REFILL_ACCOUNT, href);
|
||||
infos.put(INetworkLink.URL_REFILL_ACCOUNT, new UrlInfo(href));
|
||||
} else if (rel == REL_LINK_RECOVER_PASSWORD) {
|
||||
links.put(INetworkLink.URL_RECOVER_PASSWORD, href);
|
||||
infos.put(INetworkLink.URL_RECOVER_PASSWORD, new UrlInfo(href));
|
||||
} else if (rel == REL_CONDITION_NEVER) {
|
||||
urlConditions.put(href, NetworkCatalogItem.Accessibility.NEVER);
|
||||
} else if (rel == REL_CONDITION_SIGNED_IN) {
|
||||
|
@ -153,7 +154,7 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants, MimeType
|
|||
sslCertificate = null;
|
||||
}
|
||||
|
||||
INetworkLink result = link(siteName, title, summary, icon, language, links, urlConditions, sslCertificate);
|
||||
INetworkLink result = link(siteName, title, summary, language, infos, urlConditions, sslCertificate);
|
||||
if (result != null) {
|
||||
myListener.onNewLink(result);
|
||||
}
|
||||
|
@ -164,13 +165,12 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants, MimeType
|
|||
String siteName,
|
||||
String title,
|
||||
String summary,
|
||||
String icon,
|
||||
String language,
|
||||
Map<String,String> links,
|
||||
Map<String,UrlInfo> infos,
|
||||
HashMap<String,NetworkCatalogItem.Accessibility> urlConditions,
|
||||
String sslCertificate
|
||||
) {
|
||||
if (siteName == null || title == null || links.get(INetworkLink.URL_MAIN) == null) {
|
||||
if (siteName == null || title == null || infos.get(INetworkLink.URL_MAIN) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -178,9 +178,8 @@ class OPDSLinkXMLReader extends OPDSXMLReader implements OPDSConstants, MimeType
|
|||
siteName,
|
||||
title,
|
||||
summary,
|
||||
icon,
|
||||
language,
|
||||
links,
|
||||
infos,
|
||||
myHasStableIdentifiers
|
||||
);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
|
|||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
class OPDSNetworkLink extends AbstractNetworkLink {
|
||||
public class OPDSNetworkLink extends AbstractNetworkLink {
|
||||
private TreeMap<RelationAlias, String> myRelationAliases;
|
||||
|
||||
private TreeMap<String,NetworkCatalogItem.Accessibility> myUrlConditions;
|
||||
|
@ -44,9 +44,9 @@ class OPDSNetworkLink extends AbstractNetworkLink {
|
|||
|
||||
private final boolean myHasStableIdentifiers;
|
||||
|
||||
OPDSNetworkLink(String siteName, String title, String summary, String icon, String language,
|
||||
Map<String, String> links, boolean hasStableIdentifiers) {
|
||||
super(siteName, title, summary, icon, language, links);
|
||||
OPDSNetworkLink(String siteName, String title, String summary, String language,
|
||||
Map<String,UrlInfo> infos, boolean hasStableIdentifiers) {
|
||||
super(siteName, title, summary, language, infos);
|
||||
myHasStableIdentifiers = hasStableIdentifiers;
|
||||
}
|
||||
|
||||
|
@ -113,13 +113,12 @@ class OPDSNetworkLink extends AbstractNetworkLink {
|
|||
}
|
||||
|
||||
@Override
|
||||
public OPDSCatalogItem.State createOperationData(INetworkLink link,
|
||||
NetworkOperationData.OnNewItemListener listener) {
|
||||
return new OPDSCatalogItem.State(link, listener);
|
||||
public OPDSCatalogItem.State createOperationData(NetworkOperationData.OnNewItemListener listener) {
|
||||
return new OPDSCatalogItem.State(this, listener);
|
||||
}
|
||||
|
||||
public ZLNetworkRequest simpleSearchRequest(String pattern, NetworkOperationData data) {
|
||||
final String url = getLink(URL_SEARCH);
|
||||
final String url = getUrlInfo(URL_SEARCH).URL;
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -135,9 +134,9 @@ class OPDSNetworkLink extends AbstractNetworkLink {
|
|||
}
|
||||
|
||||
public NetworkCatalogItem libraryItem() {
|
||||
TreeMap<Integer, String> urlMap = new TreeMap<Integer, String>();
|
||||
urlMap.put(NetworkCatalogItem.URL_CATALOG, getLink(URL_MAIN));
|
||||
return new OPDSCatalogItem(this, getTitle(), getSummary(), getIcon(), urlMap, myExtraData);
|
||||
TreeMap<Integer,String> urlMap = new TreeMap<Integer,String>();
|
||||
urlMap.put(NetworkCatalogItem.URL_CATALOG, getUrlInfo(URL_MAIN).URL);
|
||||
return new OPDSCatalogItem(this, getTitle(), getSummary(), getUrlInfo(URL_ICON).URL, urlMap, myExtraData);
|
||||
}
|
||||
|
||||
public NetworkAuthenticationManager authenticationManager() {
|
||||
|
|
|
@ -172,7 +172,7 @@ class OPDSXMLReader extends ZLXMLReaderAdapter {
|
|||
|
||||
private int myState = START;
|
||||
|
||||
private final StringBuffer myBuffer = new StringBuffer();
|
||||
private final StringBuilder myBuffer = new StringBuilder();
|
||||
private HtmlToString myHtmlToString = new HtmlToString();
|
||||
|
||||
private boolean myFeedMetadataProcessed;
|
||||
|
|
|
@ -23,22 +23,20 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
class OpenSearchDescription {
|
||||
|
||||
public static OpenSearchDescription createDefault(String template) {
|
||||
return new OpenSearchDescription(template, 20, -1, -1);
|
||||
return new OpenSearchDescription(template, -1, -1);
|
||||
}
|
||||
|
||||
public final String Template;
|
||||
public final int IndexOffset;
|
||||
public final int PageOffset;
|
||||
|
||||
public final int ItemsPerPage;
|
||||
public final int ItemsPerPage = 20;
|
||||
|
||||
public OpenSearchDescription(String template, int itemsPerPage, int indexOffset, int pageOffset) {
|
||||
OpenSearchDescription(String template, int indexOffset, int pageOffset) {
|
||||
Template = template;
|
||||
IndexOffset = indexOffset;
|
||||
PageOffset = pageOffset;
|
||||
ItemsPerPage = itemsPerPage;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
|
@ -62,13 +60,7 @@ class OpenSearchDescription {
|
|||
if (name == "searchTerms") {
|
||||
m.appendReplacement(query, searchTerms);
|
||||
} else if (name == "count") {
|
||||
if (ItemsPerPage > 0) {
|
||||
m.appendReplacement(query, String.valueOf(ItemsPerPage));
|
||||
} else if (optional) {
|
||||
m.appendReplacement(query, "");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
m.appendReplacement(query, String.valueOf(ItemsPerPage));
|
||||
} else if (optional) {
|
||||
m.appendReplacement(query, "");
|
||||
} else if (name == "startIndex") {
|
||||
|
|
|
@ -30,15 +30,12 @@ import org.geometerplus.zlibrary.core.xml.ZLStringMap;
|
|||
import org.geometerplus.zlibrary.core.xml.ZLXMLReaderAdapter;
|
||||
|
||||
class OpenSearchXMLReader extends ZLXMLReaderAdapter {
|
||||
|
||||
private final List<OpenSearchDescription> myDescriptions;
|
||||
private final int myItemsPerPage;
|
||||
|
||||
private final String myBaseURL;
|
||||
|
||||
public OpenSearchXMLReader(String baseUrl, List<OpenSearchDescription> descriptions, int itemsPerPage) {
|
||||
public OpenSearchXMLReader(String baseUrl, List<OpenSearchDescription> descriptions) {
|
||||
myDescriptions = descriptions;
|
||||
myItemsPerPage = itemsPerPage;
|
||||
myBaseURL = baseUrl;
|
||||
}
|
||||
|
||||
|
@ -115,7 +112,7 @@ class OpenSearchXMLReader extends ZLXMLReaderAdapter {
|
|||
final int indexOffset = parseInt(attributes.getValue("indexOffset"));
|
||||
final int pageOffset = parseInt(attributes.getValue("pageOffset"));
|
||||
final OpenSearchDescription descr =
|
||||
new OpenSearchDescription(template, myItemsPerPage, indexOffset, pageOffset);
|
||||
new OpenSearchDescription(template, indexOffset, pageOffset);
|
||||
if (descr.isValid()) {
|
||||
myDescriptions.add(descr);
|
||||
}
|
||||
|
|
|
@ -17,20 +17,16 @@
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
package org.geometerplus.fbreader.network.tree;
|
||||
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
|
||||
import org.geometerplus.zlibrary.ui.android.R;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
import org.geometerplus.fbreader.network.NetworkItem;
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
|
||||
import org.geometerplus.android.fbreader.tree.ZLAndroidTree;
|
||||
|
||||
public class AddCustomCatalogItemTree extends NetworkTree implements ZLAndroidTree {
|
||||
public AddCustomCatalogItemTree() {
|
||||
super(1);
|
||||
public class AddCustomCatalogItemTree extends NetworkTree {
|
||||
public AddCustomCatalogItemTree(NetworkTree parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,11 +40,12 @@ public class AddCustomCatalogItemTree extends NetworkTree implements ZLAndroidTr
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCoverResourceId() {
|
||||
return R.drawable.ic_list_plus;
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Add Custom Catalog";
|
||||
}
|
||||
}
|
|
@ -120,7 +120,12 @@ public class NetworkAuthorTree extends NetworkTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Author:" + Author.DisplayName + ":" + Author.SortKey;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,12 @@ public class NetworkBookTree extends NetworkTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return Book;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Book:" + Book.Id + ":" + Book.Title;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,7 @@ package org.geometerplus.fbreader.network.tree;
|
|||
import org.geometerplus.fbreader.network.*;
|
||||
|
||||
public class NetworkCatalogRootTree extends NetworkCatalogTree {
|
||||
|
||||
public NetworkCatalogRootTree(RootTree parent, INetworkLink link, int position) {
|
||||
super(parent, (NetworkCatalogItem) link.libraryItem(), position);
|
||||
super(parent, (NetworkCatalogItem)link.libraryItem(), position);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@ import org.geometerplus.fbreader.tree.FBTree;
|
|||
import org.geometerplus.fbreader.network.*;
|
||||
|
||||
public class NetworkCatalogTree extends NetworkTree {
|
||||
|
||||
public final NetworkCatalogItem Item;
|
||||
public final ArrayList<NetworkLibraryItem> ChildrenItems = new ArrayList<NetworkLibraryItem>();
|
||||
public final ArrayList<NetworkItem> ChildrenItems = new ArrayList<NetworkItem>();
|
||||
|
||||
private long myLoadedTime = -1;
|
||||
|
||||
|
@ -62,7 +61,6 @@ public class NetworkCatalogTree extends NetworkTree {
|
|||
return createCover(Item);
|
||||
}
|
||||
|
||||
|
||||
public boolean isContentValid() {
|
||||
if (myLoadedTime < 0) {
|
||||
return false;
|
||||
|
@ -80,7 +78,6 @@ public class NetworkCatalogTree extends NetworkTree {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateVisibility() {
|
||||
final LinkedList<FBTree> toRemove = new LinkedList<FBTree>();
|
||||
|
||||
|
@ -89,7 +86,7 @@ public class NetworkCatalogTree extends NetworkTree {
|
|||
int nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < ChildrenItems.size(); ++i) {
|
||||
NetworkLibraryItem currentItem = ChildrenItems.get(i);
|
||||
NetworkItem currentItem = ChildrenItems.get(i);
|
||||
if (!(currentItem instanceof NetworkCatalogItem)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -161,13 +158,18 @@ public class NetworkCatalogTree extends NetworkTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return Item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||
public void removeItems(Set<NetworkItem> items) {
|
||||
ChildrenItems.removeAll(items);
|
||||
super.removeItems(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return Item.getFullRequestString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,15 +87,20 @@ public class NetworkSeriesTree extends NetworkTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItems(Set<NetworkLibraryItem> items) {
|
||||
public void removeItems(Set<NetworkItem> items) {
|
||||
super.removeItems(items);
|
||||
if (subTrees().isEmpty()) {
|
||||
removeSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Series:" + SeriesTitle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import org.geometerplus.fbreader.network.*;
|
|||
|
||||
public class NetworkTreeFactory {
|
||||
|
||||
public static NetworkTree createNetworkTree(NetworkCatalogTree parent, NetworkLibraryItem item) {
|
||||
public static NetworkTree createNetworkTree(NetworkCatalogTree parent, NetworkItem item) {
|
||||
return createNetworkTree(parent, item, -1);
|
||||
}
|
||||
|
||||
public static NetworkTree createNetworkTree(NetworkCatalogTree parent, NetworkLibraryItem item, int position) {
|
||||
public static NetworkTree createNetworkTree(NetworkCatalogTree parent, NetworkItem item, int position) {
|
||||
final int subtreesSize = parent.subTrees().size();
|
||||
if (position == -1) {
|
||||
position = subtreesSize;
|
||||
|
@ -80,6 +80,8 @@ public class NetworkTreeFactory {
|
|||
}
|
||||
|
||||
return new NetworkBookTree(parent, book, position, showAuthors);
|
||||
} else if (item instanceof TopUpItem) {
|
||||
return new TopUpTree(parent, (TopUpItem)item);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
package org.geometerplus.fbreader.network.tree;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
import org.geometerplus.fbreader.network.NetworkItem;
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
|
||||
public final class RootTree extends NetworkTree {
|
||||
|
@ -29,7 +29,12 @@ public final class RootTree extends NetworkTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Root";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
package org.geometerplus.fbreader.network.tree;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.LinkedList;
|
||||
|
@ -29,16 +29,11 @@ import org.geometerplus.fbreader.tree.FBTree;
|
|||
import org.geometerplus.fbreader.network.*;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkAuthorTree;
|
||||
|
||||
import org.geometerplus.zlibrary.ui.android.R;
|
||||
|
||||
import org.geometerplus.android.fbreader.tree.ZLAndroidTree;
|
||||
|
||||
public class SearchItemTree extends NetworkTree implements ZLAndroidTree {
|
||||
|
||||
public class SearchItemTree extends NetworkTree {
|
||||
private SearchResult myResult;
|
||||
|
||||
public SearchItemTree() {
|
||||
super(1);
|
||||
public SearchItemTree(NetworkTree parent, int position) {
|
||||
super(parent, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,10 +46,6 @@ public class SearchItemTree extends NetworkTree implements ZLAndroidTree {
|
|||
return ZLResource.resource("networkView").getResource("searchSummary").getValue();
|
||||
}
|
||||
|
||||
public int getCoverResourceId() {
|
||||
return R.drawable.ic_list_searchresult;
|
||||
}
|
||||
|
||||
public void setSearchResult(SearchResult result) {
|
||||
myResult = result;
|
||||
clear();
|
||||
|
@ -99,7 +90,12 @@ public class SearchItemTree extends NetworkTree implements ZLAndroidTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
public NetworkItem getHoldedItem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@Search";
|
||||
}
|
||||
}
|
|
@ -17,47 +17,36 @@
|
|||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
package org.geometerplus.fbreader.network.tree;
|
||||
|
||||
import org.geometerplus.zlibrary.core.image.ZLImage;
|
||||
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
|
||||
import org.geometerplus.zlibrary.core.resources.ZLResource;
|
||||
|
||||
import org.geometerplus.fbreader.network.INetworkLink;
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
import org.geometerplus.fbreader.network.TopUpItem;
|
||||
import org.geometerplus.fbreader.network.NetworkTree;
|
||||
import org.geometerplus.fbreader.network.tree.NetworkCatalogTree;
|
||||
import org.geometerplus.fbreader.network.authentication.NetworkAuthenticationManager;
|
||||
|
||||
import org.geometerplus.zlibrary.ui.android.R;
|
||||
public class TopUpTree extends NetworkTree {
|
||||
public final TopUpItem Item;
|
||||
|
||||
import org.geometerplus.android.fbreader.tree.ZLAndroidTree;
|
||||
|
||||
class RefillAccountTree extends NetworkTree implements ZLAndroidTree {
|
||||
public final INetworkLink Link;
|
||||
|
||||
public RefillAccountTree(NetworkCatalogTree parentTree) {
|
||||
super(parentTree.Level + 1);
|
||||
Link = parentTree.Item.Link;
|
||||
}
|
||||
|
||||
public RefillAccountTree(INetworkLink link) {
|
||||
super(1);
|
||||
Link = link;
|
||||
TopUpTree(NetworkCatalogTree parentTree, TopUpItem item) {
|
||||
super(parentTree);
|
||||
Item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ZLResource.resource("networkView").getResource("refillTitle").getValue();
|
||||
return Item.Title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSummary() {
|
||||
final NetworkAuthenticationManager mgr = Link.authenticationManager();
|
||||
final NetworkAuthenticationManager mgr = Item.Link.authenticationManager();
|
||||
try {
|
||||
if (mgr.isAuthorised(false)) {
|
||||
final String account = mgr.currentAccount();
|
||||
if (account != null) {
|
||||
return ZLResource.resource("networkView").getResource("refillSummary").getValue().replace("%s", account);
|
||||
return Item.Summary.replace("%s", account);
|
||||
}
|
||||
}
|
||||
} catch (ZLNetworkException e) {
|
||||
|
@ -66,11 +55,17 @@ class RefillAccountTree extends NetworkTree implements ZLAndroidTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NetworkLibraryItem getHoldedItem() {
|
||||
return null;
|
||||
protected ZLImage createCover() {
|
||||
return createCover(Item);
|
||||
}
|
||||
|
||||
public int getCoverResourceId() {
|
||||
return R.drawable.ic_list_library_wallet;
|
||||
@Override
|
||||
public TopUpItem getHoldedItem() {
|
||||
return Item;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStringId() {
|
||||
return "@TopUp Account";
|
||||
}
|
||||
}
|
|
@ -29,10 +29,6 @@ public abstract class FBTree extends ZLTree<FBTree> implements Comparable<FBTree
|
|||
private ZLImage myCover;
|
||||
private boolean myCoverRequested;
|
||||
|
||||
protected FBTree(int level) {
|
||||
super(level);
|
||||
}
|
||||
|
||||
protected FBTree() {
|
||||
super();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public abstract class ZLBase64EncodedImage extends ZLSingleImage {
|
|||
try {
|
||||
decode();
|
||||
final File file = new File(decodedFileName());
|
||||
return "imagefile://" + decodedFileName() + "\0000\000" + (int)file.length();
|
||||
return ZLFileImage.SCHEME + "://" + decodedFileName() + "\0000\000" + (int)file.length();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import java.io.*;
|
|||
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
|
||||
|
||||
public class ZLFileImage extends ZLSingleImage {
|
||||
public static final String SCHEME = "imagefile";
|
||||
|
||||
private final ZLFile myFile;
|
||||
private final int myOffset;
|
||||
private final int myLength;
|
||||
|
@ -40,7 +42,7 @@ public class ZLFileImage extends ZLSingleImage {
|
|||
}
|
||||
|
||||
public String getURI() {
|
||||
return "imagefile://" + myFile.getPath() + "\000" + myOffset + "\000" + myLength;
|
||||
return SCHEME + "://" + myFile.getPath() + "\000" + myOffset + "\000" + myLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2007-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.zlibrary.core.options;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ZLStringListOption extends ZLOption {
|
||||
private final List<String> myDefaultValue;
|
||||
private List<String> myValue;
|
||||
|
||||
private static String listToString(List<String> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String s : list) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append(s);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static List<String> stringToList(String str) {
|
||||
if (str == null || "".equals(str)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.asList(str.split(","));
|
||||
}
|
||||
|
||||
public ZLStringListOption(String group, String optionName, List<String> defaultValue) {
|
||||
super(group, optionName);
|
||||
myDefaultValue = (defaultValue != null) ? defaultValue : Collections.<String>emptyList();
|
||||
myValue = myDefaultValue;
|
||||
}
|
||||
|
||||
public List<String> getValue() {
|
||||
if (!myIsSynchronized) {
|
||||
final String value = getConfigValue(listToString(myDefaultValue));
|
||||
if (value != null) {
|
||||
myValue = stringToList(value);
|
||||
}
|
||||
myIsSynchronized = true;
|
||||
}
|
||||
return Collections.unmodifiableList(myValue);
|
||||
}
|
||||
|
||||
public void setValue(List<String> value) {
|
||||
if (value == null) {
|
||||
value = Collections.emptyList();
|
||||
}
|
||||
if (myIsSynchronized && (myValue.equals(value))) {
|
||||
return;
|
||||
}
|
||||
myValue = new ArrayList<String>(value);
|
||||
if (value.equals(myDefaultValue)) {
|
||||
unsetConfigValue();
|
||||
} else {
|
||||
setConfigValue(listToString(value));
|
||||
}
|
||||
myIsSynchronized = true;
|
||||
}
|
||||
}
|
|
@ -27,10 +27,6 @@ public abstract class ZLTree<T extends ZLTree<T>> implements Iterable<T> {
|
|||
public final int Level;
|
||||
private ArrayList<T> mySubTrees;
|
||||
|
||||
protected ZLTree(int level) {
|
||||
this(level, null, 0);
|
||||
}
|
||||
|
||||
protected ZLTree() {
|
||||
this(null);
|
||||
}
|
||||
|
@ -40,10 +36,6 @@ public abstract class ZLTree<T extends ZLTree<T>> implements Iterable<T> {
|
|||
}
|
||||
|
||||
protected ZLTree(T parent, int position) {
|
||||
this(0, parent, position);
|
||||
}
|
||||
|
||||
private ZLTree(int nullLevel, T parent, int position) {
|
||||
if (parent != null && (position < 0 || position > parent.subTrees().size())) {
|
||||
throw new IndexOutOfBoundsException("`position` value equals " + position + " but must be in range [0; " + parent.subTrees().size() + "]");
|
||||
}
|
||||
|
@ -52,7 +44,7 @@ public abstract class ZLTree<T extends ZLTree<T>> implements Iterable<T> {
|
|||
Level = parent.Level + 1;
|
||||
parent.addSubTree((T)this, position);
|
||||
} else {
|
||||
Level = nullLevel;
|
||||
Level = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ public abstract class ZLMiscUtil {
|
|||
return (o0 == null) ? (o1 == null) : o0.equals(o1);
|
||||
}
|
||||
|
||||
public static int hashCode(Object o) {
|
||||
return o != null ? o.hashCode() : 0;
|
||||
}
|
||||
|
||||
public static <T> boolean listsEquals(List<T> list1, List<T> list2) {
|
||||
if (list1 == null) {
|
||||
return list2 == null || list2.isEmpty();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue