commit 4a0a235eda717d33502be54c17bf4b848bc6acc1
Author: Eric Kok
Date: Thu Dec 15 11:39:19 2011 +0100
Initial import of source, both android and lib projects from original SVN revision 377
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..e963df82
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,622 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/README b/README
new file mode 100644
index 00000000..6c9f6040
--- /dev/null
+++ b/README
@@ -0,0 +1,37 @@
+
+Transdroid - http://www.transdroid.org
+"Manage your torrents from your Android device"
+
+---
+
+Transdroid 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 3 of the License, or
+(at your option) any later version.
+
+Transdroid 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 Transdroid. If not, see .
+
+---
+
+Some code/libraries are used in the project:
+ Base16Encoder (Apache OpenJPA)
+ Marc Prud'hommeaux (Apache License, Version 2.0)
+ MultipartEntity (AOSP)
+ Apache Software Foundation (Apache License, Version 2.0)
+ http://source.android.com/
+ RssParser (learning-android)
+ Tane Piper (Public Domain)
+ http://github.com/digitalspaghetti/learning-android
+ Base64
+ Robert Harder (Public Domain)
+ http://iharder.net/base64
+ android-xmlrpc
+ pskink et al. (Apache License, Version 2.0)
+ http://code.google.com/p/android-xmlrpc/
+
diff --git a/android/.classpath b/android/.classpath
new file mode 100644
index 00000000..1c9c5691
--- /dev/null
+++ b/android/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/.project b/android/.project
new file mode 100644
index 00000000..7da03a1f
--- /dev/null
+++ b/android/.project
@@ -0,0 +1,33 @@
+
+
+ Transdroid
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/android/.settings/org.eclipse.jdt.core.prefs b/android/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..b3b3a814
--- /dev/null
+++ b/android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Sun May 23 15:44:48 CEST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100644
index 00000000..dd478a09
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/project.properties b/android/project.properties
new file mode 100644
index 00000000..9575abaf
--- /dev/null
+++ b/android/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-13
+apk-configurations=
+android.library.reference.1=../JakeWharton-ActionBarSherlock/library
diff --git a/android/res/anim/grow_from_bottom.xml b/android/res/anim/grow_from_bottom.xml
new file mode 100644
index 00000000..d2a371d1
--- /dev/null
+++ b/android/res/anim/grow_from_bottom.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/anim/grow_from_top.xml b/android/res/anim/grow_from_top.xml
new file mode 100644
index 00000000..ffd722c3
--- /dev/null
+++ b/android/res/anim/grow_from_top.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/anim/grow_from_topleft_to_bottomright.xml b/android/res/anim/grow_from_topleft_to_bottomright.xml
new file mode 100644
index 00000000..b67ebe5e
--- /dev/null
+++ b/android/res/anim/grow_from_topleft_to_bottomright.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/anim/shrink_from_bottom.xml b/android/res/anim/shrink_from_bottom.xml
new file mode 100644
index 00000000..a98d592a
--- /dev/null
+++ b/android/res/anim/shrink_from_bottom.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/anim/shrink_from_bottomright_to_topleft.xml b/android/res/anim/shrink_from_bottomright_to_topleft.xml
new file mode 100644
index 00000000..d4ed5134
--- /dev/null
+++ b/android/res/anim/shrink_from_bottomright_to_topleft.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/anim/shrink_from_top.xml b/android/res/anim/shrink_from_top.xml
new file mode 100644
index 00000000..89cd8f4f
--- /dev/null
+++ b/android/res/anim/shrink_from_top.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/android/res/drawable-hdpi-v9/icon_notification.png b/android/res/drawable-hdpi-v9/icon_notification.png
new file mode 100644
index 00000000..8a0f5986
Binary files /dev/null and b/android/res/drawable-hdpi-v9/icon_notification.png differ
diff --git a/android/res/drawable-hdpi/checkbox_off.png b/android/res/drawable-hdpi/checkbox_off.png
new file mode 100644
index 00000000..6782a2c6
Binary files /dev/null and b/android/res/drawable-hdpi/checkbox_off.png differ
diff --git a/android/res/drawable-hdpi/checkbox_on.png b/android/res/drawable-hdpi/checkbox_on.png
new file mode 100644
index 00000000..e1327989
Binary files /dev/null and b/android/res/drawable-hdpi/checkbox_on.png differ
diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png
new file mode 100644
index 00000000..bb8449f4
Binary files /dev/null and b/android/res/drawable-hdpi/icon.png differ
diff --git a/android/res/drawable-hdpi/icon_barcode.png b/android/res/drawable-hdpi/icon_barcode.png
new file mode 100644
index 00000000..5fe4249f
Binary files /dev/null and b/android/res/drawable-hdpi/icon_barcode.png differ
diff --git a/android/res/drawable-hdpi/icon_mark.png b/android/res/drawable-hdpi/icon_mark.png
new file mode 100644
index 00000000..e4cd4fdc
Binary files /dev/null and b/android/res/drawable-hdpi/icon_mark.png differ
diff --git a/android/res/drawable-hdpi/icon_new.png b/android/res/drawable-hdpi/icon_new.png
new file mode 100644
index 00000000..b2e89d3f
Binary files /dev/null and b/android/res/drawable-hdpi/icon_new.png differ
diff --git a/android/res/drawable-hdpi/icon_notification.png b/android/res/drawable-hdpi/icon_notification.png
new file mode 100644
index 00000000..00a517c2
Binary files /dev/null and b/android/res/drawable-hdpi/icon_notification.png differ
diff --git a/android/res/drawable-hdpi/icon_notnew.png b/android/res/drawable-hdpi/icon_notnew.png
new file mode 100644
index 00000000..7ca1d69c
Binary files /dev/null and b/android/res/drawable-hdpi/icon_notnew.png differ
diff --git a/android/res/drawable-hdpi/icon_pause.png b/android/res/drawable-hdpi/icon_pause.png
new file mode 100644
index 00000000..86792c0c
Binary files /dev/null and b/android/res/drawable-hdpi/icon_pause.png differ
diff --git a/android/res/drawable-hdpi/icon_priority_high.png b/android/res/drawable-hdpi/icon_priority_high.png
new file mode 100644
index 00000000..43dd253b
Binary files /dev/null and b/android/res/drawable-hdpi/icon_priority_high.png differ
diff --git a/android/res/drawable-hdpi/icon_priority_low.png b/android/res/drawable-hdpi/icon_priority_low.png
new file mode 100644
index 00000000..fa8e7bfb
Binary files /dev/null and b/android/res/drawable-hdpi/icon_priority_low.png differ
diff --git a/android/res/drawable-hdpi/icon_priority_normal.png b/android/res/drawable-hdpi/icon_priority_normal.png
new file mode 100644
index 00000000..b59edc02
Binary files /dev/null and b/android/res/drawable-hdpi/icon_priority_normal.png differ
diff --git a/android/res/drawable-hdpi/icon_priority_off.png b/android/res/drawable-hdpi/icon_priority_off.png
new file mode 100644
index 00000000..e44ea25a
Binary files /dev/null and b/android/res/drawable-hdpi/icon_priority_off.png differ
diff --git a/android/res/drawable-hdpi/icon_refresh.png b/android/res/drawable-hdpi/icon_refresh.png
new file mode 100644
index 00000000..1ec27822
Binary files /dev/null and b/android/res/drawable-hdpi/icon_refresh.png differ
diff --git a/android/res/drawable-hdpi/icon_refresh_title.png b/android/res/drawable-hdpi/icon_refresh_title.png
new file mode 100644
index 00000000..08c32e09
Binary files /dev/null and b/android/res/drawable-hdpi/icon_refresh_title.png differ
diff --git a/android/res/drawable-hdpi/icon_remove.png b/android/res/drawable-hdpi/icon_remove.png
new file mode 100644
index 00000000..76362cd1
Binary files /dev/null and b/android/res/drawable-hdpi/icon_remove.png differ
diff --git a/android/res/drawable-hdpi/icon_resume.png b/android/res/drawable-hdpi/icon_resume.png
new file mode 100644
index 00000000..e314e254
Binary files /dev/null and b/android/res/drawable-hdpi/icon_resume.png differ
diff --git a/android/res/drawable-hdpi/icon_rss.png b/android/res/drawable-hdpi/icon_rss.png
new file mode 100644
index 00000000..d3014112
Binary files /dev/null and b/android/res/drawable-hdpi/icon_rss.png differ
diff --git a/android/res/drawable-hdpi/icon_search_title.png b/android/res/drawable-hdpi/icon_search_title.png
new file mode 100644
index 00000000..59de344e
Binary files /dev/null and b/android/res/drawable-hdpi/icon_search_title.png differ
diff --git a/android/res/drawable-hdpi/icon_setlabel.png b/android/res/drawable-hdpi/icon_setlabel.png
new file mode 100644
index 00000000..c8c3078b
Binary files /dev/null and b/android/res/drawable-hdpi/icon_setlabel.png differ
diff --git a/android/res/drawable-hdpi/icon_showall.png b/android/res/drawable-hdpi/icon_showall.png
new file mode 100644
index 00000000..1c3946d1
Binary files /dev/null and b/android/res/drawable-hdpi/icon_showall.png differ
diff --git a/android/res/drawable-hdpi/icon_showdl.png b/android/res/drawable-hdpi/icon_showdl.png
new file mode 100644
index 00000000..d9768d74
Binary files /dev/null and b/android/res/drawable-hdpi/icon_showdl.png differ
diff --git a/android/res/drawable-hdpi/icon_showinactive.png b/android/res/drawable-hdpi/icon_showinactive.png
new file mode 100644
index 00000000..e70fbfb1
Binary files /dev/null and b/android/res/drawable-hdpi/icon_showinactive.png differ
diff --git a/android/res/drawable-hdpi/icon_showup.png b/android/res/drawable-hdpi/icon_showup.png
new file mode 100644
index 00000000..97e702fa
Binary files /dev/null and b/android/res/drawable-hdpi/icon_showup.png differ
diff --git a/android/res/drawable-hdpi/icon_start.png b/android/res/drawable-hdpi/icon_start.png
new file mode 100644
index 00000000..1e5ee9fd
Binary files /dev/null and b/android/res/drawable-hdpi/icon_start.png differ
diff --git a/android/res/drawable-hdpi/icon_start_menu.png b/android/res/drawable-hdpi/icon_start_menu.png
new file mode 100644
index 00000000..33661bc2
Binary files /dev/null and b/android/res/drawable-hdpi/icon_start_menu.png differ
diff --git a/android/res/drawable-hdpi/icon_stop.png b/android/res/drawable-hdpi/icon_stop.png
new file mode 100644
index 00000000..bb3cad47
Binary files /dev/null and b/android/res/drawable-hdpi/icon_stop.png differ
diff --git a/android/res/drawable-hdpi/icon_trackers.png b/android/res/drawable-hdpi/icon_trackers.png
new file mode 100644
index 00000000..8cf962d5
Binary files /dev/null and b/android/res/drawable-hdpi/icon_trackers.png differ
diff --git a/android/res/drawable-hdpi/icon_turtle_title.png b/android/res/drawable-hdpi/icon_turtle_title.png
new file mode 100644
index 00000000..4032c5fd
Binary files /dev/null and b/android/res/drawable-hdpi/icon_turtle_title.png differ
diff --git a/android/res/drawable-hdpi/quickaction_arrow_down.png b/android/res/drawable-hdpi/quickaction_arrow_down.png
new file mode 100644
index 00000000..718db624
Binary files /dev/null and b/android/res/drawable-hdpi/quickaction_arrow_down.png differ
diff --git a/android/res/drawable-hdpi/quickaction_arrow_up.png b/android/res/drawable-hdpi/quickaction_arrow_up.png
new file mode 100644
index 00000000..f876f40e
Binary files /dev/null and b/android/res/drawable-hdpi/quickaction_arrow_up.png differ
diff --git a/android/res/drawable-hdpi/quickaction_bottom_frame.9.png b/android/res/drawable-hdpi/quickaction_bottom_frame.9.png
new file mode 100644
index 00000000..50749da2
Binary files /dev/null and b/android/res/drawable-hdpi/quickaction_bottom_frame.9.png differ
diff --git a/android/res/drawable-hdpi/quickaction_slider_btn_on.9.png b/android/res/drawable-hdpi/quickaction_slider_btn_on.9.png
new file mode 100644
index 00000000..c0165a66
Binary files /dev/null and b/android/res/drawable-hdpi/quickaction_slider_btn_on.9.png differ
diff --git a/android/res/drawable-hdpi/quickaction_top_frame.9.png b/android/res/drawable-hdpi/quickaction_top_frame.9.png
new file mode 100644
index 00000000..8b6543e3
Binary files /dev/null and b/android/res/drawable-hdpi/quickaction_top_frame.9.png differ
diff --git a/android/res/drawable-hdpi/widget_black.9.png b/android/res/drawable-hdpi/widget_black.9.png
new file mode 100644
index 00000000..cd9df8da
Binary files /dev/null and b/android/res/drawable-hdpi/widget_black.9.png differ
diff --git a/android/res/drawable-hdpi/widget_icon_corner.png b/android/res/drawable-hdpi/widget_icon_corner.png
new file mode 100644
index 00000000..e8153dc6
Binary files /dev/null and b/android/res/drawable-hdpi/widget_icon_corner.png differ
diff --git a/android/res/drawable-hdpi/widget_refresh_corner.png b/android/res/drawable-hdpi/widget_refresh_corner.png
new file mode 100644
index 00000000..9ea102d2
Binary files /dev/null and b/android/res/drawable-hdpi/widget_refresh_corner.png differ
diff --git a/android/res/drawable-hdpi/widget_rss.png b/android/res/drawable-hdpi/widget_rss.png
new file mode 100644
index 00000000..1679ab05
Binary files /dev/null and b/android/res/drawable-hdpi/widget_rss.png differ
diff --git a/android/res/drawable-v9/icon_notification.png b/android/res/drawable-v9/icon_notification.png
new file mode 100644
index 00000000..4dd85acc
Binary files /dev/null and b/android/res/drawable-v9/icon_notification.png differ
diff --git a/android/res/drawable-xlarge-hdpi/icon_add.png b/android/res/drawable-xlarge-hdpi/icon_add.png
new file mode 100644
index 00000000..d7d6736b
Binary files /dev/null and b/android/res/drawable-xlarge-hdpi/icon_add.png differ
diff --git a/android/res/drawable-xlarge-hdpi/icon_barcode.png b/android/res/drawable-xlarge-hdpi/icon_barcode.png
new file mode 100644
index 00000000..f486b394
Binary files /dev/null and b/android/res/drawable-xlarge-hdpi/icon_barcode.png differ
diff --git a/android/res/drawable-xlarge-hdpi/icon_notification.png b/android/res/drawable-xlarge-hdpi/icon_notification.png
new file mode 100644
index 00000000..731f5c3b
Binary files /dev/null and b/android/res/drawable-xlarge-hdpi/icon_notification.png differ
diff --git a/android/res/drawable-xlarge-hdpi/icon_refresh_title.png b/android/res/drawable-xlarge-hdpi/icon_refresh_title.png
new file mode 100644
index 00000000..426ed7a1
Binary files /dev/null and b/android/res/drawable-xlarge-hdpi/icon_refresh_title.png differ
diff --git a/android/res/drawable-xlarge-hdpi/icon_search_title.png b/android/res/drawable-xlarge-hdpi/icon_search_title.png
new file mode 100644
index 00000000..9132afd7
Binary files /dev/null and b/android/res/drawable-xlarge-hdpi/icon_search_title.png differ
diff --git a/android/res/drawable/checkbox_off.png b/android/res/drawable/checkbox_off.png
new file mode 100644
index 00000000..5224f9d2
Binary files /dev/null and b/android/res/drawable/checkbox_off.png differ
diff --git a/android/res/drawable/checkbox_on.png b/android/res/drawable/checkbox_on.png
new file mode 100644
index 00000000..2c44c4d3
Binary files /dev/null and b/android/res/drawable/checkbox_on.png differ
diff --git a/android/res/drawable/controlbar_button.xml b/android/res/drawable/controlbar_button.xml
new file mode 100644
index 00000000..963a2f88
--- /dev/null
+++ b/android/res/drawable/controlbar_button.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png
new file mode 100644
index 00000000..88fb5bd7
Binary files /dev/null and b/android/res/drawable/icon.png differ
diff --git a/android/res/drawable/icon_mark.png b/android/res/drawable/icon_mark.png
new file mode 100644
index 00000000..c9c275d8
Binary files /dev/null and b/android/res/drawable/icon_mark.png differ
diff --git a/android/res/drawable/icon_new.png b/android/res/drawable/icon_new.png
new file mode 100644
index 00000000..eaf182d0
Binary files /dev/null and b/android/res/drawable/icon_new.png differ
diff --git a/android/res/drawable/icon_notification.png b/android/res/drawable/icon_notification.png
new file mode 100644
index 00000000..4ca5720d
Binary files /dev/null and b/android/res/drawable/icon_notification.png differ
diff --git a/android/res/drawable/icon_notnew.png b/android/res/drawable/icon_notnew.png
new file mode 100644
index 00000000..32b1cd60
Binary files /dev/null and b/android/res/drawable/icon_notnew.png differ
diff --git a/android/res/drawable/icon_pause.png b/android/res/drawable/icon_pause.png
new file mode 100644
index 00000000..08130d88
Binary files /dev/null and b/android/res/drawable/icon_pause.png differ
diff --git a/android/res/drawable/icon_priority_high.png b/android/res/drawable/icon_priority_high.png
new file mode 100644
index 00000000..9c111042
Binary files /dev/null and b/android/res/drawable/icon_priority_high.png differ
diff --git a/android/res/drawable/icon_priority_low.png b/android/res/drawable/icon_priority_low.png
new file mode 100644
index 00000000..35198624
Binary files /dev/null and b/android/res/drawable/icon_priority_low.png differ
diff --git a/android/res/drawable/icon_priority_normal.png b/android/res/drawable/icon_priority_normal.png
new file mode 100644
index 00000000..5d42e8b5
Binary files /dev/null and b/android/res/drawable/icon_priority_normal.png differ
diff --git a/android/res/drawable/icon_priority_off.png b/android/res/drawable/icon_priority_off.png
new file mode 100644
index 00000000..dbd5b4e0
Binary files /dev/null and b/android/res/drawable/icon_priority_off.png differ
diff --git a/android/res/drawable/icon_refresh.png b/android/res/drawable/icon_refresh.png
new file mode 100644
index 00000000..c65f3cbb
Binary files /dev/null and b/android/res/drawable/icon_refresh.png differ
diff --git a/android/res/drawable/icon_refresh_title.png b/android/res/drawable/icon_refresh_title.png
new file mode 100644
index 00000000..587aa459
Binary files /dev/null and b/android/res/drawable/icon_refresh_title.png differ
diff --git a/android/res/drawable/icon_remove.png b/android/res/drawable/icon_remove.png
new file mode 100644
index 00000000..35e60560
Binary files /dev/null and b/android/res/drawable/icon_remove.png differ
diff --git a/android/res/drawable/icon_resume.png b/android/res/drawable/icon_resume.png
new file mode 100644
index 00000000..9cdbf17c
Binary files /dev/null and b/android/res/drawable/icon_resume.png differ
diff --git a/android/res/drawable/icon_rss.png b/android/res/drawable/icon_rss.png
new file mode 100644
index 00000000..3d631109
Binary files /dev/null and b/android/res/drawable/icon_rss.png differ
diff --git a/android/res/drawable/icon_search_title.png b/android/res/drawable/icon_search_title.png
new file mode 100644
index 00000000..396fba75
Binary files /dev/null and b/android/res/drawable/icon_search_title.png differ
diff --git a/android/res/drawable/icon_setlabel.png b/android/res/drawable/icon_setlabel.png
new file mode 100644
index 00000000..d2a87118
Binary files /dev/null and b/android/res/drawable/icon_setlabel.png differ
diff --git a/android/res/drawable/icon_showall.png b/android/res/drawable/icon_showall.png
new file mode 100644
index 00000000..d1e65a71
Binary files /dev/null and b/android/res/drawable/icon_showall.png differ
diff --git a/android/res/drawable/icon_showdl.png b/android/res/drawable/icon_showdl.png
new file mode 100644
index 00000000..79835469
Binary files /dev/null and b/android/res/drawable/icon_showdl.png differ
diff --git a/android/res/drawable/icon_showinactive.png b/android/res/drawable/icon_showinactive.png
new file mode 100644
index 00000000..6d6ddb16
Binary files /dev/null and b/android/res/drawable/icon_showinactive.png differ
diff --git a/android/res/drawable/icon_showup.png b/android/res/drawable/icon_showup.png
new file mode 100644
index 00000000..0e237877
Binary files /dev/null and b/android/res/drawable/icon_showup.png differ
diff --git a/android/res/drawable/icon_start.png b/android/res/drawable/icon_start.png
new file mode 100644
index 00000000..e7ac43f6
Binary files /dev/null and b/android/res/drawable/icon_start.png differ
diff --git a/android/res/drawable/icon_start_menu.png b/android/res/drawable/icon_start_menu.png
new file mode 100644
index 00000000..509ddedf
Binary files /dev/null and b/android/res/drawable/icon_start_menu.png differ
diff --git a/android/res/drawable/icon_stop.png b/android/res/drawable/icon_stop.png
new file mode 100644
index 00000000..2cb9d0b3
Binary files /dev/null and b/android/res/drawable/icon_stop.png differ
diff --git a/android/res/drawable/icon_trackers.png b/android/res/drawable/icon_trackers.png
new file mode 100644
index 00000000..57d46f62
Binary files /dev/null and b/android/res/drawable/icon_trackers.png differ
diff --git a/android/res/drawable/pixel.png b/android/res/drawable/pixel.png
new file mode 100644
index 00000000..5ffd6031
Binary files /dev/null and b/android/res/drawable/pixel.png differ
diff --git a/android/res/drawable/quickaction_arrow_down.png b/android/res/drawable/quickaction_arrow_down.png
new file mode 100644
index 00000000..6e8ee25a
Binary files /dev/null and b/android/res/drawable/quickaction_arrow_down.png differ
diff --git a/android/res/drawable/quickaction_arrow_up.png b/android/res/drawable/quickaction_arrow_up.png
new file mode 100644
index 00000000..b907d5bd
Binary files /dev/null and b/android/res/drawable/quickaction_arrow_up.png differ
diff --git a/android/res/drawable/quickaction_bottom_frame.9.png b/android/res/drawable/quickaction_bottom_frame.9.png
new file mode 100644
index 00000000..aa129b4e
Binary files /dev/null and b/android/res/drawable/quickaction_bottom_frame.9.png differ
diff --git a/android/res/drawable/quickaction_top_frame.9.png b/android/res/drawable/quickaction_top_frame.9.png
new file mode 100644
index 00000000..64207125
Binary files /dev/null and b/android/res/drawable/quickaction_top_frame.9.png differ
diff --git a/android/res/drawable/seedm8.png b/android/res/drawable/seedm8.png
new file mode 100644
index 00000000..a374e1cf
Binary files /dev/null and b/android/res/drawable/seedm8.png differ
diff --git a/android/res/drawable/seedm8_icon.png b/android/res/drawable/seedm8_icon.png
new file mode 100644
index 00000000..0cf7189c
Binary files /dev/null and b/android/res/drawable/seedm8_icon.png differ
diff --git a/android/res/drawable/seedm8_icon2.png b/android/res/drawable/seedm8_icon2.png
new file mode 100644
index 00000000..01e7c211
Binary files /dev/null and b/android/res/drawable/seedm8_icon2.png differ
diff --git a/android/res/drawable/small_checkbox.xml b/android/res/drawable/small_checkbox.xml
new file mode 100644
index 00000000..c2987705
--- /dev/null
+++ b/android/res/drawable/small_checkbox.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/drawable/title_button.xml b/android/res/drawable/title_button.xml
new file mode 100644
index 00000000..963a2f88
--- /dev/null
+++ b/android/res/drawable/title_button.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/android/res/drawable/title_button_pressed.9.png b/android/res/drawable/title_button_pressed.9.png
new file mode 100644
index 00000000..b1afd4b6
Binary files /dev/null and b/android/res/drawable/title_button_pressed.9.png differ
diff --git a/android/res/drawable/title_button_selected.9.png b/android/res/drawable/title_button_selected.9.png
new file mode 100644
index 00000000..331f96f4
Binary files /dev/null and b/android/res/drawable/title_button_selected.9.png differ
diff --git a/android/res/drawable/widget_15_landscape.9.png b/android/res/drawable/widget_15_landscape.9.png
new file mode 100644
index 00000000..3fd2b85f
Binary files /dev/null and b/android/res/drawable/widget_15_landscape.9.png differ
diff --git a/android/res/drawable/widget_15_portrait.9.png b/android/res/drawable/widget_15_portrait.9.png
new file mode 100644
index 00000000..2f7fae3e
Binary files /dev/null and b/android/res/drawable/widget_15_portrait.9.png differ
diff --git a/android/res/drawable/widget_16.9.png b/android/res/drawable/widget_16.9.png
new file mode 100644
index 00000000..a33dca7b
Binary files /dev/null and b/android/res/drawable/widget_16.9.png differ
diff --git a/android/res/drawable/widget_16_line.png b/android/res/drawable/widget_16_line.png
new file mode 100644
index 00000000..5ba9b88a
Binary files /dev/null and b/android/res/drawable/widget_16_line.png differ
diff --git a/android/res/drawable/widget_black.9.png b/android/res/drawable/widget_black.9.png
new file mode 100644
index 00000000..3683de08
Binary files /dev/null and b/android/res/drawable/widget_black.9.png differ
diff --git a/android/res/drawable/widget_black_line.png b/android/res/drawable/widget_black_line.png
new file mode 100644
index 00000000..51d28c69
Binary files /dev/null and b/android/res/drawable/widget_black_line.png differ
diff --git a/android/res/drawable/widget_icon_corner.png b/android/res/drawable/widget_icon_corner.png
new file mode 100644
index 00000000..538023b0
Binary files /dev/null and b/android/res/drawable/widget_icon_corner.png differ
diff --git a/android/res/drawable/widget_qsb.9.png b/android/res/drawable/widget_qsb.9.png
new file mode 100644
index 00000000..85f45779
Binary files /dev/null and b/android/res/drawable/widget_qsb.9.png differ
diff --git a/android/res/drawable/widget_refresh.png b/android/res/drawable/widget_refresh.png
new file mode 100644
index 00000000..a4e5a7ad
Binary files /dev/null and b/android/res/drawable/widget_refresh.png differ
diff --git a/android/res/drawable/widget_refresh_corner.png b/android/res/drawable/widget_refresh_corner.png
new file mode 100644
index 00000000..a31339c7
Binary files /dev/null and b/android/res/drawable/widget_refresh_corner.png differ
diff --git a/android/res/drawable/widget_rss.png b/android/res/drawable/widget_rss.png
new file mode 100644
index 00000000..60879a3c
Binary files /dev/null and b/android/res/drawable/widget_rss.png differ
diff --git a/android/res/drawable/xirvik.png b/android/res/drawable/xirvik.png
new file mode 100644
index 00000000..7b52bb85
Binary files /dev/null and b/android/res/drawable/xirvik.png differ
diff --git a/android/res/drawable/xirvik_icon.png b/android/res/drawable/xirvik_icon.png
new file mode 100644
index 00000000..43150209
Binary files /dev/null and b/android/res/drawable/xirvik_icon.png differ
diff --git a/android/res/layout-land/appwidget_15.xml b/android/res/layout-land/appwidget_15.xml
new file mode 100644
index 00000000..6356f363
--- /dev/null
+++ b/android/res/layout-land/appwidget_15.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-land/appwidget_16.xml b/android/res/layout-land/appwidget_16.xml
new file mode 100644
index 00000000..eefae545
--- /dev/null
+++ b/android/res/layout-land/appwidget_16.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-land/appwidget_black.xml b/android/res/layout-land/appwidget_black.xml
new file mode 100644
index 00000000..1f66c2b6
--- /dev/null
+++ b/android/res/layout-land/appwidget_black.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-land/appwidget_qsb.xml b/android/res/layout-land/appwidget_qsb.xml
new file mode 100644
index 00000000..8f3ab964
--- /dev/null
+++ b/android/res/layout-land/appwidget_qsb.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-v14/list_item_seedbox_settings.xml b/android/res/layout-v14/list_item_seedbox_settings.xml
new file mode 100644
index 00000000..3bd1af3f
--- /dev/null
+++ b/android/res/layout-v14/list_item_seedbox_settings.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout-xlarge-port-v11/fragment_torrents.xml b/android/res/layout-xlarge-port-v11/fragment_torrents.xml
new file mode 100644
index 00000000..b775f09d
--- /dev/null
+++ b/android/res/layout-xlarge-port-v11/fragment_torrents.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-xlarge-v11/fragment_rssfeeds.xml b/android/res/layout-xlarge-v11/fragment_rssfeeds.xml
new file mode 100644
index 00000000..5bde0d94
--- /dev/null
+++ b/android/res/layout-xlarge-v11/fragment_rssfeeds.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout-xlarge-v11/fragment_torrents.xml b/android/res/layout-xlarge-v11/fragment_torrents.xml
new file mode 100644
index 00000000..3245217d
--- /dev/null
+++ b/android/res/layout-xlarge-v11/fragment_torrents.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout-xlarge-v11/part_actionbar_progressitem.xml b/android/res/layout-xlarge-v11/part_actionbar_progressitem.xml
new file mode 100644
index 00000000..e099ffbe
--- /dev/null
+++ b/android/res/layout-xlarge-v11/part_actionbar_progressitem.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout-xlarge-v11/part_details_header.xml b/android/res/layout-xlarge-v11/part_details_header.xml
new file mode 100644
index 00000000..274d4f70
--- /dev/null
+++ b/android/res/layout-xlarge-v11/part_details_header.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout-xlarge-v11/titlebar_progressitem.xml b/android/res/layout-xlarge-v11/titlebar_progressitem.xml
new file mode 100644
index 00000000..e9335771
--- /dev/null
+++ b/android/res/layout-xlarge-v11/titlebar_progressitem.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/abs__simple_spinner_item.xml b/android/res/layout/abs__simple_spinner_item.xml
new file mode 100644
index 00000000..9be5ea8d
--- /dev/null
+++ b/android/res/layout/abs__simple_spinner_item.xml
@@ -0,0 +1,26 @@
+
+
+
diff --git a/android/res/layout/activity_add.xml b/android/res/layout/activity_add.xml
new file mode 100644
index 00000000..5aef1d21
--- /dev/null
+++ b/android/res/layout/activity_add.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/activity_details.xml b/android/res/layout/activity_details.xml
new file mode 100644
index 00000000..324a657b
--- /dev/null
+++ b/android/res/layout/activity_details.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/activity_ezrss_feedbuilder.xml b/android/res/layout/activity_ezrss_feedbuilder.xml
new file mode 100644
index 00000000..4b3a0b5a
--- /dev/null
+++ b/android/res/layout/activity_ezrss_feedbuilder.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/activity_rssfeeds.xml b/android/res/layout/activity_rssfeeds.xml
new file mode 100644
index 00000000..56caf59b
--- /dev/null
+++ b/android/res/layout/activity_rssfeeds.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/activity_rsslisting.xml b/android/res/layout/activity_rsslisting.xml
new file mode 100644
index 00000000..7bd4cf94
--- /dev/null
+++ b/android/res/layout/activity_rsslisting.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/activity_search.xml b/android/res/layout/activity_search.xml
new file mode 100644
index 00000000..f9a7b3fe
--- /dev/null
+++ b/android/res/layout/activity_search.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/activity_serverselection.xml b/android/res/layout/activity_serverselection.xml
new file mode 100644
index 00000000..70f1c710
--- /dev/null
+++ b/android/res/layout/activity_serverselection.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/android/res/layout/activity_torrents.xml b/android/res/layout/activity_torrents.xml
new file mode 100644
index 00000000..d0d4f280
--- /dev/null
+++ b/android/res/layout/activity_torrents.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/android/res/layout/appwidget_15.xml b/android/res/layout/appwidget_15.xml
new file mode 100644
index 00000000..a35c7bf0
--- /dev/null
+++ b/android/res/layout/appwidget_15.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/appwidget_16.xml b/android/res/layout/appwidget_16.xml
new file mode 100644
index 00000000..8bd84ea6
--- /dev/null
+++ b/android/res/layout/appwidget_16.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/appwidget_black.xml b/android/res/layout/appwidget_black.xml
new file mode 100644
index 00000000..d0d4e711
--- /dev/null
+++ b/android/res/layout/appwidget_black.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/appwidget_qsb.xml b/android/res/layout/appwidget_qsb.xml
new file mode 100644
index 00000000..dfcfd2bc
--- /dev/null
+++ b/android/res/layout/appwidget_qsb.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/appwidget_small.xml b/android/res/layout/appwidget_small.xml
new file mode 100644
index 00000000..efaf245f
--- /dev/null
+++ b/android/res/layout/appwidget_small.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/appwidget_transparent.xml b/android/res/layout/appwidget_transparent.xml
new file mode 100644
index 00000000..d6be285c
--- /dev/null
+++ b/android/res/layout/appwidget_transparent.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/dialog_about.xml b/android/res/layout/dialog_about.xml
new file mode 100644
index 00000000..80b98338
--- /dev/null
+++ b/android/res/layout/dialog_about.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/dialog_edittrackers.xml b/android/res/layout/dialog_edittrackers.xml
new file mode 100644
index 00000000..d71f2116
--- /dev/null
+++ b/android/res/layout/dialog_edittrackers.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/android/res/layout/dialog_new_label.xml b/android/res/layout/dialog_new_label.xml
new file mode 100644
index 00000000..9dd184c3
--- /dev/null
+++ b/android/res/layout/dialog_new_label.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/dialog_seedm8_info.xml b/android/res/layout/dialog_seedm8_info.xml
new file mode 100644
index 00000000..fc14e197
--- /dev/null
+++ b/android/res/layout/dialog_seedm8_info.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/dialog_set_download_location.xml b/android/res/layout/dialog_set_download_location.xml
new file mode 100644
index 00000000..f30e84e5
--- /dev/null
+++ b/android/res/layout/dialog_set_download_location.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/android/res/layout/dialog_transfer_rates.xml b/android/res/layout/dialog_transfer_rates.xml
new file mode 100644
index 00000000..76e9cdd0
--- /dev/null
+++ b/android/res/layout/dialog_transfer_rates.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/dialog_xirvik_info.xml b/android/res/layout/dialog_xirvik_info.xml
new file mode 100644
index 00000000..f50cae62
--- /dev/null
+++ b/android/res/layout/dialog_xirvik_info.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/fragment_details.xml b/android/res/layout/fragment_details.xml
new file mode 100644
index 00000000..f7973b47
--- /dev/null
+++ b/android/res/layout/fragment_details.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/fragment_rssfeeds.xml b/android/res/layout/fragment_rssfeeds.xml
new file mode 100644
index 00000000..a7b20811
--- /dev/null
+++ b/android/res/layout/fragment_rssfeeds.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/fragment_rsslisting.xml b/android/res/layout/fragment_rsslisting.xml
new file mode 100644
index 00000000..24ba1cdc
--- /dev/null
+++ b/android/res/layout/fragment_rsslisting.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/fragment_torrents.xml b/android/res/layout/fragment_torrents.xml
new file mode 100644
index 00000000..4d404c5c
--- /dev/null
+++ b/android/res/layout/fragment_torrents.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/list_item_daemon_settings.xml b/android/res/layout/list_item_daemon_settings.xml
new file mode 100644
index 00000000..4b17d58a
--- /dev/null
+++ b/android/res/layout/list_item_daemon_settings.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_label.xml b/android/res/layout/list_item_label.xml
new file mode 100644
index 00000000..1ca0a814
--- /dev/null
+++ b/android/res/layout/list_item_label.xml
@@ -0,0 +1,26 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/list_item_preferences_divider.xml b/android/res/layout/list_item_preferences_divider.xml
new file mode 100644
index 00000000..03503637
--- /dev/null
+++ b/android/res/layout/list_item_preferences_divider.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/list_item_rssfeed.xml b/android/res/layout/list_item_rssfeed.xml
new file mode 100644
index 00000000..892a5425
--- /dev/null
+++ b/android/res/layout/list_item_rssfeed.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_rssitem.xml b/android/res/layout/list_item_rssitem.xml
new file mode 100644
index 00000000..0aa5872c
--- /dev/null
+++ b/android/res/layout/list_item_rssitem.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_search.xml b/android/res/layout/list_item_search.xml
new file mode 100644
index 00000000..6d2a469e
--- /dev/null
+++ b/android/res/layout/list_item_search.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_seedbox_pref.xml b/android/res/layout/list_item_seedbox_pref.xml
new file mode 100644
index 00000000..e1fa13e9
--- /dev/null
+++ b/android/res/layout/list_item_seedbox_pref.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/list_item_seedbox_settings.xml b/android/res/layout/list_item_seedbox_settings.xml
new file mode 100644
index 00000000..42e6c058
--- /dev/null
+++ b/android/res/layout/list_item_seedbox_settings.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_torrent.xml b/android/res/layout/list_item_torrent.xml
new file mode 100644
index 00000000..241b68da
--- /dev/null
+++ b/android/res/layout/list_item_torrent.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/list_item_torrentfile.xml b/android/res/layout/list_item_torrentfile.xml
new file mode 100644
index 00000000..c9312961
--- /dev/null
+++ b/android/res/layout/list_item_torrentfile.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/part_actionbar_progressitem.xml b/android/res/layout/part_actionbar_progressitem.xml
new file mode 100644
index 00000000..fe6f9ac2
--- /dev/null
+++ b/android/res/layout/part_actionbar_progressitem.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/part_controlbar.xml b/android/res/layout/part_controlbar.xml
new file mode 100644
index 00000000..3db484a4
--- /dev/null
+++ b/android/res/layout/part_controlbar.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/part_details_header.xml b/android/res/layout/part_details_header.xml
new file mode 100644
index 00000000..44d882cc
--- /dev/null
+++ b/android/res/layout/part_details_header.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/layout/part_quickaction.xml b/android/res/layout/part_quickaction.xml
new file mode 100644
index 00000000..95c0a69f
--- /dev/null
+++ b/android/res/layout/part_quickaction.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/values-ca/strings.xml b/android/res/values-ca/strings.xml
new file mode 100644
index 00000000..1622bc85
--- /dev/null
+++ b/android/res/values-ca/strings.xml
@@ -0,0 +1,155 @@
+
+
+
+Ets nou a Transdroid? Pots trobar ajuda per l'instal·lació a www.transdroid.org/download\n\nPer començar a servir via torrent, entra si us plau les dades el teu servidor:
+Desa
+Descarta
+Servidor torrent
+Encara no s'ha configurat cap servidor
+
+Mostra-ho tot
+Sense etiqueta
+Etiqueta nova
+Posar una etiqueta no està suportat pel teu client
+
+Canvi vista
+Es mostren tots els torrents
+Descarregant torrent
+Torrents inactius
+
+Afegeix
+Escaneja codi de barres
+RSS
+Canvia el servidor
+Estableix els ratis de transferència
+Fes-ho per tots
+Pausa-ho tot
+Reprén-ho tot
+Atura-ho tot
+Inicia-ho tot
+Ordena per (reordeneu per invertir l\'ordre)
+Nom
+Estat
+Data fet
+Data afegit
+Velocitat depujada
+Rati
+Només transferint (> 0KB/s)
+Configuració
+Quant a/Registre de canvis
+Informe d\'error
+Suprimeix
+Pausa
+Reprén
+Atura
+Inicia
+Força l\'inici
+Estable etiqueta...
+Estableix com a predeterminat
+
+Instal·la del Market
+
+S\'esta suprimint el torrent
+Esteu segur de voler suprimir aquest torrent?
+Afegeix després
+
+S\'està cercant...
+Torrents
+Ubuntu
+Baixa ara
+Obre el lloc web
+Obre amb...
+
+Afegeix un servidor nou
+
+Nom
+Tipus de servidor
+IP o nom de domini
+Port
+Nom d\'usuari
+Contrasenya
+SO del servidor
+Carpeta
+SSL
+
+Nombre de resultats
+Qualitat
+S\'està carregant...
+
+
+
+%1$s de %2$s (%3$s)
+↑ %1$s
+↓ %1$s
+Pausat
+Aturat
+Desconegut
+
+
+suprimit
+aturat
+pausat
+
+Detalls
+Fitxers
+Mida:
+Estat:
+Baixats:
+Pujats:
+Disponibilitat:
+Etiqueta:
+
+Normal
+
+Transdroid 4x1
+Transdroid 2x1
+Servidor
+Estil
+Afegeix aquest giny
+inactiu
+/s
+nou
+
+
+RSS
+
+
+Nom del servidor
+
+Nom del servidor
+jo
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+Sense actualització automàtica
+2 segons
+5 segons
+15 segons
+1 minut
+5 minuts
+15 minuts
+1 hora
+
+
+
+1 minut
+10 minuts
+30 minuts
+1 hora
+3 hores
+12 hores
+1 dia
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Black
+Transparent
+
+
diff --git a/android/res/values-cs/strings.xml b/android/res/values-cs/strings.xml
new file mode 100644
index 00000000..35e01bd7
--- /dev/null
+++ b/android/res/values-cs/strings.xml
@@ -0,0 +1,114 @@
+
+
+
+Nastavení
+Zkouším se připojit k serveru ...
+Připojen, ale na serveru není žádný torrent.
+Připojen, ale na serveru nejsou žádné stahované torrenty.
+Připojen, ale na serveru nejsou žádné seedováné torrenty.
+Připojen, ale na serveru nejsou žádné neaktivní torrenty.
+Váš torrent klient není podporován. Nahrání torrentu není implementováno.
+Váš torrent klient není podporován. Magnet link není implementováno.
+Uložit
+Zrušit
+Torrent server
+Není nastaven žádný server.
+
+Zobrazit vše
+Neoznačený
+Nový štítek
+Nastavení štítku není podporováno Vaším klientem
+
+Zobrazit všechny torrenty
+Zobrazit stahované torrenty
+Zobrazit seedováné torrenty
+Zobrazit neaktivní torrenty
+
+Přidat
+RSS
+Změnit server
+Nastavít rychlost
+Pro vše
+Pozastavit vše
+Obnovit vše
+Zastavit vše
+Spusti vše
+Filtry
+Řadit (změnít směr)
+Jmého
+Stav
+Datum dokončení
+Datum přidání
+Rychlost stahování
+Ratio
+Pouze běžící (> 0KB/s)
+Nastavení
+O / novinky
+Hlašení chyby
+Odebrat
+Odebrat a smazat data
+Pozastavit
+Obnovit
+Stop
+Start
+Vynuceny start
+Nastavít štítek...
+Nastavit umístění stahovaní
+Nastavit výchozí
+Výchozí stránka nastavena na
+Nahoru
+Dolu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-da/strings.xml b/android/res/values-da/strings.xml
new file mode 100644
index 00000000..8c1f2b1f
--- /dev/null
+++ b/android/res/values-da/strings.xml
@@ -0,0 +1,359 @@
+
+
+En torrentklient med integreret søgefunktionalitet, RSS support og overvågningswidget
+
+Åben indstillingsmenuen for at indstille din servers dæmondetaljer.
+Ny til Transdroid? Du kan installere hjælp på www.transdroid.org/download\n\nIndtast dine serverindstillinger for at starte:
+Åben indstillinger
+Forsøger at forbinde til serveren...
+Forbundet, men der er ingen torrents på serveren.
+Forbundet, men der er ingen torrents på serveren der bliver hentet.
+Forbundet, men der er ingen torrents der seeder på serveren.
+Forbundet, men der er ingen inaktive torrents på serveren.
+Dit torrentprogram har ikke understøttelse af .torrent filer eller det er ikke implementeret endnu.
+Dit torrent program har ikke understøttelse af .magnet links eller det er ikke implementeret endnu.
+Gem
+Annuller
+Torrentserver
+Der er ikke blevet konfigureret nogle servere endnu
+
+Vis alle
+Uden etiketter
+Ny etikette
+Etiketter er ikke understøttet af din klient
+
+Skift baggrund
+Viser alle torrents
+Viser torrents der hentes
+Viser torrents der seedes
+Viser inaktive torrents
+
+Tilføj
+Scan stregkode
+RSS
+Skift server
+Sæt overførselshastigheder
+Udfør alle
+Sæt alle på pause
+Genoptag alle
+Stop alle
+Start alle
+Filtrer liste
+Sorter efter
+Navn
+Status
+Dato færdig
+Dato tilføjet
+Uploadhastighed
+Forhold
+Kun sende (> 0 KB/s)
+Indstillinger
+Om/Ændringslog
+Fejlrapport
+Fjern
+Fjern og slet data
+Slet også data
+Pause
+Fortsæt
+Stop
+Start
+Tving start
+Set etiket...
+Angiv download placering
+Sæt som standard
+Standardside sat til
+Flyt op
+Flyt ned
+Rediger trackers
+Udeluk markeringen
+
+Indsæt torrentfilens URL
+Dit input er ikke en gyldig URL
+Vælge en lokal .torrent fil
+Der blev ikke fundet en understøttet filmanager, som f.eks. OI File Manager. Vil du installere en fra Android Marked?\n\nAlternativt kan du åbne en filmanager der ikke er understøttet og sende en .torrent fil til Transdroid.
+Installér fra marked
+Android Marked programmet er ikke installeret
+Programmet Barcode Scanner kunne ikke findes, vil du installere det fra Android Marked
+For at sende en fejlrapport er du nødt til at installere programmet Log Collector. Det er gratis og open-source. Vil du installere det fra Android Marked nu?
+Log Collector vil nu samle enhedsloggen og sende den til transdroid.org@gmail.com.\nDu vil have mulighed for at gennemse og ændre de data som bliver sendt.
+En fjern-filviser, så som VLC Remote, kunne ikke findes. Vil du installere det VLC Remote fra Android Marked?
+Du har ikke installere en kompatibel FTP klient.\nVil du installere AndFTP fra Android Marked?
+
+Maksimal downloadhastighed
+Maksimal uploadhastighed
+Kun talværdier i KB/sek
+Nulstil
+Din torrentklient understøtter ikke indstilling af overførelseshastigheder eller dette er endnu ikke implementeret.
+Overførselshastigheder er opdateret
+Fjerner torrent
+Er du sikker på du vil fjerne denne torrent?
+Fejl under tilføjelse
+% 1 $ s kunne ikke tilføjes nu. Vil du forsøge igen eller sætte den til automatisk at tilføje det senere?
+% 1 $ s kunne ikke tilføjes lige nu. Vil du prøve igen?
+Prøv igen
+Tilføj senere
+
+Søger...
+Søg efter torrents online
+Torrents
+Ubuntu
+Resultater fra
+Tilføj alle markerede
+Ingen resultater fundet udfra dine søgeord
+Ingen søgeord indtastet
+Skift side
+Download nu
+Åben hjemmeside
+Åben med...
+Del link...
+Gem som RSS feed
+Brug som ny søgning
+Søgning gemt som RSS feed
+Det er ikke muligt at gemme for denne side
+Torrent Search er nu et separat modul, hvilket betyder en engangs-installation fra Android Market. Installere det nu?
+
+Transdroidindstillinger
+Tilføj ny server
+Tilføj web søge side
+Tilføj RSS feed
+In-app søgning
+Web-baseret søgning
+Andre indstillinger
+
+Serverdæmon
+Basale indstillinger
+Navn
+Valgfrit personligt navn
+Servertype
+IP eller domænenavn
+Uden http:// og portnummer
+Port
+Er normalt
+Brug godkendelse
+Du vil få brug for brugernavn og kodeord
+Brugernavn
+Kodeord
+Server operativsystem
+SCGI mappe
+Er normalt /RPC2
+Mappe
+For eksempel /torrentflux
+Normalt tom
+Avancerede indstillinger
+Download mappe
+Den absolutte sti til downloadmappen på serveren
+Basis (S)FTP URL
+For eksempel ftp://mig@server.com/downloads/
+Forbindelse timeout
+Antallet af sekunder før timeout for et forbindelse forsøg
+SSL
+Vælg at bruge HTTPS
+Tillad kun forbindelser til dette særlige certifikat
+Accepter alle SSL certifikater
+Vælg hvis certifikatet er hjemmelavet
+
+Søgemaskine
+Indstil startside
+Direkte søge URL
+%1$s vil blive erstattet af dine søgeord
+Antal resultater
+Resultat sorteringsrækkefølge
+RSS feeds
+Feedindstillinger
+Feed URL
+Kræver godkendelse
+Åben links i browseren for at godkende
+ezRSS feed bygger
+Byg et TV show RSS feed
+Vis navn
+Kvalitet
+Udgivelsesgruppe
+Kvalitet og udvidelsegruppe er valgfrie.\nGjort muligt af http://www.ezrss.it
+eksakt match ↴
+Et eksempel feed vil blive vist her efter du har indtastet din søgning
+Henter...
+Søgningen giver en tom liste
+
+Brugerfladeindstillinger
+Kun overføre (> 0 KB/s)
+Vis torrents der overfører med 0 KB/s som inaktive
+Glid i mellem etiketter
+Skift i mellem etiketter i stedet for servere når du glider fingeren over skærmen
+Opdateringsinterval
+Skjul opdateringer
+Vis ikke \'Torrent liste opdateret\' besked
+Slet søgehistorik
+Historik slettet
+Bekræft fjernelse
+Spørg først før fjernelse af torrent
+
+Alarmtjenesteindstillinger
+Aktiver alarmtjeneste
+Alamer mig når en torrents status ændres
+Alarminterval
+Hvor ofte torrents skal kontrolleres
+Downloadalarm
+Giv besked når en torrent er færdig
+Ny torrentalarm
+Giv besked når en torrent er blevet tilføjet
+Opdater RSS Feeds
+Giv besked når en ny torrent er til rådighed
+
+Venter på tjek...
+Kontrollerer lokale data...
+Venter på at downloade %1$s
+%1$s af %2$s (%3$s)
+%1$s, uploadet %2$s
+~ %1$s
+ukendt eta
+forhold %1$s
+%1$s af %2$s klienter
+↑ %1$s
+↓ %1$s
+Sat på pause
+Stoppet
+Ukendt
+/sek
+
+Opdaterer...
+Tilføjer torrent...
+Uploader torrent...
+Fjerner torrent...
+Sætter torrent på pause...
+Sætter alle torrents på pause...
+Forsætter torrent...
+Forsætter alle torrents...
+Stopper torrent...
+Stopper alle torrents...
+Starter torrent...
+Starter alle torrents...
+Henter filer...
+Sætter filindstillinger...
+Sætter overførselshastighed...
+Tilføjer etiket...
+
+Torrentliste opdateret
+Torrent tilføjet (opdaterer)
+fjernet
+fjernet og data slettet
+forsat (opdaterer)
+stoppet
+startet (opdaterer)
+på pause
+Torrents på pause
+Torrents forsat (opdaterer)
+Torrents stoppet
+Torrents startet (opdaterer)
+
+Detaljer
+Filer
+Størrelse:
+Status:
+Downloadet:
+Uploadet:
+Forhold:
+ETA (færdig om):
+Tilgængelighed:
+Klienter:
+Etiket:
+Listning af filer er ikke understøttet af din torrent klient, eller er ikke implementeret endnu
+Fil prioriteter opdateret
+
+Hent ikke
+Lav
+Normal
+Høj
+Fjernafspil i VLC
+Download med (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Opdateringsinterval
+Stil
+Tilføj denne widget
+DL @
+op
+UP @
+inaktiv
+/sek
+eta
+ukendt eta
+Ny
+
+Ny torrent tilføjet
+Torrentdownload færdig
+Nye torrents til rådighed
+%d nye RSS feed torrents
+
+RSS
+Ingen RSS feeds installeret\n\nBenyt menuen for at tilføje nye feeds
+Henter RSS feed
+Forbundet, men RSS feedet er tomt
+
+Fejl under kommunikation med serveren
+Fejl under opbygning af forespørgsel
+Fejl under fortolkning af serverens svar (kontroller venligst dine indstillinger)
+Webinterfacet er ikke i forbindelse med den kørende dæmon
+Godkendelse nægtet (kontroller venligst dine indstillinger)
+Kan ikke læse .torrent fil
+Fejl under fortolkning af RSS feedet
+Denne URL er ikke korrekt
+Din websøgnings URL er ugyldig:
+Indtastningen er ikke en gyldig IP adresse eller værtsnavn
+Portnumre er altid numeriske
+Mappestien ender med et / eller \
+RSS feed indeholder ikke en URL, der peger på en .torrent fil
+RSS feeded angiver ikke et link som kan browses til
+URL er ikke noget (gyldigt) RSS feed
+
+Xirvik tilbyder delte, delvist dedikerede og dedikerede seedmaskiner. Transdroid tilbyder en nem konfiguration på alle Xirvik servere.\n\nLæs mere på www.xirvik.com
+Tilføj Xirvik server
+Xirvik serverindstillinger
+Servertype
+Delt, devis dedikeret eller dedikeret
+Servernavn
+Som dedi000.xirvik.com
+Ugyldig server (brug det fulde værtsnavn, som dedi000.xirvik.com)
+
+SeedM8 tilbyder Gbit seedmaskine hosting. Transdroid tilbyder en nem konfiguration på alle SeedM8 servere.\n\nLæs mere på www.seedm8.com
+Tilføj SeedM8 server
+SeedM8 serverindstillinger
+Servernavn
+Som alpha.seedm8.com
+Ugyldig server (brug det fulde værtsnavn, som alpha.seedm8.com)
+
+
+Kombineret rækkefølge
+Antallet af seeders/leechers
+
+
+
+Ingen automatisk opdatering
+2 sekunder
+5 sekunder
+15 sekunder
+1 minut
+5 minutter
+15 minutter
+1 time
+
+
+
+1 minut
+10 minutter
+30 minutter
+1 time
+3 timer
+12 timer
+1 dag
+
+
+
+Android 1.5
+Android 1.6
+Hurtigsøgeboks
+Sort
+Transparent
+
+
diff --git a/android/res/values-de/strings.xml b/android/res/values-de/strings.xml
new file mode 100644
index 00000000..e138d686
--- /dev/null
+++ b/android/res/values-de/strings.xml
@@ -0,0 +1,366 @@
+
+
+Torrent-Client-Manager mit integrierter Suche, RSS-Unterstützung und Widget
+
+Öffnen Sie die Einstellungen, um eine Konfiguration der Server-Daten vorzunehmen.
+Verwenden Sie Transdroid zum ersten Mal? Eine Installationsanleitung findet man unter www.transdroid.org/download\n\nUm Transdroid zu benutzen, geben Sie bitte Ihre Server-Konfiguration ein:
+Einstellungen öffne
+Versuche eine Verbindung zum Server herzustellen …
+Verbunden, aber keine Torrents auf dem Server.
+Verbunden, aber keine herunterladende Torrents auf dem Server.
+Verbunden, aber keine verteilenden Torrents auf dem Server.
+Verbunden, aber keine inaktiven Torrents auf dem Server.
+Ihr Torrent-Client unterstützt keine .torrent-Dateien oder diese Funktion wurde noch nicht implementiert.
+Ihr Torrent-Client unterstützt keine .magnet-Links oder diese Funktion wurde noch nicht implementiert.
+Speichern
+Ausblenden
+Torrent-Server
+Es wurden noch keine Server konfiguriert.
+
+Alle Label
+Ohne Label
+Neues Label
+Setzen eines Labels wird von Ihrem Client nicht unterstützt
+
+Ansicht wechseln
+Alle Torrents
+Herunterladende Torrents
+Verteilende Torrents
+Inaktive Torrents
+
+Hinzufügen
+Barcode scannen
+RSS
+Server wechseln
+Übertragungsgeschwindigkeit setzen
+auf alle anwenden
+alle anhalten
+alle
+alle stoppen
+alle starten
+Liste filtern
+Sortieren nach (nochmal für umgekehrte Reihenfolge)
+Name
+Status
+Abgeschlossen am
+Hinzugefügt am
+Upload-Geschwindigkeit
+Verhältnis
+Nur Übertragende (> 0KB/s)
+Einstellungen
+Über/Änderungshistorie
+Fehler melden
+Entfernen
+Entfernen und alle Dateien löschen
+Auch alle Dateien löschen
+Anhalten
+Fortsetzen
+Anhalten
+Start
+Erzwungener Start
+Label setzen
+Download-Ort festlegen
+Als Standard einstellen
+Standard-Seite setzen auf
+nach oben
+nach unten
+Tracker editieren
+Auswahl umkehren
+
+Fügen Sie die URL der Torrent-Datei ein
+Diese Eingabe ist keine (valide) URL
+Lokale .torrent-Datei auswählen
+Kein unterstützter Dateimanager (wie z.B. OI File Manager) wurde gefunden. Möchten Sie diesen aus dem Android Markt installieren?\n\nAlternativ können Sie einen nicht unterstützten Dateimanager öffnen und eine .torrent Datei an Transdroid schicken.
+Installieren
+Die Anwendung Android Market ist nicht installiert
+Die Anwendung Barcode Scanner konnte nicht gefunden werden. Möchten Sie diese über den Android Market installieren?
+Um einen Fehlerreport zu senden, benötigen Sie die freie und kostenlose Log Collector App. Möchten Sie diese über den Android Markt installieren?
+
+Maximale Download-Geschwindigkeit
+Maximale Upload-Geschwindigkeit
+Nur numerische Werte, in KB/s
+Zurücksetzen
+Ihr Torrent-Client unterstützt das Setzen von Übertragungsgeschwindigkeiten nicht oder diese Funktion wurde noch nicht implementiert.
+Übertragungsgeschwindigkeiten aktualisiert
+Torrent entfernen
+Sind Sie sicher, dass Sie diesen Torrent entfernen wollen?
+Hinzufügen fehlgeschlagen
+%1$s konnte gerade nicht hinzugefügt werden.\nErneut versuchen oder zur Warteschleife hinzufügen, um sie später automatisch hinzuzufügen?
+%1$s konnte gerade nicht hinzugefügt werden.\nErneut versuchen?
+Erneut versuchen
+Später hinzufügen
+
+Suche läuft …
+Suche nach Torrents
+Torrents
+Suchanfrage eingeben
+resultiert aus
+Alle markierten hinzufügen
+Kein Ergebnis für diese Suchanfrage gefunden
+Diese Suchanfrage steht nicht zur Verfügung.
+Seite wechseln
+Download starten
+Zur Webseite wechseln
+Öffnen mit …
+Link teilen …
+Als RSS-Feed speichern
+Als neue Suche verwenden
+Suche als RSS-Feed gespeichert
+Diese Seite unterstützt das Speichern nicht
+Torrent Search ist nun ein separates Modul und benötigt eine einmalige Installation aus dem Android Market. Jetzt installieren?
+
+Transdroid-Einstellungen
+Neuen Server hinzufügen
+Neue Suchwebseite hinzufügen
+RSS-Feed hinzufügen
+applikationsinterne Suche
+internetbasierte Suche
+Andere Einstellungen
+
+Server-Daemon
+Grundeinstellungen
+Name
+optinaler Eigenname
+Art des Servers
+IP oder Domainname
+Ohne http:// oder Portnummer
+Port
+Normalerweise
+Authentifizierung benutzen
+Benutzername und Passwort werden benötigt
+Benutzername
+Passwort
+Server-Betriebssystem
+SCGI-Ordner
+Normalerweise /RPC2
+Ordner
+Zum Beispiel /torrentflux
+Normalerweise leer
+Erweiterte Einstellungen (optional)
+Downloads-Verzeichnis
+Der absolute Pfad zum Download-Verzeichnis auf Ihrem Server
+Basis-(S)FTP-URL
+zum Beispiel ftp://user@server.com/downloads/
+Timeout der Verbindung
+Anzahl an Sekunden bevor eine Zeitüberschreitung des Verbindungsversuches eintritt
+SSL (TLS)
+Die Benutzung von SSL aktivieren
+Benutzerdefinierter SSL-Fingerabdruck (SSL thumbprint)
+Nur Verbindungen mit diesem bestimmten Zertifikat zulassen
+Alle SSL-Zertifikate zulassen
+Auswählen, um Verbindungen von jedem SSL-Fingerabdruck zuzulassen
+
+Suchmaschine
+Standard-Seite setzen
+Direkte Such-URL
+%s wird durch die Suchanfrage ersetzt
+Anzahl an Ergebnissen
+Sortierung der Ergebnisse
+RSS-Feed
+Feed-Einstellungen
+Feed-URL
+Benötigt eine Authentifizierung
+Öffnet Links im Browser zur Authentifizierung
+ezRSS-Feed-Ersteller
+Erstelle ein RSS-Feed für eine TV-Sendung
+Name anzeigen
+Qualität
+Freigabegruppe
+Qualität und Freigabegruppe sind optional\nPowered by http://www.ezrss.it
+exakte Übereinstimmung ↴
+Ein Beispiel-Feed wird hier angezeigt nachdem eine Suchanfrage angegeben wurde
+Lädt …
+
+Interface-Einstellungen
+Nur Übertragende (> 0KB/s)
+Aktualisierungsintervall
+Aktualisierung verbergen
+Suchverlauf löschen
+Suchverlauf wurde gelöscht
+Entfernen bestätigen
+Beim Entfernen eines torrent nachfragen
+Import-Einstellungen
+Einstellungen erfolgreich importiert
+Datei auswählen
+Einstellungen exportieren
+Einstellungen wurden erfolgreich exportiert
+Verzeichnis auswählen
+Werbung erlauben
+Werbung am unteren Bildschirmrand darstellen
+
+Alarm-Dienst Einstellungen
+Alarm-Dienst aktivieren
+Alarm bei Änderung des Torrent-Status
+Interval des Alarms
+Wie oft sollen meine Torrents überprüft werden
+Download-Alarm
+Benachrichtigung wenn ein Torrent fertig ist
+Benachrichtigung bei neuem Torrent
+Alarmton
+Vibration aktivieren
+Bei Alarm vibrieren
+RSS-Feeds überprüfen
+ADW-Benachrichtigung aktivieren
+Torrent-Anzahl in ADW Launcher anzeigen
+Nur Downloads zählen
+ADW Launcher zeigt nur die Anzahl an herunterladenden Torrents
+
+Warten auf die Überprüfung …
+Lokale Daten werden geprüft …
+Warten auf den Download %s
+Fehler …
+%1$s von %2$s (%3$s)
+%1$s, hochgeladen %2$s
+~ %1$s
+unbekannte Dauer
+Verhältnis %1$s
+%1$s von %2$s Peers
+↑ %1$s
+↓ %1$s
+Anhalten
+Gestoppt
+Unbekannt
+/s
+
+Aktualisieren …
+Torrent wird hinzugefügt …
+Torrent wird hochgeladen …
+Torrent wird entfernt …
+Torrent wird angehalten …
+Alle Torrents werden angehalten …
+Torrent wird fortgesetzt …
+Alle Torrents werden fortgesetzt …
+Torrent wird gestoppt …
+Alle Torrents werden gestoppt …
+Torrent wird gestartet …
+Alle Torrents werden gestartet …
+Daten werden erneuert …
+Datei-Einstellungen werden gesetzt …
+Setze Transferraten …
+Label wird zugewiesen …
+Torrent wird verschoben …
+Modus wird gewechselt …
+
+Torrent-Liste aktualisiert
+Torrent hinzugefügt (wird aktualisiert)
+gelöscht
+entfernt und alle Dateien gelöscht
+fortgesetzt (wird aktualisiert)
+gestoppt
+gestartet (wird aktualisiert)
+angehalten
+Torrents angehalten
+Torrent fortgesetzt (wird aktualisiert)
+Torrents gestoppt
+Torrents gestartet (wird aktualisiert)
+Tracker aktualisiert
+Torrent verschoben nach \'%1$s\'
+
+Details
+Dateien
+Größe:
+Status:
+Hochgeladen:
+Heruntergeladen:
+Ratio:
+Voraussichtliche Dauer:
+Verfügbarkeit:
+Peers:
+Label:
+Trackers:
+%1$s (ausklappen)
+(einklappen)
+Fehler:
+Datei-Prioritäten aktualisiert
+
+Aus
+Niedrig
+Normal
+Hoch
+Remote-Play in VLC
+Download via (S)FTP
+
+Transdroid 4×1
+Transdroid 2×1
+Server
+Aktualisierungsintervall
+Style
+Dieses Widget hinzufügen
+DL @
+up
+UP @
+inaktiv
+/s
+~
+unbekannte Dauer
+neu
+
+Neuer Torrent hinzugefügt
+Torrent vollständig heruntergeladen
+Neue Torrents verfügbar
+%d neue RSS-Feed-Torrents
+
+RSS
+Keine RSS-Feeds vorhanden.\n\nBenutzen Sie das Menü um neue Feeds hinzuzufügen.
+RSS-Feed laden
+Verbunden, aber leeres RSS-Feed
+
+.torrent-Datei konnte nicht eingelesen werden
+Portnummer ist immer numerisch
+Verzeichnispfade enden mit / oder \\
+Timeout darf nicht leer sein und ist eine postive Zahl
+URL ist kein (valides) RSS-Feed
+SD Karte nicht verfügbar zum Lesen/Schreiben
+Datei scheint keine Transdroid-Einstellungen zu enthalten
+Es wurde keine Datei mit Einstellungen gefunden
+
+Xirvik offers shared, semi-dedicated or dedicated seedboxes. Transdroid provides easy setup for all Xirvik servers.\n\nRead more at www.xirvik.com
+Xirvik-Server hinzufügen
+Einstellungen des Xirvik-Servers
+Art des Servers
+Shared, semi- oder dedicated
+Server-Name
+beispielsweise dedi000.xirvik.com
+Ungültiger Server (den vollen Hostnamen verwenden, beispielsweise dedi000.xirvik.com)
+
+SeedM8 offers unmetered GBit seedbox hosting. Transdroid provides easy setup for SeedM8 servers.\n\nRead more at www.seedm8.com
+SeedM8-Server hinzufügen
+Einstellungen des SeedM8-Servers
+Server-Name
+beispielsweise alpha.seedm8.com
+Ungültiger Server (den vollen Hostnamen verwenden, beispielsweise alpha.seedm8.com)
+
+
+Kombinierte Sortierung
+Anzahl an Seedern/Leechern
+
+
+
+Kein automatisches Aktualisieren
+2 Sekunden
+5 Sekunden
+15 Sekunden
+1 Minute
+5 Minuten
+15 Minuten
+1 Stunde
+
+
+
+1 Minute
+10 Minuten
+30 Minuten
+1 Stunde
+3 Stunden
+12 Stunden
+1 Tag
+
+
+
+Android 1.5
+Android 1.6
+Schnellsuche
+Schwarz
+Transparent
+
+
diff --git a/android/res/values-el/strings.xml b/android/res/values-el/strings.xml
new file mode 100644
index 00000000..2f00630a
--- /dev/null
+++ b/android/res/values-el/strings.xml
@@ -0,0 +1,164 @@
+
+
+Διαχειριστής Torrent Client με ενσωματωμένη αναζήτηση, υποστήριξη RSS και widget παρακολούθησης
+
+Ανοίξτε το μενού των ρυθμίσεων για να βάλετε τις λεπτομέρειες του server σας.
+Νέος με το Transdroid; Μπορείς να πάρεις βοήθεια για την εγκατάσταση από το www.transdroid.org/download\n\nΓια να ξεκινήσετε με τα torrents βάλτε τις ρυθμίσεις του server σας:
+Άνοιγμα Ρυθμίσεων
+Απόπειρα σύνδεσης με το server...
+Συνδεθήκατε, αλλά δεν υπάρχουν torrents στον server.
+Συνδεθήκατε, αλλά δεν υπάρχουν torrents που κατεβαίνουν στον server.
+Συνδεθήκατε, αλλά δεν υπάρχουν torrents που διαμοιράζονται στον server.
+Συνδεθήκατε, αλλά κανένα torrent δεν είναι ενεργό.
+Ο torrent client σας δεν υποστηρίζει μεταφόρτωση αρχείων .torrent ή ακόμα αυτή η διαδικασία δεν έχει υλοποιηθεί.
+Ο torrent client σας δεν υποστηρίζει συνδέσμους .magnet ή ακόμα αυτή η διαδικασία δεν έχει υλοποιηθεί.
+Αποθήκευση
+Ακύρωση
+Torrent server
+Κανένας server δεν έχει ρυθμιστεί ακόμα
+
+Εμφάνιση όλων
+Χωρίς ετικέτα
+Νέα ετικέτα
+Η εφαρμογή ετικέτας δεν υποστηρίζεται από τον client σας
+
+Αλλαγή προβολής
+Εμφάνιση όλων των torrent
+Εμφάνιση όσων torrent γίνετε τώρα λήψη
+Εμφάνιση όσων torrent γίνετε τώρα διαμοιρασμός
+Εμφάνιση όσων torrent δεν είναι ενεργά
+
+Προσθήκη
+Σάρωση barcode
+RSS
+Αλλαγή Server
+Ορισμός ταχύτητας μεταφοράς
+Κάντο για όλα
+Παύση όλων
+Συνέχιση όλων
+Σταμάτημα όλων
+Ξεκίνημα όλων
+Λίστα φίλτρων
+Ταξινόμηση κατά (για αντίστροφή ταξινόμησης)
+Όνομα
+Κατάσταση
+Ημερομηνία ολοκλήρωσης λήψης
+Ημερομηνία προσθήκης
+Ταχύτητα μεταφόρτωσης
+Αναλογία
+Ρυθμίσεις
+Σχετικά / Αρχείο αλλαγών
+Έκθεση σφαλμάτων
+Αφαίρεση
+Αφαίρεση και διαγραφή δεδομένων
+Διέγραψε επίσης τα δεδομένα
+Παύση
+Συνέχιση
+Σταμάτημα
+Ξεκίνημα
+Εξαναγκαστικό Ξεκίνημα
+Ορισμός ετικέτας...
+Ορισμός διαδρομής αποθήκευσης ληφθέντων αρχείων
+Ορισμός ως προεπιλογή
+Προεπιλεγμένο site ορίσθηκε σε
+Μετακίνησης προς τα πάνω
+Μετακίνησης προς τα πκάτω
+Αναίρεση επιλογής
+
+Επικόλληση URL του αρχείου torrent
+Αυτό που εισάγατε δεν είναι σωστό URL
+Επιλογή τοπικού αρχείου .torrent
+Δεν υπάρχει κάποιος υποστηριζόμενος διαχειριστής αρχείων, ο OI File Manager, θα μπορούσε να βρεθεί(είναι υποστηριζόμενος). Θα ήθελες να εγκατασταθεί από το Android Market?\n\n Εναλλακτικά, μπορείς να ανοίξεις ένα μη υποστηριζόμενο διαχειριστή αρχείων και να στείλεις το αρχείο .torrent στο Transdroid.
+Εγκατάσταση απο το market.
+Η εφαρμογή Android Market δεν είναι εγκατεστημένη.
+To Barcode Scanner δεν βρέθηκε. Θα θέλατε να εγκατασταθεί από το Android Market;
+Για να στείλετε μια αναφορά σφαλμάτων, θα χρειαστείτε την δωρεάν και ανοιχτού κώδικα εφαρμογή Log Collector. Θα θέλατε να εγκατασταθεί από το Android Market;
+Η εφαρμογή Log Collector τώρα θα συλλέξει το αρχείο καταγραφής της συσκευής και θα το στείλει στο transdroid.org@gmail.com.\n Θα μπορείς να δεις και να επεξεργαστείς τα δεδομένα που στέλνονται.
+Ένας απομακρυσμένος file viewer , όπως το VLC Remote, δεν μπόρεσε να βρεθεί. Θα θέλατε να εγκαταστήσετε το VLC Remote από το Android Market;
+Δεν έχετε εγκαταστήσει κάποιο συμβατό FTP client.\nΘα θέλατε να εγκαταστήσετε το AndFTP από το Android Market;
+
+Μέγιστη ταχύτητα λήψης
+Μέγιστη ταχύτητα μεταφόρτωσης
+Μόνο αριθμητικές τιμές , σε KB/s
+Επανεκκίνηση
+Ο torrent client σας, δεν υποστηρίζει τον ορισμό ταχυτήτων μεταφοράς ή ακόμα αυτή η διαδικασία δεν έχει υλοποιηθεί.
+Οι ταχύτητες μεταφοράς ανανεώθηκαν.
+Αφαίρεση torrent
+Είστε σίγουρος πως θέλετε να αφαιρέσετε αυτό το torrent;
+Η προσθήκη απέτυχε
+Επανάληψη
+Προσθήκη Αργότερα
+
+Αναζήτηση...
+Αναζήτηση on-line για torrents
+Torrents
+Ubuntu
+Αποτελέσματα από
+Προσθήκη όλων των επιλεγμένων
+Δεν βρέθηκαν αποτελέσματα για την αναζήτησή σας
+Δεν θέσατε κάτι προς αναζήτηση
+Αλλαγή site
+Λήψη τώρα
+Άνοιγμα ιστοσελίδας
+Άνοιγμα με...
+Μοιράσου τον σύνδεσμο...
+Σώσε το σαν RSS feed
+Χρήση σαν καινούργια αναζήτηση
+
+Προσθήκη καινούργιου server
+Προσθήκη RSS feed
+Άλλες ρυθμίσεις
+
+Βασικές ρυθμίσεις
+Όνομα χρήστη
+Κωδικός
+Φάκελος
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-es/strings.xml b/android/res/values-es/strings.xml
new file mode 100644
index 00000000..d4a7db88
--- /dev/null
+++ b/android/res/values-es/strings.xml
@@ -0,0 +1,393 @@
+
+
+Gestor de clientes de -torrents con búsqueda integrada, soporte para RSS y un widget de estado.
+
+btorrente
+Nuevo usuario de Transdroid?\nAbre el menú de configuración para introducir los detalles de tu servidor.\n\nPara más información: www.transdroid.org/download
+Mostrar opciones
+Intentando conectar con el servidor...
+Conectado, pero no hay torrents en el servidor.
+Conectado, pero no hay descargas activas en el servidor.
+Conectado, pero no se está enviando nada en el servidor.
+Conectado, pero no hay descargas paradas en el servidor.
+Tu cliente de torrents no soporta la subida de archivos .torrent o esto todavía no está implementado.
+Tu cliente de torrents no soporta enlaces .magnet o esto todavía no está implementado.
+Guardar
+Ignorar
+Servidor torrent
+Ningún servidor has sido configurado
+
+Mostrar todas
+Sin entiquetar
+Nueva etiqueta
+Tu cliente torrent no permite definir etiquetas
+
+Cambiar vista
+Mostrando todos los torrents
+Mostrando los torrents descargándose
+Mostrando los torrents enviándose
+Mostrando los torrents inactivos
+
+Añadir
+Escanear código de barras
+RSS
+Cambiar servidor
+Ajustes de transferencia
+Hacer para todos
+Pausar todos
+Reanudar todos
+Parar todos
+Iniciar todos
+Lista de filtros
+Ordenar por (repetir para invertir el orden)
+Nombre
+Estado
+Fecha completado
+Fecha añadido
+Velocidad de subida
+Proporción
+Sólo transfiriendo (> 0KB/s)
+Opciones
+Acerca de/Registro de cambios
+Informe de error
+Eliminar
+Eliminar y borrar datos
+Borrar también datos
+Pausar
+Reanudar
+Parar
+Iniciar
+Forzar inicio
+Definir etiqueta
+Definir carpeta de descargas
+Establecer como predeterminado
+Sitio predeterminado asignado a
+Ir arriba
+Ir abajo
+Editar trackers
+Invertir selección
+
+Pega la URL del archivo torrent
+La entrada introducida no es una URL (válida)
+Seleccione un archivo .torrent local
+Ningún explorador de archivos soportado, como el OI File Manger, pudo ser encontrado. ¿Quiere instalarlo desde el Android Market?\n\nTambién puede abrir un explorador de archivos no soportado y enviar un fichero .torrent a Transdroid.
+Instalar desde el Market
+La aplicación Android Market no está instalada
+Barcode Scanner (escáner de código de barras) no fue encontrado. ¿Te gustaría instalarlo desde el Android Market?
+Para enviar un informe de error, necesitas la aplicación libre y de código abierto "Log Collector". ¿Te gustaría instarla desde el Android Market?
+La aplicación "Log Collector" cogerá el registro (log) del dispositivo y lo enviará a transdroid.org@gmail.com.\nPodrás revisar y modificar los datos que se enviarán.
+Un visor de ficheros remotos, como VLC Remote, no pudo ser encontrado. ¿Te gustaría instalar VLC Remote desde el Android Market?
+No tienes instalado un cliente FTP compatible.\n¿Te gustaría instalar AndFTP desde el Android Market?
+
+Velocidad máxima de descarga
+Velocidad máxima de subida
+Sólo valores numérico, en KB/s
+Reiniciar
+Tu cliente de torrents no soporta el ajuste de velocidad o esto aún no ha sido implementado.
+Velocidades de transf. actualizadas
+Eliminando torrent
+¿Estás seguro de que quieres eliminar este torrent?
+La adición falló
+No se ha podido añadir en este momento. ¿Quiere reintentarlo o ponerlo en cola para que se añada automáticamente después?
+No se ha podido añadir en este momento. ¿Quiere reintentarlo?
+Reintentar
+Añadir más tarde
+
+Buscando...
+Buscar torrents en línea
+Torrents
+Ubuntu
+Resultados de
+Añadir todos los seleccionados
+No hay resultados para tu búsqueda
+No se ha introducido ninguna búsqueda.
+Cambiar sitio
+Descargar ahora
+Abrir sitio web
+Abrir con...
+Compartir enlace...
+Guardar como fuente RSS
+Utilizar como nueva busqueda
+Busqueda guardada como fuente RSS
+No está soportada la opción Guardar para este archivo
+Torrent Search es ahora un módulo aparte, lo que significa una sola instalación desde el Android Market. ¿Instalar ahora?
+
+Preferencias de Transdroid
+Añadir nuevo servidor
+Añadir motor de búsquedas
+Añadir una fuente RSS
+Búsqueda en la aplicación
+Búsqueda en la web
+Otras opciones
+
+Servidor remoto
+Ajustes básicos
+Nombre
+Nombre personalizado opcional
+Tipo de servidor
+IP o Nombre dominio
+Sin http:// o número de puerto
+Número de puerto
+Normalmente es
+Usar autentificación
+Necesitarás nombre de usuario y contraseña
+Usuario
+Contraseña
+SO del Servidor
+Carpeta SCGI
+Normalmente es /RPC2
+Carpeta
+Por ejemplo /torrentflux
+Normalmente vacío
+Opciones avanzadas (opcional)
+Directorio de descargas
+La dirección absoluta al directorio de descargas de tu servidor
+Base (S)FTP) url
+Por ejemplo: ftp://yo@servidor.com/descargas/
+Tiempo de conexión excedido
+Segundos restantes para intentar conectar de nuevo
+SSL
+Seleccionar para usar https
+Certificado personalizado de SSL
+Permitir conexiones sólo del certificado especificado
+Aceptar todos los certificados SSL
+Seleccionar si es un certificado autofirmado
+
+Motor de búsqueda
+Definir sitio predeterminado
+URL de búsqueda directa
+%1$s se sustituirá por la cadena buscada
+Número de resultados
+Orden del resultado
+Fuentes RSS
+Ajustes de fuentes
+URL de la fuente
+Necesita autentificación
+Abrir enlaces en el navegador para autentificar
+Creador de fuentes ezRSS
+Crear una fuente RSS de show televisivo
+Nombre del show
+Calidad
+Grupo publicador
+Calidad y grupo publicador son opcionales\nHecho posible por http://www.ezrss.it
+Coincidencia exacta
+Un ejemplo de fuente aparecerá aquí después de insertar tu cadena de búsqueda
+Cargando...
+Esta cadena de búsqueda resulta en una lista de episodios vacía
+
+Ajustes de interfaz
+Sólo transfiriendo (> 0KB/s)
+Mostrar torrents descargándose a 0KB/s como inactivos
+Deslizar etiquetas
+Deslizar para cambiar de etiqueta en vez de servidor
+Intervalo de actualización
+Ocultar actualización
+No mostrar el mensaje \'Lista de torrents actualizada\'
+Limpiar historial de búsqueda
+Historial borrado correctamente
+Confirmación de borrado
+Preguntar para confirmar la eliminación de un torrent
+Importar configuración
+Transdroid intentará importar la configuración de servidor, búsquedas web y RSS de:
+Configuración importada con éxito
+Seleccionar un archivo
+Exportar configuración
+Transdroid exportará la configuración de servidor (incluyendo contraseñas), búsquedas web y RSS al siguiente archivo de texto plano:
+Configuración exportada con éxito
+Seleccionar un directorio
+Activar publicidad
+Mostrar publicidad en la parte de abajo de la pantalla
+
+Configuración del servicio de alarmas
+Habilitar el servicio de alarmas
+Alertarme si cambia el estado de un torrent
+Intervalo entre alarmas
+Cada cuánto revisar my torrents
+Descargar alarma
+Notificarme cuando un torrent termina
+Nueva alarma de torrent
+Notificarme cuando un torrent es añadido
+Activar sonido de alarma
+Reproducir sonido de notificación con alarma
+Sonido de alarma
+Sonido de notificación a reproducir con alarma
+Activar vibración
+Vibrar con alarma
+Revisar fuentes RSS
+Alarma cuando nuevos torrents están disponibles
+Permitir notificaciones ADW
+Mostrar contador de torrents en ADW Launcher
+Sólo contar descargas
+El contador ADW solo contiene los torrents descargados
+
+Esperando para revisar...
+Verificando datos locales...
+Esperando para descargar %1$s
+Error...
+%1$s de %2$s (%3$s)
+%1$s, subidos %2$s
+~ %1$s
+eta desconocido
+proporción %1$s
+%1$s de %1$s peers
+↑ %1$s
+↓ %1$s
+Pausados
+Parados
+Desconocido
+/s
+
+Actualizando...
+Agregando torrent...
+Subiendo torrent...
+Eliminando torrent...
+Pausando torrent...
+Pausando todos los torrents...
+Reanudando torrent
+Reanudando todos los torrents...
+Parando torrent...
+Parando todos los torrents...
+Iniciando torrent...
+Iniciando todos los torrents...
+Extrayendo archivos...
+Configurando propiedades de archivo...
+Configurando velocidades de transferencia...
+Asignando etiqueta...
+Moviendo torrent...
+Cambiando modo...
+
+Lista de torrents actualizada
+Torrent añadido (actualizando)
+Eliminado
+Eliminado completamente
+Torrent(s) reanudados (actualizando)
+Torrent(s) parados
+Torrent(s) iniciados (actualizando)
+Torrent(s) pausados
+Torrents pausados
+Torrents reanudados (actualizando)
+Torrents detenidos
+Torrents iniciados (actualizando)
+Trackers actualizados
+Torrent movido a \'%1$s\'
+
+Detalles
+Archivos
+Tamaño:
+Estado:
+Descargado:
+Subido:
+Proporción:
+Eta:
+Disponibilidad:
+Peers:
+Etiqueta:
+Trackers:
+%1$s (desplegar)
+%1$s (contraer)
+Errores:
+Listar los ficheros no está soportado por tu cliente torrent o aún no está imprementado
+Prioridad de Ficheros actualizada
+
+Apagado
+Bajo
+Normal
+Alto
+Control remoto en VLC
+Descargar usando (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Servidor
+Intervalo de recarga
+Estilo
+Agregar este widget
+BJ @
+sb
+SB @
+inactivo
+/s
+eta
+eta desconocido
+nuevo
+
+Nuevo torrent añadido
+Torrent terminó la descarga
+Nuevos torrents disponibles
+%d nuevos torrents de fuente RSS
+
+RSS
+No hay ningún feed RSS\n\nUsa el menú para añadir nuevos feeds
+Cargando feed RSS
+Conectado, pero el feed RSS está vacío
+
+Error durante la comunicación con el servidor
+Error generando la petición
+Error analizando la respuesta del servidor (por favor, revisa la configuración)
+El interface Web no está conectado a ningún programa en ejecución.
+Autenticación denegada (por favor, revisa la configuración)
+No se puede leer el fichero .torrent
+Error mientras se analizaba la fuente RSS
+El formato de la URL no es válido.
+La URL de búsqueda web no es válida:
+No ha introducido una dirección IP o un nombre de host válidos.
+El puerto siempre es un número
+Directorios terminan con un / o
+El timeout debe ser un número positivo y no vacío
+La entrada de la fuente RSS no proporciona una URL que apunte al fichero .torrent
+El ítem de la fuente RSS no provee un enlace para mostrar
+La URL no es una (válida) fuente RSS
+La tarjeta SD no está disponible para lectura/escritura
+El archivo no aparenta tener la configuración de Transdroid
+No se encontró el archivo de configuración
+
+Xirvik ofrece cajas de subida (seedboxes) compartidas y dedicadas o semi-dedicadas. Transdroid provee una configuración rápida para todos los servidores Xirvik.\n\nLea más en www.xirvik.com
+Añadir servidor Xirvik
+Preferencias del servidor Xirvik
+Tipo de servidor
+Compartido, semi- o dedicado
+Nombre del servidor
+Como dedi000.xirvik.com
+Servidor incorrecto (usa el nombre del host completo, como dedi000.xirvik.com)
+
+SeedM8 ofrece hospedaje ilimitado de cajas de subida (seedboxes). Transdroid provee una configuración rápida para todos los servidores SeedM8.\n\nLea más en www.seedm8.com
+Añadir servidor SeedM8
+Configuración del servidor SeedM8
+Nombre del sevidor
+Como alpha.seedm8.com
+Servidor incorrecto (usa el nombre del host completo, como alpha.seedm8.com)
+
+
+Ordenación combinada
+Núm. de semillas/clientes
+
+
+
+No auto-actualizar
+2 segundos
+5 segundos
+15 segundos
+1 minuto
+5 minutos
+15 minutos
+1 hora
+
+
+
+1 minuto
+10 minutos
+30 minutos
+1 hora
+3 horas
+12 horas
+1 día
+
+
+
+Android 1.5
+Android 1.6
+Caja de búsqueda rápida
+Negro
+Transparent
+
+
diff --git a/android/res/values-et/strings.xml b/android/res/values-et/strings.xml
new file mode 100644
index 00000000..04cdda4c
--- /dev/null
+++ b/android/res/values-et/strings.xml
@@ -0,0 +1,127 @@
+
+
+Torrenti kliendi haldur intregbeeritud otsingu, RSS toega ja monitoorims vidinaga
+
+Ava Seaded menüü, et sisestada serveri parameetrid.
+Ava Seaded menüü, et sisestada serveri parameetrid.\n\nInstalli abi: www.transdroid.org/download
+Proovin ühendust luua...
+Salvesta
+Tühista
+
+Näita kõik
+Sildistamata
+Uus silt
+
+Näitan kõiki torrenteid
+Näitan kõiki allalaetavaid torrenteid
+Näitan kõiki üleslaetavaid torrenteid
+
+Lisa
+RSS
+Vaheta serverit
+Seadista liikluse piirangud
+Tee kõigile
+Jätka kõik
+Seiska kõik
+Käivita kõik
+Filtreeri listi
+Nimi
+Staatus
+Ratio
+Seaded
+Eemalda
+Jätka
+Seiska
+Käivita
+Sunni käivitama
+
+
+Lisa hiljem
+
+Otsin...
+Ubuntu
+
+
+Nimi
+Serveri tüüp
+IP või domeen
+Ilma http:// või pordi numbrita
+Port
+Kasutajanimi
+Parool
+Serveri OS
+Kaust
+Näiteks /torrentflux
+SSL
+
+Otsingumootor
+Tulemuste arv
+RSS voog
+ezRSS voo ehitaja
+Sarja nimi
+Kvaliteet
+Laen...
+
+
+
+
+
+
+Detailid
+Failid
+Suurus:
+Olek:
+Tõmmatud:
+Üleslaetud:
+Eta:
+Saadavus
+
+Madal
+Normaalne
+Kõrge
+
+DL @
+üles
+UP @
+eta
+uus
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Black
+Transparent
+
+
diff --git a/android/res/values-eu/strings.xml b/android/res/values-eu/strings.xml
new file mode 100644
index 00000000..cb59de12
--- /dev/null
+++ b/android/res/values-eu/strings.xml
@@ -0,0 +1,58 @@
+
+
+
+zerbitzarira konektatzen...
+ezin izan dugu daemon zerbitzarira konektatu. Mesedez, berrikusi zure konfigurazioa.
+
+
+
+Gehitu
+Bilatu
+RSS
+Zerbitzaria aldatu
+Eguneratu
+Denentzako egin
+Denak jarraitu
+Denak gelditu
+Denak hasi
+Izena
+Ezabatu
+Jarraitu
+
+
+
+Torrentak aurkitu
+Bilakera berria
+Orain jeitsi
+Orria iriki
+
+
+Pasahitza
+
+
+
+
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
diff --git a/android/res/values-fi/strings.xml b/android/res/values-fi/strings.xml
new file mode 100644
index 00000000..01ebe060
--- /dev/null
+++ b/android/res/values-fi/strings.xml
@@ -0,0 +1,336 @@
+
+
+Torrent clientin etäkäyttö-ohjelma RSS tuella ja seuranta widgetillä
+
+Avaa asetusvalikko asettaaksesi palvelimen daemon tiedot
+Uusi Transdroid käyttäjä? Voit saada apua (englanniksi) osoitteessa www.transdroid.org/download
+Avaa asetukset
+Avataan yhteyttä palvelimeen...
+Yhdistetty, mutta ei torrentteja palvelimella.
+Yhdistetty, mutta ei latautuvia torrentteja palvelimella.
+Yhdistetty, mutta ei jaettavia torrentteja palvelimella.
+Yhdistetty, mutta ei epäaktiivisia torrentteja palvelimella.
+Torrent ohjelmasti ei tue .torrent tiedostojen vastaanottamista tai tätä ominaisuutta ei ole vielä lisätty.
+Torrent clienttisi ei tue Magnet-linkkejä tai tätä ei ole vielä toteutettu.
+Tallenna
+Peruuta
+Torrent-palvelin
+Palvelimia ei ole vielä määritelty
+
+Näytä kaikki
+Poista merkki
+Uusi merkki
+Clienttisi ei tue merkkien lisäystä
+
+Vaihda näkymää
+Näytetään kaikki torrentit
+Näytetään ladattavat torrentit
+Näytetään jaettavat torrentit
+Näytetään epäaktiiviset torrentit
+
+Lisää
+Lue viivakoodi
+RSS
+Vaihda palvelinta
+Aseta kaistan käyttö
+Tee kaikille
+Tauota kaikki
+Jatka kaikkia
+Pysäytä kaikki
+Aloita kaikki
+Suodatin lista
+Järjestä (turvaudu päinvastaiseen järjestykseen)
+Nimi
+Tila
+Valmistumispäivä
+Lisäämispäivä
+Uploadnopeus
+Suhde
+Nopeus vain (> 0KB/s)
+Asetukset
+Tietoa/Muutoshistoria
+Virheraportti
+Poista
+Poista ja tyhjennä data
+Poista myös data
+Tauko
+Jatka
+Pysäytä
+Aloita
+Pakota aloitus
+Laita merkki...
+Aseta latauspaikka
+Laita oletukseksi
+Oletussivuksi laitettu
+Siirrä ylös
+Siirrä alas
+
+Liitä torrentin URL
+Liitetty URL ei ole toimiva
+Valitse paikallinen .torrent tiedosto
+Tuettua tiedostonhallintaa, kuten esimerkiksi OI File Manageria ei löydetty. Haluatko asentaa sen Android Marketista?\n\nVaihtoehtoisesti voit avata ei-tuetun tiedostonhallinnan ja itse lähettää .torrent tiedoston Transdroidiin.
+Asenna marketista
+Android Market -sovellusta ei ole asennettu.
+Viivakoodinlukijaa ei löydetty. Haluatko asentaa sen Android Marketista?
+Jos haluat lähettää raportin virheestä tarvitset ilmaisen & open-source Lag Collector sovelluksen. Haluatko asentaa sen Android Marketista?
+Log Collector sovellus kerää laitteen lokin ja lähettää sen transdroid.org@gmail.com.\nSinulla on mahdollisuus tarkastaa tai muuttaa lähetettäviä tietoja.
+VLC:tä ei löydetty, Haluatko asentaa sen Android marketista?
+Et ole vielä asentanut yhteensopivaa FTP-asiakasta, haluatko asentaa sen Android marketista?
+
+Maksimi latausnopeus
+Maksimi lähetysnopeus
+Vain numerot
+Nollaa
+Torrent-clienttisi ei tue rajoitusten määritystä.
+Siirtonopeuden asetukset määritetty.
+Poistetaan torrent
+Oletko varma että haluat poistaa tämän torrentin?
+Lisäys epäonnistui
+Uudestaan
+Lisää myöhemmin.
+
+Etsitään...
+Hae netistä torrentteja.
+Torrentit
+Ubuntu
+Tulokset sivulta
+Lisää kaikki valitut.
+Ei tuloksia haullasi.
+Hakusanaa ei annettu.
+Vaihda sivua
+Lataa nyt
+Avaa nettisivu
+Avaa ohjelmalla...
+Jaa linkki...
+Tallenna RSS-syöte
+Etsi talletettuja RSS syöteitä
+Tallennus ei tuettu tällä sivustolla.
+
+Transdroidin asetukset
+Lisää uusi palvelin
+Lisää hakusivu
+Lisää RSS syöte
+Ohjelman sisäinen haku
+Web haku
+Muut asetukset
+
+Palvelin daemon
+Perusasetukset
+Nimi
+Valinnainen henkilökohtainen nimi
+Palvelimen tyyppi
+IP tai domain nimi
+Ilman http:// tai portin numeroa
+Portti
+On yleensä
+Käytä varmennusta
+Tarvitset käyttäjätunnuksen ja salasanan
+Käyttäjätunnus
+Salasana
+Palvelimen käyttöjärjestelmä
+SCGI kansio
+Yleensä /RPC2
+Kansio
+Esimerkiksi /torrentflux
+Yleensä tyhjä
+Lisäasetukset (valinnainen)
+Lataukset-hakemisto
+Tarkka polku Lataukset-hakemistoon palvelimellasi
+Esimerkiksi ftp://me@server.com/downloads/
+SSL
+Valitse käyttääksesi https
+Hyväksy kaikki SSL-sertifikaatit
+
+Hakukone
+Valitse oletussivu
+Suorahaun URL
+Tuloksien määrä
+Tuloksien järjestys
+RSS-syötteet
+Syötteen asetukset
+Syötteen URL
+Vaatii varmennusta.
+Avaa linkit selaimella todentaaksesi.
+ezRSS-syöterakentaja
+Rakenna TV-sarjan RSS-syöte
+Sarjan nimi
+Laatu
+Julkaisuryhmä
+Laatu ja julkaisuryhmä ovat valinnaisia\nPalvelun tarjoaa http://www.ezrss.it
+Syöte-esimerkki näkyy täällä kun olet lisännyt pyyntösi
+Ladataan...
+Tämä pyyntö antaa tyhjän jaksolistauksen
+
+Käyttöliittymän asetukset
+Näytä 0KB/s nopeudella olevat torrentit epäaktiivisena.
+Käytä Swipeä merkkeihin
+Käytä Swipeä palvelimien sijasta merkkeihin
+Päivitysnopeus
+Piilota päivitys
+Älä näytä \'Torrent list refreshed\' viestiä
+Tyhjennä hakuhistoria
+Historia tyhjennetty onnistuneesti
+Varmista poisto
+Kysy poistettaessa torrenttia
+
+Hälytyspalvelun asetukset
+Ota hälytyspalvelu käyttöön
+Hälytä minua kun torrentin tila muuttuu
+Hälytyksien nopeus
+Kuinka usein torrenttini tarkastetaan
+Lataa hälytys
+Ilmoita minulle kun torrent valmistuu
+Uusi torrent hälytys
+Ilmoita kun uusi torrent on lisätty
+Tarkista RSS syötteet
+Hälytä kun uusia torrentteja on saatavilla
+
+Odotetaan tarkistusta...
+Varmistetaan paikallista dataa...
+Virhe...
+%1$s, lähetetty %2$s
+~ %1$s
+tuntematon arvio
+suhde %1$s
+%1$s of %2$s käyttäjät
+↑ %1$s
+↓ %1$s
+Tauolla
+Pysäytetty
+Tuntematon
+/s
+
+Päivitetään...
+Lisää...
+Luo...
+Poista...
+Pysäytä...
+Pysäytä kaikki...
+Jatka...
+Jatka kaikki...
+Pysäytä...
+Pysäytä kaikki...
+Aloita...
+Aloita kaikki...
+Noudetaan tiedostoja...
+Asetetaan siirtorajat...
+
+Torrent-lista päivitetty
+Torrent lisätty (päivitetään)
+poistettu
+poistettu ja tiedot tyhjennetty
+jatkettu (päivitetään)
+pysäytetty
+aloitettu (päivitetään)
+tauotettu
+Torrentit tauotettu
+Torrenttien lataus jatkettu (päivitetään)
+Torrenttien lataus pysäytetty (päivitetään)
+Torrenttien lataus aloitettu (päivitetään)
+
+Tiedot
+Tiedostot
+Koko:
+Tila:
+Ladattu:
+Lähetetty:
+Nopeus:
+Arvio:
+Saatavuus:
+Käyttäjät:
+Merkki:
+Virheet:
+Torrent-clienttisi ei tue tiedostojen listausta tai ominaisuutta ei ole vielä lisätty
+Tiedostojen tärkeydet päivitetty
+
+Pois
+Matala
+Normaali
+Korkea
+Käynnistä VLC:llä etänä
+Lataa käyttäen (S)FTP:tä
+
+Widgetin koko 4x1
+Widgetin koko 2x1
+Palvelin
+Päivitys väli
+Ulkonäkö
+Lisää widgetti
+DL @
+UP @
+Passiivisia
+/s
+Valmis
+Valmistuminen ei tiedossa.
+uusi
+
+Uusi torrent lisätty
+Torrentin lataus valmistui
+Uusia torrentteja saatavilla
+%d uusia RSS syöte torrentteja
+
+RSS
+RSS-syötteitä ei asennettu\n\nKäytä valikkoa lisätäksesi uusia syötteitä
+Ladataan RSS-syötettä
+Yhdistetty, mutta RSS-syöte on tyhjä
+
+Virhe yhdistättäessä palvelimeen
+Web-käyttöliittymää ei ole yhdistetty toimivaan daemon
+Pääsy estetty (tarkista asetuksesi)
+Ei voi lukea .torrent -tiedostoa
+Virhe luettaessa RSS-tiedostoa
+Tämä URL ei ole kunnollinen
+Internethakusi URL on virheellinen:
+Ei ole oikea IP-osoite tai isäntä
+Portin numero on aina numeerinen
+Hakemiston polku päättyy aina / tai \ -merkkiin
+RSS syötteen kohde ei anna linkkiä jonne voisi mennä
+URL ei ole (hyväksyttävä) RSS syöte
+Tiedosto ei näytä sisältävän Transdroidin asetuksia
+Asetustiedostoa ei löytynyt
+
+Xirvik tarjoaa shared, semi-dedicated tai dedicated seedboxeja. Transdroid tarjoaa yksinkertaisen setupin kaikille Xirvik palvelimille.\n\nLue lisää osoitteessa www.xirvik.com (englanniksi)
+Lisää Xirvik-palvelin
+Xirvik-palvelimen asetukset
+Palvelimen tyyppi
+Shared, semi- or dedicated
+Palvelimen nimi
+Kuten dedi000.xirvik.com
+Virheellinen palvelin (käytä kokonaista host nimeä, kuten dedi000.xirvik.com)
+
+Palvelimen nimi
+
+
+Yhdistetty
+Seederien/leecherien lukumäärä
+
+
+
+Ei automaattista päivitystä
+2 sekuntia
+5 sekuntia
+15 sekuntia
+1 minuutti
+5 minuuttia
+15 minuuttia
+1 tunti
+
+
+
+1 minuutti
+10 minuuttia
+30 minuuttia
+1 tunti
+3 tuntia
+12 tuntia
+1 päivä
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Black
+Transparent
+
+
diff --git a/android/res/values-fr/strings.xml b/android/res/values-fr/strings.xml
new file mode 100755
index 00000000..104062ca
--- /dev/null
+++ b/android/res/values-fr/strings.xml
@@ -0,0 +1,386 @@
+
+
+Gestionnaire de clients Bittorrent avec recherche intégrée, support RSS et widget de monitoring
+
+Ouvrez le menu des paramètres pour configurer les détails de votre serveur.
+Ouvrez le menu des paramètres pour configurer les détails de votre serveur.\n\nPour plus d\'informations : www.transdroid.org/download
+Ouvrir les paramètres
+Tentative de connexion au serveur...
+Connecté mais aucun torrent sur le serveur.
+Connecté mais aucun torrent actif sur le serveur.
+Connecté mais aucun torrent en cours de partage sur le serveur.
+Connecté mais aucun torrent inactif sur le serveur.
+Votre application torrent ne supporte pas l\'envoi de fichier .torrent ou cela n\'est pas encore implémenté.
+Votre application torrent ne supporte pas les liens .magnet ou cela n\'est pas encore implémenté.
+Enregistrer
+Annuler
+Serveur torrent
+Aucun serveur n\'a été configuré
+
+Afficher tout
+Sans étiquette
+Nouvelle étiquette
+Définir une étiquette n\'est pas supporté par votre client
+
+Changer de vue
+Voir tous les torrents
+Voir les torrents en cours de téléchargement
+Voir les torrents en cours de partage
+Voir les torrents inactifs
+
+Ajouter
+Scanner un code barre
+RSS
+Changer de serveur
+Définir les vitesses de transfert
+Pour tout
+Tout en pause
+Tout reprendre
+Tout arrêter
+Tout démarrer
+Liste de filtres
+Trier par (retrier pour inverser l\'ordre)
+Nom
+Etat
+Date de création
+Date d\'ajout
+Vitesse d\'envoi
+Ratio
+En cours de transfert (> 0KB/s)
+Paramètres
+En savoir plus
+Rapport d\'erreurs
+Supprimer
+Supprimer et effacer les données
+Supprimer également les données
+Pause
+Reprise
+Arrêter
+Démarrer
+Démarrage forcé
+Définir une étiquette...
+Emplacement de téléchargement...
+Définir par défaut
+Site par défaut à
+Monter
+Descendre
+Editer les trackers
+Insérer la sélection
+
+Coller l\'URL du fichier torrent
+Ce n\'est pas une URL valide
+Sélectionner un fichier .torrent local
+Aucun gestionnaire de fichier supporté n\'a pu être trouvé. Souhaitez-vous installer OI File Manager depuis l\'Android Market ?\n\nVous pouvez aussi ouvrir un gestionnaire de fichiers non supporté et envoyer un fichier .torrent à Transdroid.
+Installer depuis l\'Android Market
+L\'application Android Market n\'est pas installée.
+Barcode Scanner n\'a pas pu être trouvé. Voulez-vous l\'installer depuis l\'Android Market ?
+Pour envoyer un rapport d\'erreur, vous devez avoir l\'application gratuite et open-source Log Collector. Voulez-vous l\'installer depuis l\'Android Market ?
+L\'application Log Collector va maintenant collecter le log du périphérique et l\'envoyer à transdroid.org@gmail.com.\nVous pourrez voir et modifier les données envoyées.
+Aucun lecteur de fichier à distance n\'a pu être trouvé. Voulez-vous installer VLC Remote depuis l\'Android Market?
+Vous n\'avez pas de client FTP compatible.\nVoulez-vous installer AndFTP depuis l\'Android Market?
+
+Vitesse maximum de réception
+Vitesse maximum d\'envoi
+Seulement des valeurs numériques, en Ko/s
+Remise à zéro
+Votre client torrent ne supporte pas la gestion des vitesses de transfert ou ce n\'est pas encore implémenté.
+Vitesses de transfert mises à jour
+Suppression du torrent
+Êtes-vous certain de vouloir supprimer ce torrent ?
+Échec de l\'ajout
+Réessayer
+Ajouter ultérieurement
+
+Recherche en cours...
+Rechercher des torrents
+Torrents
+Ubuntu
+Résultats de
+Ajouter tous les sélectionnés
+Aucun résultat pour cette recherche.
+Aucun critère de recherche n\'a été fourni.
+Changer de site
+Télécharger maintenant
+Voir le site web
+Ouvrir avec...
+Partager le lien...
+Enregistrer en tant que flux RSS
+Utiliser en tant que nouvelle recherche
+Recherche enregistrée en tant que flux RSS
+Enregistrement non supporté pour ce site
+
+Préférences Transdroid
+Ajouter un nouveau serveur
+Ajouter un moteur de recherche
+Ajouter un flux RSS
+In-app searching
+Recherche à partir du Web
+Autres paramètres
+
+Paramètres du serveur
+Configuration simple
+Nom
+Alias optionnel
+Type de serveur
+IP ou nom de domaine
+Sans http:// ni numéro de port
+Port
+Généralement
+Utiliser l\'authentification
+Vous aurez besoin d\'un nom d\'utilisateur et d\'un mot de passe
+Nom d\'utilisateur
+Mot de passe
+OS du serveur
+Dossier SCGI
+Généralement /RPC2
+Dossier
+Par exemple /torrentflux
+Généralement vide
+Paramètres avancés (optionnel)
+Dossier de téléchargements
+Chemin absolu du dossier de téléchargements sur votre serveur
+Adresse (S)FTP racine
+Par exemple ftp://me@server.com/downloads/
+Délai de connexion dépassé
+Nombre de secondes avant l'expiration d'une tentative de connexion
+SSL
+Sélectionner pour utiliser https
+Empreinte du certificat SSL
+N\'autoriser que les connexions avec ce certificat
+Accepter tous les certificats SSL
+Sélectionner si le certificat est auto-signé
+
+Moteur de recherche
+Définir le site par défaut
+Adresse directe de recherche
+%1$s sera remplacé par la requête de recherche
+Nombre de résultats
+Ordre de tri des résultats
+Flux RSS
+Paramètres
+URL du flux
+Nécessite une authentification
+Ouvre les liens dans le navigateur pour s\'authentifier
+Constructeur de flux ezRSS
+Construisez un flux RSS de séries télévisées
+Afficher le nom
+Qualité
+Groupe
+La qualité et le groupe sont optionnels\nPropulsé par http://www.ezrss.it
+Correspondance exacte ↴
+Un exemple de flux sera affiché ici après avoir saisi votre requête
+Chargement...
+Cette requête retourne une liste d\'épisode vide
+
+Paramètres d\'interface
+Seulement les torrents en transfert (> 0KB/s)
+Afficher les torrents téléchargeant à 0KB/s comme inactifs
+Glisser entre les étiquettes
+Glisser entre les étiquettes plutôt que les serveurs
+Intervalle d\'actualisation
+Masquer l\'actualisation
+Ne pas afficher le message \'Liste des torrents actualisée\'
+Effacer l\'historique de recherche
+Historique effacé avec succès
+Confirmer la suppression
+Demander à confirmer la supression d\'un torrent
+Importer paramètres
+Transdroid tentera d\'importer les paramètres de serveurs, recherches web et RSS depuis :
+Paramètres importés avec succès
+Prenez les fichiers
+Exporter paramètres
+Transdroid exportera les paramètres de serveurs (mots de passe inclus), recherches web et RSS vers le fichier texte suivant :
+Paramètres exportés avec succès
+Prenez les dossiers
+Activer les pub
+Montrer les pub en bas de l\'écran
+
+Paramètres d\'alarme
+Activer le service d\'alarme
+M\'alerter au changement d\'état d\'un torrent
+Intervalle d\'alarme
+Délai entre deux vérifications des torrents
+Téléchargements
+Notifier quand un téléchargement se termine
+Nouveau torrent
+Notifier quand un nouveau torrent a été ajouté
+Activer le son d\'alarme
+Joue le son de notification avec l\'alarme
+Son d\'alarme
+Son de notification à jouer avec l\'alarme
+Activer vibration
+Vibrer avec l\'alarme
+Vérifier les fluxs RSS
+Alerter quand de nouveaux torrents sont disponibles
+Autoriser les notifications ADW
+Montrer le compteur torrent dans le lanceur ADW
+Compter seulement les téléchargements
+
+En attente de vérification...
+Vérification des données locales...
+En attente du téléchargement
+Erreur ...
+%1$s de %2$s (%3$s)
+%1$s, émis %2$s
+~ %1$s
+ETA inconnue
+ratio %1$s
+%1$s de %1$s pairs
+↑ %1$s
+↓ %1$s
+En pause
+Arrêté
+Inconnu
+/s
+
+Rafraichissement...
+Ajout du torrent...
+Envoi du torrent...
+Suppression du torrent...
+Mise en pause du torrent...
+Mise en pause de tous les torrents...
+Reprise du torrent...
+Reprise de tous les torrents...
+Arrêt du torrent...
+Arrêt de tous les torrents...
+Démarrage du torrent...
+Démarrage de tous les torrents...
+Récupération des fichiers...
+Paramétrage des propriétés du fichier...
+Paramétrage des taux de transfert...
+Ajout de l\'étiquette...
+Déplacement du torrent...
+Changement en cours ...
+
+Liste des torrents actualisée
+Torrent ajouté (actualisation)
+supprimé
+supprimé et données effacées
+reprise (actualisation)
+arrêté
+démarré (actualisation)
+en pause
+Torrents en pause
+Torrents repris (actualisation)
+Torrents arrêtés
+Torrents démarrés (actualisation)
+Trackers mis à jour
+Torrent déplacé vers \'%1$s\'
+
+Détails
+Fichiers
+Taille :
+État :
+Reçu :
+Emis :
+Transfert :
+ETA :
+Disponibilité :
+Pairs :
+Étiquette :
+Trackers:
+Erreurs :
+Lister les fichiers n\'est pas supporté par votre client torrent ou ce n\'est pas encore implanté
+Priorités du fichier mises à jour
+
+Ne pas télécharger
+Bas
+Normal
+Haut
+Lire à distance via VLC
+Télécharger avec (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Serveur
+Intervalle de rafraichissement
+Style
+Ajouter ce widget
+R @
+up
+E @
+inactif
+/s
+ETA
+ETA inconnu
+nouveau
+
+Nouveau torrent ajouté
+Téléchargement torrent terminé
+Nouveaux torrents disponibles
+%d nouveaux torrents de flux RSS
+
+RSS
+Aucun flux RSS n\'est installé\n\nUtiliser le menu pour en ajouter
+Chargement des flux RSS
+Connecté mais le flux RSS est vide
+
+Erreur pendant la communication avec le serveur
+Erreur lors de la création de la requête
+Erreur d\'analyse de la réponse du serveur (merci de vérifier vos paramètres)
+L\'interface web n\'est connectée à aucun processus en cours
+Accès refusé (veuillez vérifier vos paramètres)
+Impossible de lire le fichier .torrent
+Erreur d\'analyse du flux RSS
+Cette URL n\'est pas bien formée
+Votre URL de recherche est invalide :
+Ce n\'est pas une IP ou une adresse valide
+Le numéro de port doit être numérique
+Les chemins de répertoires se finissent par / ou \\
+L\'objet du flux RSS ne donne pas une URL qui pointe vers un fichier .torrent
+Le sujet du flux RSS ne fournit pas de lien pour accéder à
+L\'URL n\'est pas un flux RSS valide
+Carte SD indisponible en lecture ou écriture
+Le fichier ne semble pas contenir de paramètres Transdroid
+Aucun fichier de paramètres trouvé
+
+Xirvik propose des seedboxes partagées, semi-dédiées ou dédiées. Transdroid permet de configurer facilement tous les serveurs Xirvik.\n\nEn savoir plus sur www.xirvik.com
+Ajouter un serveur Xirvik
+Paramètres du serveur Xirvik
+Type de serveur
+Partagé, semi-dédié ou dédié
+Nom du serveur
+Comme dedi000.xirvik.com
+Serveur invalide (utiliser l\'adresse complète, comme dedi000.xirvik.com)
+
+SeedM8 propose un hébergement de seedbox sans limite de téléchargement. Transdroid permet de configurer facilement tous les serveurs SeedM8.\n\nEn savoir plus sur www.seedm8.com
+Ajouter un serveur SeedM8
+Paramètres du serveur SeedM8
+Nom du serveur
+Exemple : alpha.seedm8.com
+Serveur invalide (utiliser l\'adresse complète, comme alpha.seedm8.com)
+
+
+Ordre combiné
+Nombre de seeders/leechers
+
+
+
+Pas d\'actualisation automatique
+2 secondes
+5 secondes
+15 secondes
+1 minute
+5 minutes
+15 minutes
+1 heure
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 heure
+3 heures
+12 heures
+1 jour
+
+
+
+Android 1.5
+Android 1.6
+Boîte de recherche
+Noir
+Transparent
+
+
diff --git a/android/res/values-he/strings.xml b/android/res/values-he/strings.xml
new file mode 100644
index 00000000..bcea12db
--- /dev/null
+++ b/android/res/values-he/strings.xml
@@ -0,0 +1,160 @@
+
+
+תוכנת שליטה על תוכנות טורנט: Transmission, uTorrent, BitTorrent, rTorrent, Vuze and Deluge.
+
+פתח את תפריט ההגדרות בכדי להגדיר את השרת שלך
+פתח את תפריט ההגדרות בכדי להגדיר את השרת שלךnn לקבלת עזרה: www.transdroid.org/download
+פתח הגדרות
+מנסה להתחבר לשרת...
+מחובר, אך כרגע אין טורנטים.
+מחובר, אך כרגע לא מוריד טורנטים.
+מחובר, אך כרגע לא משתף טורנטים.
+מחובר, אך כרגע אין טורנטים לא פעילים
+שרת הטורנט שלך או האפליקציה לא תומכים בטעינת קבצי .torrent
+שמור
+
+
+
+הוסף
+RSS
+החלף שרת
+הגדר מהירות העברה
+בצע על כולם
+השהה את כולם
+המשך את כולם
+עצור את כולם
+התחל את כולם
+סנן רשימה
+סדר על פי.. (לחץ שנית כדי להפוך סדר)
+שם
+סטטוס
+תאריך סיום
+תאריך התחלה
+רק פעילים (> 0KB/s)
+הגדרות
+דוח שגיאה
+הסר
+הסר ומחק קבצים
+השהה
+המשך
+עצור
+התחל
+הפעל בכוח
+קבע כברירת מחדל
+אתר ברירת המחדל:
+
+הדבק כתובת לקובץ הטורנט
+כתובת לא תקינה
+בחר קובץ טורנט מקומי
+לא נמצא מנהל קמצים נתמך, כמו OI File Manager. התרצה להוריד אותו משוק התוכנות?\n\nלחילופין, ניתן להשתמש בתוכנה המועדפת עליך ולשלוח את הקובץ לטראנסדרואיד.
+התקן משוק התוכנות
+שוק התוכנות של אנדרואיד לא מותקן
+סורק הברקוד לא נמצא. האם תרצה להתקינו משוק האנדרואיד?
+כדי לשלוח דוח שגיאה, עליך להתקין תוכנה חופשית לאיסוף דוחות. האם ברצונך להתקין משוק התוכנות?
+תוכנת איסוף הדוחות מיד תאסוף ותשלח את הדוח לכתובת: transdroid.org@gmail.com\n\תוכל לראות ולערוך את המידע שישלח.
+
+מהירות הורדה מירבית
+מהירות העלאה מירבית
+מספרים בלבד, בקילו בייטים לשניה
+אפס
+שרת הטורנט שלך או האפליקציה לא תומכים ושינוי הגדרה זו.
+הגדרות מהירות עודכנו
+מחיקת טורנט
+האם אתה בטוח שברצונך למחוק את הטורנט?
+
+מחפש...
+חפש טורנטים באינטרנט
+מילת חיפוש
+הוסף את כל הנבחרים
+לא נמצאו תוצאות
+לא סיפקת טקסט לחיפוש
+החלף אתר
+הורד עכשיו
+פתח כתובת אינטרנט
+
+הגדרות טראנסדרואיד
+הוסף שרת חדש
+הוסף אתר חיפוש
+הוסף מקור RSS
+חיפוש מובנה
+חיפוש באתר-חיפוש
+הגדרות נוספות
+
+תוכנת שרת
+שם
+שם זיהוי (אופציונלי)
+סוג שרת
+כתובת או IP
+ללא http:// או מספר פורט
+פורט
+בד"כ
+הרשאות התחברות
+שימוש בשם וסיסמא כדי להתחבר
+שם
+סיסמא
+תיקיית SCGI
+בד"כ: /RPC2
+תיקייה
+/torrentflux : לדוגמה
+הצפנה (SSL)
+בחר כדי להשתמש ב-https
+קבל כל SSL certificate
+
+מנוע חיפוש
+כתובת שאילתת חיפוש
+%1$s יוחלף במילות החיפוש
+מספר תוצאות
+צורת סידור תוצאות
+מקורות RSS
+הגדרת מקור
+כתובת מקור
+
+הגדרות ממשק
+מרווח זמן רענון
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Black
+Transparent
+
+
diff --git a/android/res/values-hu/strings.xml b/android/res/values-hu/strings.xml
new file mode 100644
index 00000000..e665a4c6
--- /dev/null
+++ b/android/res/values-hu/strings.xml
@@ -0,0 +1,232 @@
+
+
+Torrent-kliens menedzser beépített keresővel, RSS-támogatással és megfigyelő widgettel
+
+Nyisd meg a Beállításokat, és add meg a kapcsolódási adatokat.
+Új Transdroid-felhasználó vagy? A www.transdroid.org/download címen találsz segítseget.\n\nAhhoz, hogy elkezdhess torrentezni, kérlek, add meg a szerver-beállításaidat:
+Beállítások megnyitása
+Kapcsolódás a szerverre...
+Kapcsolódva, de nincsenek torrentek a szerveren.
+Kapcsolódva, de nincs folyamatban lévő torrent letöltés a szerveren.
+Kapcsolódva, de nincs seedelt torrent a szerveren.
+Kapcsolódva, de nincs inaktív torrent a szerveren.
+A torrent-kliensed nem támogatja a .torrent file feltöltéseket, vagy nincs implementálva egyelőre.
+A torrent-kliensed nem támogatja a .magnet linkeket, vagy nincs implementálva egyelőre.
+Mentés
+Bezárás
+Torrent szerver
+Még nincs beállított szerver
+
+Összes mutatása
+Cimkék eltávolítása
+Új cimke
+A cimkézést nem támogatja a kliens
+
+Nézet váltása
+Minden torrent
+Letöltések
+Seedelő torrentek
+Inaktív torrentek
+
+Hozzáadás
+Vonalkód leolvasása
+RSS
+Szervel váltása
+Átviteli sebesség beállítása
+Mindre
+Összes szüneteltetése
+Összes újraindítása
+Összes leállítása
+Összes indítása
+Szűrők listája
+Rendezés (fordított)
+Név
+Állapot
+Hozzáadás dátuma
+Feltöltési sebesség
+Arány
+Beállítások
+Névjegy/Változások
+Hibajelentés
+Eltávolítás
+Eltávolítás és adatok törlése
+Szüneteltetés
+Újraindítás
+Megállítás
+Indítás
+Kényszerített indítás
+Cimke beállítása
+Letöltési hely megadása
+Beállítás alapértelmezettként
+Feljebb rendez
+Lejjebb rendez
+Trackerek szerkesztése
+Kijelölés megfordítása
+
+Add meg a torrent-file URL-jét
+Nem helyes URL
+Válassz egy lokális .torrent filet
+Telepítés a Marketről
+A Market alkalmazás nincs telepítve
+Barcode Scanner nem található. Telepítsük az Android Market-ből?
+
+Legmagasabb letöltési sebesség
+Legmagasabb feltöltési sebesség
+Torrent törlése
+Biztosan törölni szeretnéd ezt a torrentet?
+Hozzáadás sikertelen
+Nem sikerült %1$ hozzáadása. Megpróbálod újra, vagy hozzáaadod a várólistához?
+Nem sikerült %1$ hozzáadása. Megpróbálod újra?
+Újrapróbálkozás
+Hozzáadás később
+
+Keresés...
+Torrentek keresése a neten
+Torrentek
+Ubuntu
+Kijelöltek hozzáaadása
+Nincs találat
+Nincs keresési kifejezés megadva
+Letöltés most
+Weboldal megnyitása
+Megnyitás ezzel...
+Link megosztása...
+Elmentés RSS-ként
+A Torrent Search egy különálló modul, amihez egyszeri installálás után hozzáférsz. Beinstallálod most az Android Marketről?
+
+Transdroid beállítások
+Új szerver hozzáadása
+Torrentkereső hozzáadása
+RSS feed hozzáadása
+Appon belüli keresés
+Webes keresés
+Más beállítások
+
+Alapbeállítások
+Név
+Szerver típusa
+IP vagy domain név
+http:// és port-szám nélkül
+Port
+Általában
+Autentikáció használata
+Felhasználónév és jelszó szükséges
+Felhasználónév
+Jelszó
+Szerver operációsrendszer
+SCGI mappa
+Mappa
+Például /torrentflux
+Általában üres
+Haladó beállítások (opcionális)
+Letöltési könvytár
+Abszolút elérési út a letöltési könyvtárhoz a szervereden
+Például ftp://en@szerverem.com/letoltesek/
+Időtúllépés
+SSL
+Válassza ki https használatához
+
+Keresőmotor
+Alapértelmezett oldal
+Minőség
+Töltés...
+
+Felület beállítások
+Frissítés gyakorisága
+Frissítés elrejtése
+Eltávolítás megerősítése
+Beállítások importálása
+Beállítások exportálása
+Hírdetések engedélyezése
+
+Vibrálás engedélyezése
+
+Várakozás az ellenőrzésre
+Ellenőrzés
+Hiba...
+%1$s, feltöltött %2$s
+arány %1$s
+Szünetelve
+Leállítva
+Ismeretlen
+/mp
+
+Frissítés...
+Torrent hozzáadása...
+Torrent feltöltése...
+Torrent eltávolítása...
+Torrent szüneteltetése...
+Összes torrent szüneteltetése...
+Torrent folytatása...
+Összes torrent folytatása...
+Torrent leállítása...
+Összes torrent leállítása...
+Torrent indítása...
+Összes torrent indítása...
+Cimke hozzárendelése...
+Torrent mozgatása...
+
+Torrent lista frissítve
+Torrent hozzáadva (frissítés)
+eltávolítva
+
+Részletek
+Fájlok
+Méret:
+Letöltve:
+Feltöltve:
+Arány:
+Elérhetőség:
+Hiba:
+
+Alacsony
+Normál
+Magas
+
+Szerver
+Stílus
+LE @
+FEL @
+inaktív
+új
+
+Torrent hozzáadva
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 perc
+10 perc
+30 perc
+1 óra
+3 óra
+12 óra
+1 nap
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-it/strings.xml b/android/res/values-it/strings.xml
new file mode 100755
index 00000000..125eb60e
--- /dev/null
+++ b/android/res/values-it/strings.xml
@@ -0,0 +1,393 @@
+
+
+Un client torrent remoto con ricerca integrata, supporto RSS e widget di monitoraggio
+
+Apri il menù impostazioni per inserire i dettagli del tuo server.
+Apri il menù impostazioni per inserire i dettagli del tuo server.\n\nMaggiori info: www.transdroid.org/download
+Apri impostazioni
+Tentativo di connessione al server...
+Connesso, nessun torrent nel server.
+Connesso, nessun torrent in scaricamento sul server.
+Connesso, nessun torrent in seed sul server.
+Connesso, nessun torrent non attivo sul server.
+La tua applicazione torrent non supporta l\'apertura dei files .torrent o questa funzione non è ancora implementata.
+La tua applicazione torrent non supporta i collegamenti .magnet o questa funzione non è ancora implementata.
+Salva
+Annulla
+Server torrent
+Non è ancora stato configurato nessun server
+
+Mostra tutte
+Non etichettato
+Nuova etichetta
+L\'impostazione di etichette non è supportata dal tuo client
+
+Cambia visuale
+Tutti i torrent
+In scaricamento
+In seeding
+Inattivi
+
+Aggiungi
+Scansione codici a barre
+RSS
+Cambia server
+Velocità trasferimento
+Applica a tutti
+Pausa tutti
+Riprendi tutti
+Ferma tutti
+Inizia tutti
+Lista Filtri
+Ordina per
+Nome
+Stato
+Data completamento
+Aggiunto
+Velocità invio
+Rapporto
+Solo attivi (> 0KB/s)
+Impostazioni
+Info/Note di rilascio
+Segnala errori
+Rimuovi
+Rimuovi ed elimina i dati
+Elimina anche i dati
+Pausa
+Riprendi
+Ferma
+Inizia
+Forza avvio
+Imposta etichetta...
+Imposta percorso scaricati
+Imposta predefinito
+Sito predefinito
+Sposta su
+Sposta giù
+Modifica trackers
+Inverti selezione
+
+Incolla l\'URL del file torrent
+Il collegamento fornito non è un URL (valido)
+Seleziona un file .torrent locale
+Nessun gestore file supportato (es. OI File Manager). Vuoi installarlo utilizzando il Market?\n\nIn alternativa puoi usare il tuo gestore file preferito ed inviare il file .torrent a Transdroid
+Installa dal Market
+L\'applicazione "Android Market" non è installata
+Barcode Scanner non è stato trovato. Vuoi installarlo dal market?
+Per inviare un errore, è necessaria l\'applicazione gratuita e open-source Log Collector. Vuoi scaricarla dal Market?
+L\'applicazione Log Collector raccoglierà il log del telefono e lo invierà a transdroid.org@gmail.com.\nAvrai l\'opportunità di vedere e modificare i dati che verranno inviati.
+Non è stato rilevato un visualizzatore di file remoti, come ad esempio VLC Remote. Vuoi installare VLC Remote dal Market?
+Non hai installato un client FTP.\nVuoi installare AndFTP dal Market?
+
+Banda massima in ricezione
+Banda massima in invio
+Solo valori numerici, in KB/s
+Reimposta
+Il tuo client torrent non supporta l\'impostazione di velocità di trasferimento o la funzione non è ancora implementata.
+Velocità di trasferimento aggiornata
+Rimozione torrent
+Sei sicuro di voler rimuovere questo torrent?
+Aggiunta fallita
+Il torrent non può essere aggiunto.\nVuoi riprovare o metterlo in coda perchè sia auto-inserito più tardi?
+Il torrent non può essere aggiunto.\nVuoi riprovare?
+Riprova
+Aggiungi dopo
+
+Ricerca...
+Cerca online i torrent
+Torrent
+Ubuntu
+Risultati da
+Aggiungi tutti i selezionati
+Nessun risultato trovato per la tua ricerca
+Non è stato fornito alcun termine di ricerca.
+Cambia sito
+Scarica ora
+Apri sito web
+Apri con...
+Condividi collegamento...
+Salva come feed RSS
+Usa come nuova ricerca
+Cerca tra i salvati come feed RSS
+Salvataggio non supportato per questo sito
+Torrent Search è ora un modulo separato, perciò deve essere installato dal Market. Vuoi installarlo ora?
+
+Impostazioni Transdroid
+Aggiungi nuovo server
+Aggiungi un sito web di ricerca
+Aggiungi un feed RSS
+Ricerca integrata
+Ricerca via web
+Altre impostazioni
+
+Server
+Impostazioni base
+Nome
+Nome sito (opzionale)
+Tipo server
+IP o dominio
+Senza http:// o numero della porta
+Porta
+In genere
+Usa autenticazione
+Sono necessari nome utente e password
+Nome utente
+Password
+S.O. server
+Cartella SCGI
+Normalmente è /RPC2
+Cartella
+Per esempio /torrentflux
+Solitamente vuoto
+Impostazioni avanzate (opzionali)
+Cartella scaricati
+Il percorso assoluto alla cartella di scaricamento sul tuo server
+URL (S)FTP base
+Ad esempio ftp://mio@server.com/scaricati/
+Timeout connessione
+Numero di secondi prima di chiudere per timeout un tentativo di connessione
+SSL
+Seleziona per usare HTTPS
+Personalizza identificazione SSL
+Permetti connessioni solo da questo specifico certificato
+Accetta tutti i certificati SSL
+Seleziona se il certificato è auto-firmato
+
+Motore di ricerca
+Imposta sito predefinito
+Ricerca diretta da URL
+%1$s sarà sostituito con la domanda di ricerca
+Numero di risultati
+Ordine risultati
+Feed RSS
+Impostazioni dei Feed
+URL del Feed
+Richiede autenticazione
+Apri il collegamento nel browser per autenticazione
+Creazione feed ezRSS
+Crea un feed RSS per uno show TV
+Mostra nome
+Qualità
+Gruppo distribuzione
+Qualità e gruppo sono opzionali\nOfferto da http://www.ezrss.it
+corrispondenza esatta ↴
+Un feed di esempio verrà visualizzato dopo aver inserito una chiave di ricerca
+Caricamento...
+La chiave di ricerca fornisce una lista episodi vuota.
+
+Impostazioni interfaccia
+Solo attivi (> 0KB/s)
+Mostra i torrent a 0KB/s come inattivi
+Scorri etichette
+Striscia per scorrere le etichette anzichè i server
+Frequenza aggiornamento
+Nascondi aggiornamento
+Non mostrare il messaggio \'Lista dei torrent aggiornata\'
+Cancella cronologia di ricerca
+Cronologia di ricerca cancellata con successo
+Conferma rimozione
+Chiedi di confermare la rimozione di un torrent
+Importa le impostazioni
+Transdroid tenterà di importare le impostazioni di server, ricerche web e RSS da:
+Impostazioni importate con successo
+Scegli file
+Esporta le impostazioni
+Transdroid esporterà le impostazioni di server (incluse password), ricerche web e RSS nel seguente file:
+Impostazioni esportate con successo
+Scegli una cartella
+Abilita pubblicità
+Mostra avvisi nella parte bassa dello schermo
+
+Impostazioni servizio notifica
+Attiva il servizio notifica
+Avvisami quando lo stato di un torrent cambia
+Intervallo notifica
+Quanto spesso controllare i torrent
+Notifica completamento
+Notifica quando un torrent è completo
+Notifica nuovo torrent
+Notifica quando un nuovo torrent viene aggiunto
+Abilita allarme
+Riproduci suono di notifica con l\'allarme
+Allarme
+Suono di notifica da riprodurre con l\'allarme
+Abilita vibrazione
+Vibra all\'allarme
+Controlla i feed RSS
+Avvisa quando sono disponibili nuovi torrent
+Abilita notifiche ADW
+Mostra contatore torrent nel launcher ADW
+Solo conteggio scaricamenti
+Il contatore ADW include soltanto torrent in fase di scaricamento
+
+In attesa di verificare...
+Verificando dati locali...
+In attesa di scaricare %1$s
+Errore...
+%1$s di %2$s (%3$s)
+%1$s, inviati %2$s
+~ %s
+ETA sconosciuto
+rapporto %s
+%1$s di %1$s peers
+↑ %s
+↓ %s
+Pausa
+Fermo
+Sconosciuto
+/s
+
+Aggiornamento...
+Aggiunta torrent...
+Invio torrent...
+Rimozione torrent...
+Pausa torrent...
+Pausa tutti i torrent...
+Avvio torrent...
+Avvio tutti i torrent...
+Fermo torrent...
+Fermo tutti i torrent...
+Avvio torrent...
+Avvio tutti i torrent...
+Recupero file...
+Impostazione proprietà dei file...
+Impostazione velocità di trasferimento...
+Assegnazione etichetta...
+Spostamento torrent...
+Cambio modalità...
+
+Lista dei torrent aggiornata...
+Torrent aggiunto (aggiornamento)
+rimosso
+rimosso e dati eliminati
+torrent ripartiti (aggiornamento)
+fermato
+avviato (aggiornamento)
+in pausa
+Torrent in pausa
+Torrent riavviati (aggiornamento)
+Torrent fermato
+Torrent avviato (aggiornamento)
+Trackers aggiornati
+Torrent spostato in \'%1$s\'
+
+Dettagli
+File
+Dimensioni:
+Stato:
+Scaricati:
+Inviati:
+Rapporto:
+Eta:
+Disponibilità:
+Peers:
+Etichetta:
+Trackers:
+%1$s (apertura)
+(chiusura)
+Errori:
+La funzione di elenco file non è supportata o non è ancora stata implementata nel tuo client torrent
+Priorità file aggiornate
+
+Disattivo
+Bassa
+Normale
+Alta
+Esecuzione remota in VLC
+Scarica usando (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Intervallo aggiornamento
+Stile
+Aggiungi questo widget
+DL @
+su
+UP @
+inattivo
+/s
+eta
+eta sconosciuto
+nuovo
+
+Nuovo torrent aggiunto
+Torrent completato
+Nuovi torrent disponibili
+%d nuovi torrent da feed RSS
+
+RSS
+Nessun feed RSS presente\n\nUsa il menu per aggiungere nuovi Feed
+Caricamento Feed RSS
+Connesso, ma il feed RSS è vuoto
+
+Errore nella comunicazione col server
+Errore nella richiesta
+Errore nella risposta del server (controlla le tue impostazioni)
+Interfaccia web non connessa ad un server attivo
+Autenticazione non riuscita (controlla le tue impostazioni)
+Non è possibile leggere il file .torrent
+Errore nella risposta del feed RSS
+Questo URL non è stato inserito correttamente
+Il tuo URL di ricerca non è valido:
+IP o nome sistema inserito non corretto
+Il numero della porta è sempre un valore numerico
+I percorsi cartella terminano per / o \
+Il timeout non può essere vuoto e deve essere un numero positivo
+Il feed RSS non ha fornito un URL diretto ad un file .torrent
+Il feed RSS non fornisce un collegamento su cui effettuare una ricerca
+L\'URL non è un feed RSS valido
+Memoria SD non disponibile per la lettura/scrittura
+Il file non contiene impostazioni di Transdroid
+File di impostazioni non trovati
+
+Xirvik offre seedbox condivise, semi-dedicate o dedicate. Transdroid può essere facilmente configurato per qualsiasi server Xirvik.\n\nMaggiori info su www.xirvik.com
+Aggiungi server Xirvik
+Impostazioni server Xirvik
+Tipo server
+Condiviso, semi-dedicato o dedicato
+Nome server
+Ad es. dedi000.xirvik.com
+Server non valido (usa il nome sistema completo, come dedi000.xirvik.com)
+
+SeedM8 offre sistemi di seedbox GBit senza limiti. Transdroid permette una facile configurazione per i server SeedM8.\n\nAltre info su www.seedm8.com
+Aggiungi server SeedM8
+Impostazioni server SeedM8
+Nome server
+Come alpha.seedm8.com
+Server non valido (usa il nome sistema completo, come alpha.seedm8.com)
+
+
+Ordine combinato
+Numero di seeders/leechers
+
+
+
+Nessun aggiornamento automatico
+2 secondi
+5 secondi
+15 secondi
+1 minuto
+5 minuti
+15 minuti
+1 ora
+
+
+
+1 minuto
+10 minuti
+30 minuti
+1 ora
+2 ore
+3 ore
+12 ore
+
+
+
+Android 1.5
+Android 1.6
+Casella Ricerca Veloce
+Nero
+Transparent
+
+
diff --git a/android/res/values-nl/strings.xml b/android/res/values-nl/strings.xml
new file mode 100644
index 00000000..e4138afc
--- /dev/null
+++ b/android/res/values-nl/strings.xml
@@ -0,0 +1,395 @@
+
+
+Torrent client manager met geintegreerd zoeken, RSS ondersteuning en widget
+
+Gebruik het instellingenmenu om de server daemon te configureren.
+Gebruik het instellingenmenu om de server daemon te configureren.\n\nVoor meer info, zie: www.transdroid.org/download
+Open instellingen
+Verbinden met de server...
+Verbonden, maar er zijn geen torrents op de server.
+Verbonden, maar er zijn geen active downloads op de server.
+Verbonden, maar er zijn geen seeding torrents op de server.
+Verbonen, maar er zijn geen inactieve torrents op de server.
+Je torrentapplicatie ondersteund geen .torrent bestand uploads of dit is nog niet geïmplementeerd.
+Je torrentapplicatie ondersteund geen magnet links of dit is nog niet geïmplementeerd.
+Opslaan
+Sluiten
+Verversen
+Torrent server
+Er zijn nog geen servers geconfigureerd
+
+Toon alles
+Niet gelabeld
+Nieuw label
+Aanpassen van labels wordt niet ondersteund door je torrent client
+
+Wissel lijst
+Alle torrents tonen
+Alleen downloads tonen
+Seeding torrents tonen
+Inactieve torrents tonen
+
+Toevoegen
+Barcode scannen
+RSS
+Wissel server
+Zet maximumsnelheid
+Alles...
+Alles pauzeren
+Alles herstarten
+Alles stoppen
+Alles starten
+Lijst filteren
+Sorteren (kies opnieuw om volgorde om te keren)
+Naam
+Status
+Datum klaar
+Datum toegevoegd
+Upload snelheid
+Ratio
+Alleen actieve (> 0KB/s)
+Instellingen
+Over/Wijzigingen
+Foutrapport
+Verwijder
+Verwijder en wis data
+Ook data wissen
+Pauzeer
+Hervat
+Stop
+Start
+Forceer start
+Wijzig label...
+Downloadlocatie instellen...
+Als standaard gebruiken
+Standaard is nu
+Omhoog
+Omlaag
+Trackers aanpassen
+Selectie omdraaien
+
+Plak hier de URL van het torrent bestand
+Ongeldige URL ingevoegd
+Selecteer een lokaal .torrent bestand
+Er is geen ondersteunde applicatie voor bestandsbeheer gevonden, zoals OI File Manager. Wil je deze installeren uit de Android Market?\n\nAls alternatief kunt u een niet-ondersteunde applicatie openen en hierin het .torrent bestand openen met Transdroid.
+Installeren uit de Market
+De Android Market applicatie is niet geïnstalleerd
+De Barcode scanner is niet gevonden. Wil je deze installeren uit de Android Market?
+Om een foutrapport te versturen heb je de Log Collector applicatie nodig. Wil je deze nu uit de Android Market installeren?
+De Log Collector applicatie zal nu je foutenlog versturen naar transdroid.org@gmail.com.\nJe kunt van tevoren de gegevens nog inzien en wijzigen.
+Er is geen remote file viewer applicatie gevonden, zoals VLC Remote. Wil je deze installeren uit de Android Market?
+Er is geen ondersteunde FTP aplicatie geinstalleerd.\nWil je AndFTP installeren uit de Android Market?
+
+Maximum downloadsnelheid
+Maximum uploadsnelheid
+Alleen numerieke waarden, in KB/s
+Resetten
+Je torrent client heeft geen ondersteuning van het instellen van maximumsnelheden of dit is nog niet geimplementeerd.
+Maximumsnelheden aangepast
+Bevestig verwijderen
+Wil je deze torrent echt verwijderen?
+Toevoegen mislukt
+%1$s kan niet worden toegevoegd.\nWil je opnieuw proberen of later toevoegen?
+%1$s kan niet worden toegevoegd.\nWil je opnieuw proberen?
+Opnieuw
+Later toevoegen
+
+Zoeken
+Bezig met zoeken...
+Zoek on-line naar torrents
+Torrents
+Ubuntu
+Resultaten van
+Alle geselecteerde toevoegen
+Geen resultaten voor je zoekopdracht
+Er is geen zoekopdracht.
+Wissel site
+Download torrent
+Open website
+Openen met...
+Link delen...
+Opslaan als RSS feed
+Gebruik als zoekopdracht
+Opgeslagen als RSS feed
+Kan niet opslaan via deze website
+Torrent Search is tegenwoordig een aparte module, welke eenmalig geinstalleerd moet worden uit de Android Market. Nu installeren?
+
+Transdroid instellingen
+Nieuwe server toevoegen
+Nieuwe website toevoegen
+RSS feed toevoegen
+Zoeken vanuit applicatie
+Web-gebaseerde zoekopdracht
+Andere instellingen
+
+Server instellingen
+Standaardinstellingen
+Naam
+Optionele persoonlijke naam
+Server type
+IP/Domeinnaam
+Zonder http:// of poortnummer
+Poortnummer
+Is meestal
+Gebruik beveiliging
+Je hebt een gebruikersnaam en wachtwoord nodig
+Gebruiksnaam
+Wachtwoord
+Besturingssysteem
+SCGI folder
+Is meestal /RPC2
+Folder
+Bijvoorbeeld /torrentflux
+Is meestal leeg
+Geavanceerde instellingen (optioneel)
+Directory met downloads
+Het absolute pad van je downloads directory op de server
+Basis (S)FTP url
+Bijvoorbeeld ftp://me@server.com/downloads/
+Maximale verbindingstijd
+Aantal seconden voordat een poging wordt onderbroken
+SSL
+Kies om https te gebruiken
+Eigen SSL thumbprint invoeren
+Alleen verbindingen naar dit certificaat toestaan
+Accepteer alle SSL certificaten
+Nodig voor self-signed certificaat
+
+Zoekmachine
+Standaard site instellen
+Directe URL om te zoeken
+%s wordt vervangen door de zoekopdracht
+Aantal resultaten
+Sorteervolgorde resultaten
+RSS feeds
+Feed instellingen
+Feed URL
+Authenticatie vereist
+Opent links in de browser om toegang te krijgen
+ezRSS feedbouwer
+Een TV programma RSS feed samenstellen
+Programmanaam
+Kwaliteit
+Releasegroep
+Kwaliteit en releasegroep zijn optioneel\nAangeboden door http://www.ezrss.it
+exacte overeenkomst ↴
+Een voorbeeld van de feed verschijnt na het invoeren van je zoekopdracht
+Laden...
+Deze zoekopdracht geeft geen resultaten
+
+Interfaceinstellingen
+Alleen als actief (> 0KB/s)
+Toon alleen down- en upload >0 KB/s
+Slepen tussen labels
+Wissel tussen labels i.p.v. servers bij slepen
+Verversingsinterval
+Verberg verversbericht
+Toon geen \'Torrentlijst ververst\' meldingen
+Zoekhistorie legen
+Zoekhistorie geleegd
+Bevestig verwijderen
+Vraag om een bevestiging bij verwijderen van een torrent
+Importeer instellingen
+Transdroid zal alle server-, torrent site- en RSS feedinstellingen importeren van:
+Instellingen succesvol geïmporteerd
+Kies bestand
+Exporteer instellingen
+Transdroid zal alle server-, torrent site- en RSS feedinstellingen exporteren naar het tekstbestand:
+Instellingen succesvol geëxporteerd
+Directory kiezen
+Advertenties tonen
+Toon advertenties aan onderzijde van het scherm
+
+Alarmering instellingen
+Alarmeringen aanzetten
+Alarmeer bij torrent status wijzigingen
+Alarmeringsinterval
+Hoe vaak er gecontroleerd wordt
+Downloadalarmering
+Laat weten als een torrent is afgerond
+Nieuwe torrent alarmering
+Laat weten als er een torrent is toegevoegd
+Alarmtoon gebruiken
+Speel een geluid als het alarm af gaat
+Alarmtoon
+Af te spelen alarmtoon
+Trillen
+Trillen als het alarm af gaat
+Controleer RSS feeds
+Laat weten als er nieuwe torrents beschikbaar zijn
+ADW notificaties
+Toon torrent teller in ADW Launcher
+Alleen downloads tellen
+Tel alleen downloads in de ADW teller
+
+In de wacht...
+Lokale data verifiëren...
+Wachten om %s te downloaden
+Fout...
+%1$s van %2$s (%3$s)
+%1$s, %2$s geüpload
+~ %1$s
+resterend onbekend
+ratio %1$s
+%1$s van %1$s peers
+↑ %s
+↓ %s
+Gepauzeerd
+Stopped
+Onbekend
+/s
+
+Verversen...
+Toevoegen torrent...
+Uploaden torrent...
+Verwijderen torrent...
+Pauzeren torrent...
+Pauzeren van alle torrents...
+Hervatten torrent...
+Hervatten van alle torrents...
+Stoppen torrent...
+Stoppen van alle torrents...
+Starten torrent...
+Starten van alle torrents...
+Bestandslijst ophalen...
+Bestandsprioriteit aanpassen...
+Maximumsnelheden aanpassen...
+Label wijzigen...
+Verplaatsen torrent...
+Verwissel van modus...
+
+Torrentlijst ververst
+Torrent toegevoegd (nu verversen)
+verwijderd
+verwijderd en data gewist
+hervat (nu verversen)
+gestopt
+gestart (nu verversen)
+gepauzeerd
+Torrent(s) gepauzeerd
+Torrent(s) hervat (nu verversen)
+Torrent(s) gestopt
+Torrent(s) gestart (nu verversen)
+Trackers opgeslagen
+Torrent verplaatst naar \'%1$s\'
+
+Details
+Bestanden
+Grootte:
+Status:
+Gedownload:
+Geüpload:
+Snelheid:
+Resterend:
+Beschikbaar:
+Peers:
+Label:
+Trackers:
+%1$s (uitklappen)
+(inklappen)
+Fouten:
+Ophalen van de bestandslijst wordt niet door je torrentprogramma ondersteund of dit is nog niet geïmplementeerd
+Bestandsprioriteiten geüpdatet
+
+Uit
+Laag
+Normaal
+Hoog
+Remote afspelen met VLC
+Downloaden via (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Verversingsinterval
+Stijl
+Widget toevoegen
+DL @
+up
+UP @
+inactief
+/s
+resterend
+resterend onbekend
+nieuwe
+
+Nieuwe torrent toegevoegd
+Torrent download voltooid
+Nieuwe torrents beschikbaar
+%d nieuwe RSS feed torrents
+
+RSS
+Geen RSS feeds ingesteld\n\nGebruik het instellingenmenu om feeds toe te voegen
+RSS feed wordt geladen
+Verbonden, maar de RSS feed heeft geen items
+
+Fout tijdens communicatie met server
+Fout bij opbouwen verzoek
+Fout bij verwerken van serverreactie (controleer je instellingen)
+Web interface niet verbonden aan een daemon
+Geen toegang (controleer je gebruikersnaam en wachtwoord)
+Kan .torrent bestand niet lezen
+Fout bij het verwerken van de RSS feed
+Je URL is ongeldig
+Je zoeksite URL is ongeldig:
+Invoer is geen geldig IP adres of domeinnaam
+Het poortnummer moet numeriek zijn
+Directorypaden eindigen op een / of
+Verbindingstijd kan niet leeg zijn en is een positief nummer
+Het RSS feed item heeft geen URL enclosure dat naar een .torrent bestand verwijst
+De RSS feed biedt geen download link om te gebruiken
+URL is geen (geldig) RSS feed adres
+Geheugenkaart is niet beschikbaar
+Het bestand bevat geen Transdroid instellingen
+Geen bestand met instellingen gevonden
+
+Xirvik biedt gedeelde, semi-gedeelde en dedicated seedbox servers aan. In Transdroid zijn deze eenvoudig in te stellen.\n\nLees verder op www.xirvik.com
+Xirvik server toevoegen
+Xirvik server instellingen
+Servertype
+Gedeeld, semi-gedeeld of dedicated
+Servernaam
+Bijvoorbeeld dedi000.xirvik.com
+Ongeldige servernaam (gebruikt het volledige adres, zoals dedi000.xirvik.com)
+
+SeedM8 biedt ongelimiteerde GBit seedbox hosting aan. In Transdroid zijn deze eenvoudig in te stellen.\n\nLees verder op www.seedm8.com
+SeedM8 server toevoegen
+SeedM8 server instellingen
+Servernaam
+Bijvoorbeeld alpha.seedm8.com
+Ongeldige servernaam (gebruikt het volledige adres, zoals alpha.seedm8.com)
+
+
+Gecombineerde ordening
+Aantal seeders/leechers
+
+
+
+Niet automatisch verversen
+2 seconden
+5 seconden
+15 seconden
+1 minuut
+5 minuten
+15 minuten
+1 uur
+
+
+
+1 minuut
+10 minuten
+30 minuten
+1 uur
+3 uur
+12 uur
+1 dag
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Zwart
+Transparant
+
+
diff --git a/android/res/values-no/strings.xml b/android/res/values-no/strings.xml
new file mode 100644
index 00000000..957e82e6
--- /dev/null
+++ b/android/res/values-no/strings.xml
@@ -0,0 +1,330 @@
+
+
+En ekstern torrentklient for Transmission, uTorrent, BitTorrent, rTorrent, Vuze and Deluge.
+
+Åpne menyen "innstillinger" for å angi detaljer til serverens daemon.
+Åpne menyen "innstillinger" for å angi detaljer til serverens daemon.\n\nFor mer informasjon: www.transdroid.org/download
+Åpne innstillinger
+Forsøker å koble til server...
+Tilkoblet, men ingen torrents på serveren.
+Tilkoblet, men ingen torrents som laster ned på serveren.
+Tilkoblet, men ingen torrents som deles på serveren.
+Tilkoblet, men ingen inaktive torrents på serveren.
+Ditt torrentprogram har ikke støtte for opplasting av .torrent filer, eller har ikke implementert dette enda.
+Din torrent klient støtter ikke .magnet linker, eller at det ikke er implementert
+Lagre
+Slett
+Torrent server
+Ingen server har blitt konfigurert enda
+
+Vis alt
+Fjern etikett
+Ny etikett
+Etiketer er ikke støttet av din klient
+
+Vis alle torrents
+Viser torrents som lastes ned
+Viser torrents som deles
+Viser innaktive torrents
+
+Legg til
+RSS nyhetsstrøm
+Bytt server
+Velg nedlastingsrate
+Gjør for alle
+Pause alle
+Fortsett alle
+Stop alle
+Start alle
+Filtrer liste
+Sorter etter (resort to reverse order)
+Navn
+Status
+Dato ferdig
+Dato lagt til
+Opplastingshastighet
+Ratio
+Overfører bare (> 0KB/s)
+Settings
+Om/Endrings logg
+Error report
+Fjern
+Fjern og slett data
+Pause
+Fortsett
+Stopp
+Start
+Tving start
+Sett Etikett...
+Sett nedlastingssted
+Sett som standard
+Standard side satt som
+Flytt opp
+Flytt ned
+
+Lim inn torrentfilens URL
+Det du tastet inn er ikke en (gyldig) URL
+Velg en lokal .torrent-fil
+Installer fra market
+Applikasjonen Android Market er ikke installert
+Strekkode leseren er ikke installert. Ønsker du å installere den fra Android Market?
+For å sende en feilmelding må du installere applikasjonen Log Collector. Denne er gratis og er åpen kildekode. Ønsker du å installere denne fra Android Market?
+Applikasjonen Log Connector vil nå samle loggen fra enheten og sende den til transdroid.org@gmail.com.\nDu vil få mulighet til å kontrollere og endre informasjonen som sendes.
+Du har ikke en kompatibel FTP klient installert. \nØnsker du å installere AndFTP fra Android Market?
+
+Maksimal nedlastningsrate
+Maksimal opplastningsrate
+Kun numeriske verdier, i KB/s
+Tilbakestill
+Your torrent client does not support setting of transfer rates or this is not yet implemented.
+Overføringsrater oppdatert
+Fjerner torrent
+Er du sikker på at du vil fjerne denne torrenten?
+Legge til feilet
+Prøv igjen
+Legg til senere
+
+Søker...
+Søk etter torrents på nettet
+Torrents
+Ubuntu
+Resultater fra
+Legg til alle merkete
+Ditt søk ga ingen treff
+Ingen søkeforespørsel ble gitt.
+Bytt side
+Last ned nå
+Åpne nettsted
+Åpne med...
+Del link...
+Lagre som RSS nyhetsstrøm
+Søk lagret som RSS feed
+lagring støttes ikke fra dette nettstedet
+
+Transdroid innstillinger
+Legg til ny server
+Legg til søkeside
+Legg til RSS nyhetsstrøm
+In-app søk
+Web-basert søk
+Andre innstillinger
+
+Tjener deamon
+Grunnleggende innstillinger
+Navn
+Valgfritt personlig navn
+Server type
+IP eller domene navn
+Uten http:// eller port
+Port
+Som regel
+Bruk autentisering
+Du vil få bruk for brukernavn og passord
+Brukernavn
+Passord
+Server OS
+SCGI mappe
+Som regel /RPC2
+Mappe
+For eksempel /torrentflux
+Vanligvis tom
+Avanserte innstillinger (valgfritt)
+Nedlastnings mappe
+absolutt sti til nedlastingskatalogen på serveren
+For eksempel ftp://me@server.com/downloads/
+SSL
+Velg for å bruke https
+Aksepter alle SSL sertifikater
+Select if cert is self-signed
+
+Søkemotor
+Angi standard site
+DIrektesøk URL
+%s vil bli erstattet med ditt søkeordl
+Antall resultater
+Resultat sortering rekkefølge
+RSS nyhetsstrømmer
+Nyhetsstrøm innstillinger
+Nyhetsstrøm URL
+Krever godkjenning
+Åpner linker i nettleseren for å autentisere
+Vis navn
+Kvalitet
+Laster...
+
+Innstillinger for grensesnitt
+Skift mellom etiketter
+Bytt mellom etiketer istedenfor servere
+Oppdateringsintervall
+Skjul oppdater
+Ikke vis \'Torrentliste oppdatert\' beskjed
+Tøm søkehistorikk
+History cleared successfully
+Bekreft fjerning
+Spør om bekreftelse ved fjerning av en torrent
+importér innstillinger
+Innstillinger ble importert
+Eksport innstillinger
+Innstillinger ble eksportert
+
+Alarm innstillinger
+Aktivér alarm
+Varsle meg ved torrent status forandringer
+Alarm intervall
+Hvor ofte torrents skal sjekkes
+Nedlastningsalarm
+Varsle når en torrent er ferdig
+Ny torrent alarm
+Varsle når en ny torrent blir lagt til
+Aktivér alarmlyd
+Alarmlyd
+Aktivér vibrasjon
+vibrér ved alarm
+Kontroller RSS nyhetsstrøm
+Varsle når nye torrenter er tilgengelig
+
+Venter for å kontrollere...
+Kontrollerer lokale data...
+Venter til nedlastning %s
+%1$s av %2$s (%3$s)
+%1$s, opplastet %2$s
+~ %1$s
+ukjent eta
+ratio %1$s
+%1$s av %2$s peers
+↑ %1$s
+↓ %1$s
+Pauset
+Stoppet
+Ukjent
+/s
+
+Oppdaterer...
+Legger til torrent...
+Laster opp torrent...
+Fjerner torrent...
+Setter torrent på pause...
+Setter alle torrents på pause...
+Fortsetter torrent...
+Fortsetter alle torrents...
+Stopper torrent...
+Stopper alle torrents...
+Starter torrents...
+Starter alle torrents...
+Henter filer...
+Setter filegenskaper
+Setter overføringshastighet
+Tilordner etikett
+
+Torrentliste oppdatert
+Torrent lagt til (oppdaterer)
+Fjernet
+Fjernet og data slettet
+Gjenopptatt (oppdaterer)
+stoppet
+startet (oppdaterer)
+pauset
+Torrenter pauset
+Torrenter gjenopptatt (oppdaterer)
+Torrenter stoppet
+Torrenter startet (oppdaterer)
+
+Detaljer
+Filer
+Størrelse:
+Status:
+Nedlastet:
+Opplastet:
+Rate:
+Eta:
+Tilgjengelig:
+Peers
+Etikett:
+Fil prioriteter oppdatert
+
+Av
+Lav
+Normal
+Høy
+Fjernavspilling i VLC
+Last ned med (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Oppdaterings intervall
+Stil
+Legg
+DL @
+opp
+UP @
+inaktiv
+/s
+eta
+ukjent eta
+ny
+
+Ny torrent lagt til
+Torrent ferdig nedlastet
+Nye torrents tilgjengelig
+
+RSS
+Ingen installerte RSS nyhetsstrømmer\n\nBruk menyen for å legge til nyhetsstrømmer
+Laster RSS nyhetsstrøm
+Tilkoblet, men RSS nyhetsstrømmen er tom
+
+Feil under kommunikasjon med server
+Feil når forespørsel ble bygget
+Autentisering nektet (vennligst kontroller dine innstillinger)
+Kan ikke lese .torrent fil
+Feil ved tolking av RSS nyhetsstrøm
+Det du tastet inn er ikke en gyldig IP adresse eller et gyldig vertsnavn
+Et portnummer er alltid tall
+URL er ikke en (gyldig) RSS nyhetsstrøm
+SD kortet er ikke tilgjengelig for lese/skrive
+Filen ser ikke ut til å inneholde Transdroid innstillinger
+Finner ingen fil med innstillinger
+
+Legg til Xirvik server
+Innstillinger for Xirvik server
+Server type
+Server navn
+
+Legg til SeedM8 server
+SeedM8 server innstillinger
+Server navn
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Zwart
+Transparent
+
+
diff --git a/android/res/values-pl/strings.xml b/android/res/values-pl/strings.xml
new file mode 100644
index 00000000..145c5631
--- /dev/null
+++ b/android/res/values-pl/strings.xml
@@ -0,0 +1,370 @@
+
+
+Zdalny klient Transmission, uTorrent, BitTorrent, rTorrent, Buze oraz Deluge.huooo
+
+Otwórz ustawienia w celu skonfigurowania połaczeń.\n\nPo dalszą pomoc zajrzyj na www.transdroid.org/download
+Otwórz ustawienia
+Próba łączenia z serwerem...
+Połaczono, lecz brak torrentów na serwerze.
+Połączono, lecz brak torrentów do pobrania.
+Połączono, lecz brak torrentów do seedowania.
+Połączono, lecz brak nieaktywnych torrentów.
+Aplikacja nie wspiera plików *.torrent. Opcja nie jest jeszcze wspierana.
+Twój klient Torrent nie obsługuje linków typu .magnet bądź ta funkcjonalność jeszcze nie została zaimplementowana
+Zapisz
+Pomiń
+Serwer Torrent
+Serwery nie zostały jeszcze skonfigurowane
+
+Pokaż wszystkie
+Bez etykiety
+Nowa etykieta
+Ustawianie etykiet nie jest wspierane przez twojego klienta.
+
+Pokazano wszystkie torrenty
+Pokazano pobierane pliki torrent
+Pokazano seedowane pliki torrent
+Pokazano nieaktywne pliki torrent
+
+Dodaj
+RSS
+Zmień serwer
+Ustaw limit transferu
+Dla wszystkich
+Wstrzymaj wszystkie
+Wznów wszystkie
+Zatrzymaj wszystkie
+Uruchom wszystkie
+Filtrowanie listy
+Sortuj wg (sortuj w odwrotnej kolejności)
+Nazwa
+Status
+Data Pobrania
+Data Dodania
+Szybkość wysyłania
+Ratio
+Tylko powyżej (> 0KB/s)
+Ustawienia
+O programie/Lista zmian
+Raport błędów
+Usuń
+Usuń dane i torrent
+Wstrzymaj
+Wznów
+Zatrzymaj
+Uruchom
+Wymuś start
+Ustaw etykiete...
+Ustaw ścieżkę pobierania
+Ustaw Domyślnie
+Domyślna strona ustawiona na
+Do góry
+Do dołu
+
+Wklej adres URL lub pliku torrent.
+Wprowadzony link jest nieprawidłowy.
+Wybierz plik *.torrent.
+Nie wspierany menedżer plików, taki jak OI File Manager. Czy chces zainstalować go z Android Market?\n\nMożesz także uruchomić nieobsługiwany menedżer plików i przesłać samodzielnie torrent do Transdroid.
+Zainstaluj z marketu
+Aplikacja Android Market jest niezainstalowana.
+Barcode Scanner nie został odnaleziony. Czy chcesz zainstalować go z Android Market?
+Aby wysłać raport o błędach, musisz zainstalować aplikacje Log Collector. Czy chcesz ją teraz zainstaloawć?
+aplikacja Log Collector zbierze w tej chwili informacje i wyśle je na adres transdroid.org@gmail.com.\nBedziesz mieć możliwość przejrzenia i modyfikacji informacji które będą wysłane
+Zdalny podgląd pliku, taki jak VLC Remote, nie został odnaleziony. Czy chcesz zainstalować VLC Remote z Android Market?
+Nie posiadasz kompatybilnego klienta FTP.\nCzy chcesz zainstalować AndFTP z Android Market?
+
+Maksymalna prędkość pobierania
+Maksymalna prędkość wysyłania
+Tylko cyfry, w KB/s
+Reset
+Twój klient torrent nie obsługuje limitów lub ta funkcja nie jest zaimplementowana.
+Limity prędkości uaktualnione.
+Trwa usuwanie torrenta
+Na pewno chcesz usunąć ten torrent?
+Dodawanie się nie powiodło
+Ponów
+Dodaj później
+
+Wyszukiwanie...
+Szukaj torrentów on-line
+Torrenty
+Ubuntu
+Wyniki z
+Dodaj zaznaczone
+Niczego nie znaleziono.
+Nie wprowadzono frazy do wyszukania.
+Przełącz wyszukiwarkę
+Pobierz teraz
+Otwórz stronę
+Otwórz za pomocą...
+Poleć link...
+Zapisz jako RSS
+Użyj nowego szukania
+Wyszukiwanie zapisano jako RSS
+Zapisywanie nie jest wspierane dla tej strony
+
+Ustawienia Transdroid
+Dodaj nowy serwer
+Dodaj wyszukiwarkę
+Dodaj kanał RSS
+Szukaj w aplikacji
+Web-based searching
+Pozostałe ustawienia
+
+Server deamon
+Ustawienia podstawowe
+Nazwa serwera
+Opcjonalnie
+Typ serwera
+Adres IP lub domeny
+Wpisuj bez http:// oraz bez portu
+Port
+Przeważnie
+Użyj autoryzacji
+Potrzebny login oraz hasło
+Login
+Hasło
+OS serwera
+SCGI folder
+Przeważnie /RPC2
+Folder
+Przykładowo /torrentflux
+Zwyczajowo pusty
+Ustawienia zaawansowane(opcjonalnie)
+Katalog pobierania
+Bezwględna ścieżka do katalogu pobierania na twoim serwerze
+URL źródłowy (S)FTP
+Dla przykładu ftp://me@server.com/downloads/
+SSL
+Wybierz aby używać https
+Zmieniony SSL
+Zezwalaj na połączenia tylko do tego certyfikatu
+Akceptuj wszystkie certyfikaty
+Zaznacz jeśli certyfikat nie jest podpisany
+
+Wyszukiwarka
+Ustaw domyślną stronę
+Bezpośrednieo wyszukiwanie URL
+%s zostanie zastąpiony szukaną frazą
+Ilość wyników
+Sortuj według
+Kanał RSS
+Ustawienia kanału
+URL kanału
+Wymaga uwierzytelnienia
+Otwiera link w przeglądarce, w celu uwierzytelnienia
+Kreator powiadomień ezRSS
+Stwórz telewizyjny program RSS
+Nazwa serialu
+Jakość
+Grupa
+Jakość i grupa wydająca są opcjonalne
+Dokładne dopasowanie ↴
+Przykład kanału pojawi się tutaj po wejściu zapytanie
+Ładowanie...
+To zapytanie pokazuje pustą listę
+
+Ustawienia interfejsu
+Pokaż tylko aktywne (> 0KB/s)
+Torrenty niewysyłane pokaż jako nieaktywne
+Zwiń etykiety
+Zwiń pobiędzy etykiety, a nie serwery
+Interwał odświeżania
+Ukryj przycisk odśwież
+Nie pokazuj komunikatu \'Lista torrentów odświeżona\'
+Wyczyść historię wyszukiwania
+Historia wyczyszczona poprawnie!
+Potwierdź usunięcie
+Potwierdź w celu usunięcia pliku torrent
+Importuj Ustawienia
+Transdroid próbuje zimportować ustawienia serwera, wyszukiwania i RSS z:
+Ustawienia zimportowane
+Wybierz plik
+Eksportuj Ustawienia
+Transdroid wyeksportuje serwer (z hasłami), wyszukiwanie w internecie i ustawienia RSS do następującego pliku tekstowego:
+Ustawienia zostały wyeksportowane
+Wybierz folder
+
+Alarm ustaweień
+Włącz powiadomienia ustawień
+Powiadom kiedy zmieni się status Torrenta
+Alarm przerwy
+Jak często sprawdzasz torrenty
+Powiadomienie pobierania
+Powiadom gdy pobieranie zostanie ukończone
+Powiadomienie o nowym Torrrenicie
+Powiadom kiedy dodany zostanie nowy torrent
+Alarm dźwiękowy
+Odtwórz dzwięk podczas powiadomienia
+Alarm dzwiękowy
+Dźwięk powiadomienia uruchamiany z powiadomieniem
+Aktywuj wibracje
+Wibruj podczas powiadomień
+Sprawdzanie RSS
+Powiadom gdy nowy torrent jest dostępny
+Włącz powiadomienia ADW
+Pokaż torrent w ADW
+Policz tylko pliki do pobrania
+Licznik ADW zawiera tylko pobierane torrenty
+
+Czekam na sprwadzenie
+Weryfikacja danych
+Czekam na pobieranie %s
+%1$s z %2$s (%3$s)
+%1$s, wysłano %2$s
+~ %1$s
+eta nieznany
+ratio %1$s
+%1$s z %2$s peerów
+↑ %1$s
+↓ %1$s
+Wstrzymano
+Zatrzymano
+Nieznane
+/s
+
+Odświeżanie...
+Dodawanie pliku torrent...
+Pobieranie pliku torrent...
+Usuwanie pliku torrent...
+Wstrzymywanie pliku torrent...
+Wstrzymywanie wszystkich plików torrent...
+Wznawianie pliku torrent...
+Wznawianie wszystkich torrentów...
+Zatrzymywanie pliku torrent...
+Zatrzymywanie wszystkich torrentów...
+Uruchamianie pliku torrent...
+Uruchamianie wszystkich torrentów...
+Pobieranie plików...
+Ustawienie właściwości pliku...
+Ustawienie szybkości transferu...
+Przypisywanie etykiet...
+
+Lista torrentów odświeżona
+Torrent dodany (odświeżanie)
+Usunięty
+Usunięty wraz z danymi
+Torrent wznowiony (odświeżanie)
+Torrent zatrzymany
+Torrent uruchomiony (odświeżanie)
+Torrent wstrzymany
+Torrenty wstrzymane
+Torrenty wznowione (odświeżanie)
+Torrenty zatrzymane
+Torrenty uruchomione (odświeżanie)
+
+Szczegóły
+Fragmenty
+Rozmiar:
+Status:
+Pobieranie:
+Wysyłanie:
+Prędkość:
+Pozostało:
+Dostępność:
+Pobierający:
+Etykieta:
+Listowanie plików nie jest wspieranie przez klienta torrenta lub nie zostało zaimplementowane
+Priorytety zostały zaaktualizowane
+
+Wyłączony
+Niski
+Normalny
+Wysoki
+Zdalny odtwarzanie za pomocą VLC
+Pobierz za pomocą (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Serwer
+Czasu odświeżania
+Styl
+Dodaj ten widget
+DL @
+up
+UP @
+nieaktywny
+/s
+eta
+eta nieznany
+nowy
+
+Dodano nowy plik torrent
+Torrent został pobrany
+Nowy torrenty są dostępne
+%d nowych torrentów z RSS
+
+RSS
+Brak kanaów RSS.\n\nPrzejdź do menu aby dodać nowe.
+Wczytywanie RSS
+Połączono, lecz kanał RSS jest pusty.
+
+Błąd podczas łączenia z serwerem.
+Bład połączenia
+Bład w przetwarzaniu odpowiedzi serwera (sprawdź ustawienia)
+Interfejs webowy nie jest połaczony z usługą
+Autoryzacja zakończona niepowodzeniem (sprwadź ustawienia)
+Nie mogę odczytać pliku *.torrent
+Błąd podczas odczytywania kanału RSS
+Ten adres jest źle skonstruowany
+Twoja sieciowa wyszukiwarka URL jest nieprawidłowa:
+Wprowadzone dane nie są prawidłowym adresem IP/domeną
+Numer portu musi być numeryczny
+Ścieżki katalogów kończą się na \ lub /
+Kanał RSS nie przekazuje prawidłowego linku do pliku *.torrent
+RSS nie posiada linki do pobierania.
+URL nie jest (prawidłowym) adresem RSS
+Karta SD nie jest dostępna do odczytu/zapisu
+Plik wydaje się nie zawierać ustawień Transdroid\'a
+Nie znaleziono pliku z ustawieniami
+
+Xirvik oferuje wspólne, częściowo wydzielone lub przeznaczone ustwawienia. Transdroid zapewnia łatwą konfigurację wszystkich serwerów Xirvik. \ n \ nCzytaj więcej na:www.xirvik.com
+Dodaj serwer Xirvik
+Ustawienia serwera Xirvik
+Typ serwera
+Dzielony, połowicznie lub dedykowany
+Nazwa serwera
+Na przykład: dedi000.xirvik.com
+Zły serwer (użyj pełnej nazwy hosta, np dedi000.xirvik.com)
+
+SeedM8 oferuje niemierzalne GBit hosting. Transdroid zapewnia łatwy edytorów serwerów SeedM8 \ n \ nCzytaj więcej na: www.seedm8.com
+Dodaj Serwer SeedM8
+Ustawienia serwera SeedM8
+Nazwa serwera
+Np. alpha.seedm8.com
+Niewłaściwy serwer (użyj pełnej nazwy, np. alpha.seedm8.com)
+
+
+Łączna liczba osób
+Liczba od seedów/leecherów
+
+
+
+Brak automatyczego odświeżania
+2 sekundy
+5 sekund
+15 sekund
+1 minuta
+5 minut
+15 minut
+1 godzina
+
+
+
+1 minuta
+10 minut
+30 minut
+1 godzina
+3 godziny
+12 godzin
+1 dzień
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Czarny
+
+
+
diff --git a/android/res/values-pt/strings.xml b/android/res/values-pt/strings.xml
new file mode 100644
index 00000000..b6f73570
--- /dev/null
+++ b/android/res/values-pt/strings.xml
@@ -0,0 +1,391 @@
+
+
+Um cliente torrent com pesquisa integrada, suporte a RSS e widget de monitoração
+
+Abra o menu de configurações para definir as informações do seu servidor.
+Novo no Transdroid? Obtenha ajuda para instalação em www.transdroid.org/download\n\nPara começar, por favor insira as configurações do servidor:
+Abrir configirações
+Tentando conectar ao servidor...
+Conectado, mas não há torrents no servidor.
+Conectado, mas não há torrents baixando no servidor.
+Conectado, mas não há torrents semeando no servidor.
+Conectado, mas não há torrents ativos no servidor.
+Seu cliente torrent não suporta o envio de arquivos .torrent ou a funcção ainda não foi implementada.
+Seu cliente torrent não suporta magnet links ou a função ainda não está implementada.
+Salvar
+Fechar
+Servidor Torrent
+Nenhum servifor foi configurado ainda
+
+Mostrar todos
+Sem etiqueta
+Nova etiqueta
+Seu cliente não permite a atribuição de etiquetas
+
+Mudar visão
+Todos os torrents
+Torrents ativos
+Torrents semeados
+Torrents inativos
+
+Adicionar
+Capturar cód barras
+RSS
+Trocar de servidor
+Definir taxas transferência
+Fazer para todos
+Interromper todos
+Retomar todos
+Parar todos
+Iniciar todos
+Lista de filtros
+Ordenar por (ordene novamente para inverter)
+Nome
+Estado
+Concluído em
+Adicionado em
+Velocidade envio
+razão
+Apenas transferindo (> 0KB/s)
+Configurações
+Sobre/Changelog
+Comunique erros
+Remover
+Remover e apagar dados
+Também apagar dados
+Interromper
+Retomar
+Parar
+Iniciar
+Forçar Início
+Definir etiqueta...
+Definir local de download...
+Marcar como padrão
+Site padrão definido para
+Mover para cima
+Mover para baixo
+Editar trackers
+Inverter seleção
+
+Cole a URL do arquivo torrent
+O endereço inserido não é uma URL válida
+Selecione um arquivo .torrent local
+Nenhum gerenciador de arquivos suportado, como OI FIle Manager, foi encontrado. Deseja instalá-lo a partir do Android Market?\n\nAlternativamente, você pode abrir outro gerenciador de arquivos e enviar um arquivo .torrent para o Transdroid.
+Instalar do Market
+A aplicação Android Market não está instalada
+O leitor de códigos de barra não foi encontrado. Deseja instalá-lo a partir do Android Market?
+É necessário instalar o Log Collector (gratuito e open source) para enviar um relatório de erros. Deseja instalá-lo a partir do Android Market?
+O Log Collector irá coletar informações do seu dispositivo e enviar para o e-mail transdroid.org@gmail.com.\nVocê terá a oportunidade de rever e modificar o conteúdo da mensagem.
+Não foi encontrado um visualizador de arquivos remotos, como o VLC Remote. Deseja instalá-lo a partir do Android Market?
+Não foi encontrado um cliente de FTP compatível.\nDeseja instalar o AndFTP a partir do Android Market?
+
+Taxa máxima download
+Taxa máxima upload
+Apenas números, em KB/s
+Reiniciar
+Seu cliente torrent não permite configurar taxas de transferência, ou esta função ainda não foi implementada.
+Taxas de transferência atualizadas
+Removendo torrent
+Tem certeza que quer remover este torrent?
+Inclusão falhou
+%1$s não pôde ser incluído agora.\nDeseja tentar novamente ou adicionar depois??
+%1$s não pôde ser incluído agora.\nDeseja tentar novamente?
+Tentar novamente
+Adicionar depois
+
+Pesquisando...
+Pesquisar por torrents online
+Torrents
+Ubuntu
+Resultados de
+Adicionar todos selecionados
+Nenhum resultado encontrado para a pesquisa
+Nenhum termo foi fornecido
+Trocar site
+Baixar agora
+Abrir site
+Abrir com...
+Compartilhar link...
+Salvar como feed RSS
+Usar como nova pesquisa
+Pesquisa salva como feed RSS
+Site não suporta salvamento
+Pesquisa torrent agora é um módulo separado, a ser instalado do Android Market. Instalar agora?
+
+Preferências do Transdroid
+Adicionar novo servidor
+Adicionar site de pesquisa
+Adicionar feed RSS
+Pesquisa local
+Pesquisa na web
+Outras configurações
+
+Servidor
+Configurações básicas
+Nome
+Nome pessoal opcional
+Tipo do servidor
+IP ou nome do domínio
+Sem http:// ou número da porta
+Porta
+Geralmente é
+Usar autenticação
+É necessário nome de usuário e senha
+Usuário
+Senha
+SO do servidor
+Pasta SCGI
+Geralmente é /RPC2
+Pasta
+Por exemplo /torrentflux
+Geralmente vazio
+Configurações avançadas (opcional)
+Pasta de downloads
+Caminho absoluto da pasta de downloads em seu servidor
+Endereço base (S)FTP
+Por exemplo ftp://me@server.com/downloads/
+Timeout de conexão
+Segundos até abortar uma tentativa de conexão
+SSL
+Selecione para utilizar https
+Identificação SSL personalizada
+Permitir apenas conexões com este certificado específico
+Aceitar todos os certificados SSL
+Permitir conexões com certificados auto-assinados
+
+Motor de busca
+Definir site padrão
+URL de pesquisa direta
+%s serão substituidos pelos termos de pesquisa
+Número de resultados
+Ordenar resultados
+Feeds RSS
+Configurações do feed
+Endereço do feed
+Requer autenticação
+Abrir links no navegador para autenticar
+Criador de feeds ezRSS
+Criar um feed RSS para um programa de televisão
+Nome do programa
+Qualidade
+Grupo
+A qualidade e o grupo são opcionais\nOferecido por http://www.ezrss.it
+cópia exata↴
+Um exemplo de feed aparecerá aqui após a inserção dos termos
+Abrindo...
+A pesquisa retornou uma lista de episódios vazia
+
+Configurações da interface
+Apenas baixando (>0 KB/s)
+Mostrat torrents baixando a 0KB/s como inativos
+Bater etiquetas
+Bater entre etiquetas ao invés de servidores
+Intervalo de atualização
+Esconder atualização
+Não mostrar mensagem \'Lista de torrents atualizada\'
+Eliminar histórico de busca
+Histórico eliminado com sucesso
+Confirme a remoção
+Confirmar a remoção de um torrent
+Importar definições
+Transdroid tentará importar servidor, busca web e configurações RSS de:
+Configurações importadas com sucesso
+Escolher arquivo
+Exportar configurações
+Transdroid exportará servidores (e suas senhas), busca web e configurações RSS para o seguinte arquivo texto:
+Configurações exportadas com sucesso
+Escolher pasta
+Permitir anúncios
+Mostrar anúncios no rodapé da tela
+
+Configurações do serviço de avisos
+Habilitar serviço de avisos
+Avisar quando o status do torrent mudar
+Intervalo dos avisos
+Frequência de verificação dos torrents
+Aviso de download
+Avisar o término de um torrent
+Aviso de novo torrent
+Avisar a inclusão de um novo torrent
+Habilitar avisos com som
+Tocar som ao avisar
+Som do alarme
+Som a ser tocado com o aviso
+Habilitar vibração
+Vibrar com aviso
+Verificar feeds RSS
+Avisar quando novo torrent está disponível
+Habilitar notificações ADW
+Mostrar contador de torrents no ADW
+Contar apenas downloads
+Contador ADW inclui apenas torrents em download
+
+Aguardando verificação...
+Verificando dados locais...
+Em espera para baixar %s
+Erro...
+%1$s de %2$s (%3$s)
+%1$s, enviado %2$s
+~ %1$s
+sem estimativa
+relação %1$s
+%1$s de %2$s peers
+↑ %1$s
+↓ %1$s
+Interrompido
+Parado
+Desconhecido
+/s
+
+Atualizando...
+Adicionando torrent...
+Subindo torrent...
+Removendo torrent...
+Pausando torrent...
+Pausando todos os torrents...
+Retomando torrent...
+Retomando todos os torrents...
+Parando torrent...
+Parando todos os torrents...
+Iniciando torrent...
+Iniciando todos os torrents...
+Recuperando arquivos...
+Gravando propriedades do arquivo...
+Gravando taxas de transferência...
+Associando etiqueta...
+Movendo torrent...
+Alterando modo...
+
+Lista de torrents atualizada
+Torrent adicionado (atualizando)
+removido
+removido e seus dados apagados
+retomado (atualizando)
+parado
+iniciado (atualizando)
+interrompido
+Torrents interrompidos
+Torrents retomados (atualizando)
+Torrents parados
+Torrents iniciados (atualizando)
+Trackers atualizados
+Torrent movido para \'%1$s\'
+
+Detalhes
+Arquivos
+Tamanho:
+Estado:
+Baixados:
+Enviados:
+Relação:
+Estimativa:
+Disponibilidade:
+Peers:
+Etiqueta:
+Trackers:
+%1$s (expandir)
+(ocultar)
+Erros:
+A listagem de arquivos não é permitida pelo seu cliente, ou a função ainda não foi implementada
+Prioridade dos arquivos atualizada
+
+Desligado
+Baixa
+Normal
+Alta
+Reprodução remota no VLC
+Descarregar usando (S)FTP
+
+Servidor
+Intervalo de atualização
+Estilo
+Adicionar widget
+DL @
+up
+UP @
+inativo
+/s
+estim
+sem estimativa
+novo
+
+Novo torrent adicionado
+Torrent concluído
+Novos torrents disponíveis
+%d novo torrent feed RSS
+
+RSS
+Não há feeds RSS instalados\n\nUse o menu para adicionar um novo
+Carregando o feed RSS
+Conectado, mas o feed RSS está vazio
+
+Erro durante a comunicação com o servidor
+Erro ao gerar o pedido
+Erro ao interpretar a resposta do servidor (verifique as configurações)
+A interface web não está conectada a um serviço ativo
+Erro de autenticação (verifique as configurações)
+Não foi possível ler arquivo .torrent
+Erro ao interpretar o feed RSS
+URL não está bem construída
+Sua URL de busca é inválida:
+Valor não é um IP ou domínio válido
+O número da porta é sempre numérico
+Caminhos de diretório terminam com / ou
+Timeout precisa ser um número positivo
+O item RSS não contém um endereço para um arquivo .torrent
+O item RSS não contém um link para abrir no browser
+O endereço não é um feed RSS válido
+Cartão SD não disponível para leitura/gravação
+Arquivo não contém configurações do Transdroid
+Não foi encontrado arquivo de configuração
+
+A Xirvik oferece servidores partilhados, semi-dedicados ou dedicados. O Transdroid inclui configuração fácil para todos os servidores Xirvik\n\nLeia mais em www.xirvik.com
+Adicionar servidor Xirvik
+Configurações do servidor Xirvik
+Tipo de servidor
+Partilhado, semi- ou dedicado
+Nome do servidor
+Por exemplo: dedi000.xirvik.com
+Servidor inválido (use o nome completo, como dedi000.xirvik.com)
+
+SeedM8 oferece hosting de seedbox GBit ilimitado. Transdroid provê configuração simples para servidores SeedM8. Veja mais em www.seedm8.com
+Adicionar servidor SeedM8
+Definições do servidor SeedM8
+Nome do servidor
+Como alpha.seedm8.com
+Servidor inválido (use todo o nome do host, como alpha.seedm8.com)
+
+
+Ordenação combinada
+Número de seeders/leechers
+
+
+
+Sem atualização automática
+2 segundos
+5 segundos
+15 segundos
+1 minuto
+5 minutos
+15 minutos
+1 hora
+
+
+
+1 minuto
+10 minutos
+30 minutos
+1 hora
+3 horas
+12 horas
+1 dia
+
+
+
+Android 1.5
+Android 1.6
+Pesquisa Rápida
+Preto
+Transparente
+
+
diff --git a/android/res/values-ro/strings.xml b/android/res/values-ro/strings.xml
new file mode 100644
index 00000000..c56387ac
--- /dev/null
+++ b/android/res/values-ro/strings.xml
@@ -0,0 +1,277 @@
+
+
+Manager de torrenti cu functii de cautare, suport RSS si widget
+
+Deschide meniul de setări pentru a introduce detalile serverului.
+Deschide meniul de setări pentru a introduce detalile serverului.\n\nPentru mai multe detalii: www.transdroid.org/download
+Deschide setarile
+Se incearcă conectarea la server...
+Conectat, dar nu sunt torrenti pe server.
+Conectat, dar nu sunt torenți la download pe server.
+Conectat, dar nu sunt torenți la seeduit pe server.
+Conectat, dar nu sunt torenți inactivi pe server.
+Aplicația ta de torenți nu are implementat sau nu suportă fișierele de tip .torrent.
+Salveaza
+Anuleaza
+Server Torrent
+Nu a fost configurat nici un server
+
+Arata tot
+Fara eticheta
+Eticheta noua
+
+Arata toti torrentii
+Arata torrentii care downloadeaza
+
+Adaugă
+RSS
+Switch server
+Seteaza rata de transfer
+Pauză pentru toate
+Reincepe pentru toate
+Oprește pentru toate
+Incepele pe toate
+Listă de filtre
+Sorteaza dupa
+Nume
+Status
+Data terminării
+Data adaugării
+Viteza upload
+Ratio
+Setari
+Despre
+Indepărtează
+Indepărtează și șterge datele
+Pauză
+Reincepe
+Oprește
+Incepe
+Forteaza inceperea
+Seteaza eticheta
+Seteaza ca implicit
+Site-ul implicit este setat
+
+Pastează URLul fișierului torrent
+Adresa introdusă nu este un URL valid
+Instaleaza din market
+
+Reincearca
+Adauga mai tarziu
+
+Se caută...
+Caută torenți online
+ultimele filme
+Rezultate de la
+Nu au fost găsite rezultate în urma căutarii
+Nu a fost introdus nici un termen de căutare.
+Schimba site
+Descarcă acum
+Website deschis
+Deschide cu
+Imparte linkul
+Salveaza ca feed RSS
+Cauta in feed-ul RSS salvat
+
+Preferințe
+Adaugă un nou server
+Adaugă un nou site de căutare
+Adauga feed RSS
+Cautare in-app
+Căutare Web-based
+Alte setări
+
+Demon server
+Setari de baza
+Nume
+Nume personal optional
+Tipul serverului
+IP sau nume de domeniu
+Fără http:// sau numărul portului
+Port
+În general este
+Foloseste autentificare
+Ai nevoie de un username și de o parola
+Username
+Parola
+Server OS
+Folder SCGI
+În general este /RPC2
+Dosar
+Exemplu /torrentflux
+Setari avansate (optional)
+Director download-uri
+Alege sa folosesti https
+
+Motor de căutare
+Alege site implicit
+căutare directă URL
+%s o să fie inlocuit de termenul de căutare
+Număr de rezultate
+Ordinea sortării rezultatelor
+Feeduri RSS
+Setari feed
+URL feed
+Arata nume
+Calitate
+Se incarca...
+
+Setari interfata
+Alege intre etichete
+Interval împrospatare
+Ascunde reîmprospatarea
+Nu arăta mesajul \'Lista de torenți reimprospatata\'
+Șterge istoria căutarilor
+Istoria căutarilor a fost stearsa cu succes
+Confirma inlaturarea
+Intreaba-ma sa confirm stergerea unui torrent
+
+Setari alarme service
+Porneste alarme service
+Anunta-ma cand se schimba statusul la un torrent
+Interval alarme
+Cat de des sa verifice torrentii mei
+Descarca alarme
+Anunta-ma cand un torrent este completat
+Alarma torrent nou
+Anunta-ma cand un torrent a fost adaugat
+Verifica feed-urile RSS
+Alarma cand noi torrenti sunt disponibili
+
+Aștept să verific...
+Verific datele locale...
+Aștept să descarc %s
+%1$s de %2$s (%3$s)
+%1$s, uploadat %2$s
+~ %1$s
+Estimare necunoscută
+ratio %1$s
+%1$s de %2$s Parteneri
+↑ %1$s
+↓ %1$s
+Pauză
+Oprit
+Necunoscut
+/s
+
+Se reimprospateaza...
+Adaug torrent...
+Urc torrent...
+Indepartez torrent...
+Intrerup torrent...
+Se intrerup toti torrentii...
+Reincep torrent...
+Reincep toti torrentii...
+Opresc torrent...
+Opresc toti torrentii...
+Incep torrent...
+Incep toti torrentii...
+Se recupereaza fisierele...
+Setez proprietati fisiere...
+Setez viteze transfer...
+
+Lista de torenți reîmprospătată
+Torent adaugat (se reîmprospătează)
+indepartat
+indepartat si sters date
+Torent reînceput (se reîmprospătează)
+Torent oprit
+Torent pornit (se reîmprospătează)
+intrerupt
+Torrent intrerupt
+Torrent reinceput (se reimprospateaza)
+Torrent oprit
+Torrent pornit
+
+Detalii
+Fisiere
+Marime:
+Conditie:
+Descarcat:
+Uploadat:
+Rata:
+ETA:
+Disponibilitate:
+Eticheta:
+
+Oprit
+Mic
+Normal
+Mare
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Interval reimprospatare
+Stil
+Adauga acest widget
+DL @
+up
+UP @
+inactiv
+/s
+Estimare
+Estimare necunoscuta
+nou
+
+Torrent nou adaugat
+Terminat descarcare torrent
+Noi torrenti disponibili
+%d noi feed-uri RSS
+
+RSS
+Se incarca feed-ul RSS
+Conectat, dar feed-ul RSS este gol
+
+Eroare la comunicarea cu serverul
+Eroare la construirea cererii
+Eroare in parsarea răspunsului serverului (Te rog verifică setările)
+Autentificarea a fost respinsa (Te rog verifică setările)
+Nu pot citi fișierul .torrent
+Eroare la parsarea subscrierii RSS
+Acest URL nu este bine format
+Datele introduse nu sunt un IP sau hostname valabil
+Numarul portului este intodeauna numeric
+Calea folderului se termina cu / sau \
+URL-ul nu este un feed RSS valid
+
+Adauga server Xirvik
+Setari server Xirvik
+Tip server
+Nume server
+
+
+
+Combină aranjarea
+Număr de seederi/leecheri
+
+
+
+Nu exită reîmprospatare automată
+2 secunde
+5 secunde
+15 secunde
+1 minut
+5 minute
+15 minute
+1 ora
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Seach Box
+Black
+Transparent
+
+
diff --git a/android/res/values-ru/strings.xml b/android/res/values-ru/strings.xml
new file mode 100644
index 00000000..94fc102f
--- /dev/null
+++ b/android/res/values-ru/strings.xml
@@ -0,0 +1,380 @@
+
+
+Клиент для удаленного управления Transmission, uTorrent, BitTorrent, rTorrent и Deluge
+
+Перейдите в меню настроек, для ввода параметров вашего сервера
+Перейдите в меню настроек, для указания данных о сервере.\n\nДля помощи при инсталляции: www.transdroid.org/download
+Открыть настройки
+Попытка подключения к серверу
+Соединение установлено, но на сервере отсутствуют торренты.
+Соединение установлено, но на сервере нет скачиваемых торрентов.
+Соединение установлено, но на сервере нет сидируемых торрентов.
+Соединение установлено, но на сервере нет неактивных торрентов.
+Ваше приложение не поддерживает загрузку файлов типа .torrent или же данная функция не реализована.
+Ваш торрент клиент не поддерживает ссылки .magnet или это еще не реализовано.
+Сохранить
+Отменить
+Торрент сервер
+Серверы еще не настроены
+
+Показать все
+Без меток
+Новая метка
+Работа с метками не поддерживается Вашим клиентом
+
+Переключить вид
+Показать все торренты
+Показать загружаемые торренты
+Показать сидируемые торренты
+Показать неактивные торренты
+
+Добавить
+Сканирование штрих-кодов
+RSS
+Сменить сервер
+Установить скорость передачи
+Для всех
+Приостановить все
+Продолжить все
+Остановить все
+Запустить все
+Фильтр
+Сортировать по (в обратном порядке)
+Имени
+Статусу
+Дате загрузки
+Дате добавления
+Скорость выгрузки
+Коэффициенту
+Только активные
+Настройки
+О программе
+Сообщить об ошибке
+Удалить
+Удалить вместе с данными
+Кроме удаления данных
+Приостановить
+Продолжить
+Остановить
+Запустить
+Запустить принудительно
+Установить метку...
+Каталог загрузки
+По умолчанию
+Сайт по умолчанию
+Вверх
+Вниз
+Изменить трекеры
+Обратить выделенное
+
+Вставьте URL торрент-файла
+Введенные данные не являются корректным URL
+Выберите локальный .torrent файл
+Не найден поддерживаемый файл-менеджер (OI File Manager). Установить его с Android Market?\n\nВы можете использовать уже установленный файл-менеджер, для того, чтобы передать торрент-файл в Transdroid
+Установить из Market
+Приложение Android Market не установлено
+Сканер штрих-кодов не найден. Установить через Android Market?
+Чтобы отправить сообщение об ошибке вам нужно установить бесплатное приложение Log Collector. Установить через Android Market?
+Приложение Log Collector теперь будет следить за ошибками и отправлять автору transdroid.org@gmail.com. \nУ вас будет возможность просматривать и редактировать сообщения.
+Приложение для удаленного управления (VLC Remote) не найдено. Установить через Android Market?
+Не установлен поддерживаемый FTP клиент AndFTP.\nУстановить через Android Market?
+
+Максимальная скорость закачки
+Максимальная скорость раздачи
+Только цифровые значения, в Кб/с
+Сброс
+Ваш торрент-клиент не поддерживает настройку скорости передачи
+Скорость раздачи обновлена
+Удаление торрента
+Вы действительно хотите удалить этот торрент?
+Добавление не удалось
+% 1 $ S не удалось добавить прямо сейчас. \ NВы хотите повторить или автоматически добавить его в очередь позже?
+% 1 $ S не удалось добавить прямо сейчас. \ NВы хотите повторить?
+Повторить
+Добавить позже
+
+Поиск...
+Искать торренты он-лайн
+Торренты
+Ubuntu
+Результаты от
+Добавить все выбранные
+По вашему запросу ничего не найдено
+Отсутствует поисковый запрос
+Переключиться на другой сайт
+Скачать
+Открыть сайт
+Открыть с помощью...
+Отправить ссылку...
+Сохранить RSS-фид
+Искать заново
+Искать в сохраненных RSS-фидах
+Сохранение не поддерживается этим сайтом
+Torrent Search теперь отдельный модуль. Установить его сейчас из Android Market?
+
+Настройки Transdroid
+Добавить новый сервер
+Добавить поисковый сайт
+Добавить RSS-фид
+Поиск в приложении
+Поиск через Web
+Прочие настройки
+
+Сервер
+Основные настройки
+Имя
+Опциональное имя
+Тип сервера
+IP адрес или имя домена
+Без префикса http:// и номера порта
+Порт
+Обычно
+Использовать авторизацию
+Требуется имя пользователя и пароль
+Имя пользователя
+Пароль
+Операционная система
+Папка SGGI
+Обычно /RPC2
+Папка
+Например: /torrentflux
+Обычно пусто
+Дополнительные настройки
+Папка для загрузки
+Полный путь папки для загрузки на сервере
+Адрес FTP
+Например: ftp://me@server.com/downloads/
+Тайм-аут соединения
+Количество секунд до таймаута попытки подключения
+SSL
+Выбрать для использования https
+Пользовательский SSL-сертификат
+Разрешение подключения только к этому конкретному сертификату
+Принимать все SSL сертификаты
+Выберите, чтобы разрешить соединения с любым сертификатом
+
+Поисковая система
+Выберите сайт по-умолчанию
+Прямой URL для поиска
+%s будет заменено поисковым запросом
+Количество результатов
+Тип сортировки
+RSS фиды
+Настройки фида
+URL фида
+Необходима авторизация
+Открытие в браузере для авторизации
+ezRSS feed builder
+Составить RSS-фид с ТВ программами
+Показать имя
+Качество
+Релиз-группа
+Качество и релиз-группа не являются обязательными\nОсновано на http://www.ezrss.it
+точное совпадение ↴
+Пример фида будет показан после введения запроса
+Загрузка...
+Этот запрос не дал результатов
+
+Параметры интерфейса
+Только активные (> 0 KB/s)
+Показывать торренты со скоростью 0KB/s как неактивные
+Свайпать метки
+Переключать метки вместо серверов при свайпе
+Интервал обновления
+Спрятать обновление
+Не показывать сообщение \'Список торрентов обновлен\'
+Очистить историю поиска
+История поиска успешно очищена
+Подтвердить удаление
+Запросить подтверждение удаления торрента
+Импортировать настройки
+Transdroid попытается импортировать сервер, веб-поиск и RSS настроек из:
+Настройки успешно импортированы
+Выберите файл
+Экспортировать настройки
+Transdroid будет экспортировать сервера (включая пароли), веб-поиск и RSS настройки следующий текстовый файл:
+Настройки успешно экспортированы
+Выберите каталог
+Показать объявления в нижней части экрана
+
+Настройки уведомлений
+Включить уведомления
+Уведомлять при изменении статуса торрента
+Частота уведомления
+Частота проверки моих торрентов
+Уведомление о скачивании
+Уведомлять когда торрент загружен
+Уведомление новых торрентов
+Уведомлять при добавлении новых торрентов
+Включить звук уведомления
+Предупреждающий звуковой сигнал
+Включить вибрацию
+Проверка RSS фидов
+Уведомлять когда доступны новые торренты
+Включить ADV уведомление
+
+Ожидание проверки...
+Проверяем локальные данные...
+Ожидание начала загрузки %s
+Ошибка...
+%1$s из %2$s (%3$s)
+%1$s, закачано %2$s
+~ %1$s
+неизвестно
+рейтинг %1$s
+%1$s из %2$s пиры(ов)
+↑ %1$s
+↓ %1$s
+Приостановка
+Остановка
+Неизвестно
+/c
+
+Обновление...
+Добавление торрента...
+Закачка торрента...
+Удаление торрента...
+Приостановка торрента...
+Приостановка всех торрентов...
+Возобновление торрента...
+Возобновление всех торрентов...
+Остановка торрента...
+Остановка всех торрентов...
+Запуск торрента...
+Запуск всех торрентов...
+Извлечение файлов...
+Настройка свойств файла...
+Настройка скорости передачи...
+Назначение метки...
+Переместить торрент...
+
+Список торрентов обновлен
+Торрент добавлен (обновляем)
+удалён
+удалён, данные тоже удалены
+возоблено (обновляем)
+остановлено
+запущено (обновляем)
+приостановлено
+Торренты приостановлены
+Торренты востановлены (обновляются)
+Торренты остановлены
+Торренты запущены (обновляются)
+Трекеры обновлены
+Торрент перемещён в \ "% 1 $ S \ '
+
+Подробности
+Файлы
+Размер:
+Состояние:
+Скачано:
+Закачано:
+Рейтинг:
+Осталось:
+Доступность:
+Пиры:
+Метка:
+Трекеры:
+Ошибки:
+Отображение в виде списка не поддерживается вашим торрент клиентом либо еще не осуществлено
+Обновлены приоритеты файла
+
+Выкл
+Низк
+Норм
+Высок
+Удаленно проиграть в VLC
+Загрузка при помощи (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Сепвеп
+Частота обновления
+Стиль
+Добавить виджет
+DL @
+up
+UP @
+неактивен
+/c
+~
+неизвестно
+новое
+
+Добавлен новый торрент
+Загрузка торрента закончена
+Доступны новые торренты
+%d новых RSS-фидов
+
+RSS
+Не установлено RSS-фидов\n\nДобавьте новые фиды через меню
+Загрузка RSS-фида
+Поключено, но RSS-фид пуст
+
+Ошибка связи с сервером
+Ошибка при построении запроса
+Ошибка при обработке ответа от сервера (пожалуйста, проверьте ваши настройки)
+Не подключен web-интерфейс
+Ошибка авторизации (пожалуйста, проверьте ваши настройки)
+Невозможно прочитать торрент-файл
+Ошибка при разборе RSS-фида
+URL не правильно оформлен
+Ссылка на web-поиск ошибочна:
+Введенный адрес не является корректным адресом или именем сервера
+Номер порта - всегда числовое значение
+Путь к папке должен заканчиваться / или \
+Тайм-аут не может быть пустым, и положительным числом
+RSS-фид не дает ссылку, чтобы перейти к
+Не правильная ссылка на RSS-фид
+SD-карта не доступна для чтения/записи
+Файл, кажется, не содержат настроек Transdroid
+Файл настроек не найден
+
+Добавить Xirvik сервер
+Настройки Xirvik сервера
+Тип сервера
+Название сервера
+Например dedi000.xirvik.com
+Неверный сервер (Используйте полное имя, например dedi000.xirvik.com)
+
+SeedM8 предлагает безлимитный Гбит seedbox-хостинг. Transdroid обеспечивает легкую установку для SeedM8 серверов.\ n\ nУзнайте больше на www.seedm8.com
+Добавить сервер SeedM8
+Настройки сервера SeedM8
+Имя сервера
+Например alpha.seedm8.com
+Неверный сервер (Используйте полное имя, например alpha.seedm8.com)
+
+
+Комбинированный запрос
+Количество сидеров/личеров
+
+
+
+Не обновлять
+2 секунды
+5 секунд
+15 секунд
+1 минута
+5 минут
+15 минут
+1 час
+
+
+
+1 минута
+10 минут
+30 минут
+1 час
+3 часа
+12 часов
+1 день
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-sk/strings.xml b/android/res/values-sk/strings.xml
new file mode 100644
index 00000000..941b6268
--- /dev/null
+++ b/android/res/values-sk/strings.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/values-sl/strings.xml b/android/res/values-sl/strings.xml
new file mode 100644
index 00000000..aef710cc
--- /dev/null
+++ b/android/res/values-sl/strings.xml
@@ -0,0 +1,97 @@
+
+
+Oddaljeni torrent odjemalec za Transmission, uTorrent, BitTorrent, rTorrent, Vuze in Deluge.
+
+V meniju odprite nastavitve, če želite dodati nov strežnik.
+V meniju odprite nastavitve, če želite dodati nov strežnik.\n\nZa pomoč pri inštalaciji:www.transdroid.org/download
+Odpri nastavitve
+Poskušam se povezati s strežnikom..
+Povezava je vzpostavljena vendar na strežniku ni torrentov.
+Povezava je vzpostavljena vedar na strežniku ni torrentov v fazi shranjevanja.
+Povezava je vzpostavljena vendar ni torrentov v fazi razsajanja.
+Povezava je vzpostavljena vendar ni aktivnih torrentov.
+Vaša torrent aplikacija ne podpira pošiljanja .torrent datotek ali pa podpora še ni implementirana.
+Vaša torrent aplikacija ne podpira pošiljanja .magnet datotek ali pa podpora še ni implementirana.
+Shrani
+Zavrži
+Torrent strežnik
+Nastavljen ni še noben strežnik
+
+Prikaži vse
+Neoznažen
+Nova oznaka
+Nastavljanje oznak ni podprto na vašem odjemalcu
+
+Vsi torenti
+Neaktivni torenti
+
+Dodaj
+RSS
+Zamenjaj strežnik
+Nastavi prenosne zmogljivosti
+Naredi za vse
+Nadaljuj vse
+Ustavi vse
+Zaženi vse
+Filtriraj seznam
+Uredi po
+Ime
+Status
+Datum zaključka
+Datum
+Hitrost oddajanja
+Razmerje
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-sv/strings.xml b/android/res/values-sv/strings.xml
new file mode 100644
index 00000000..df3e6a9c
--- /dev/null
+++ b/android/res/values-sv/strings.xml
@@ -0,0 +1,393 @@
+
+
+Torrentklient-hanterare med integrerad sökning, RSS-support, och övervakningswidget
+
+Öppna inställningsmenyn för att ange uppgifter till serverns daemon.
+Ny på Transdroid? Du kan få installationshjälp på www.transdroid.org/download\n\nFör att starta torrenta, ange dina serverinställningar:
+Öppna inställningar
+Försöker att ansluta till servern...
+Ansluten, men inga torrents på servern.
+Ansluten, men inga torrents under nedladdning finns på servern.
+Ansluten, men inga seedande torrents på servern.
+Ansluten, men inga inaktiva torrents på servern.
+Ditt torrentprogram stödjer inte .torrent-filuppladdningar eller inte implementerat ännu.
+Din torrentklient stödjer inte .magnet-länkar
+Spara
+Ångra
+Torrentserver
+Inga servrar har blivit konfigurerade
+
+Alla etiketter
+Etikettlös
+Ny etikett
+Ange etikett stödjs inte av din klient
+
+Byt vy
+Alla torrenter
+Nedladdande torrenter
+Seedande torrenter
+Inaktiva torrenter
+
+Lägg till
+Scanna streckkod
+RSS
+Byt server
+Ange hastighetsgräns
+Gör för alla
+Pausa alla
+Återuppta alla
+Stoppa alla
+Starta alla
+Filtrera lista
+Sortera efter (återfaller till omvänd ordning)
+Namn
+Status
+Datum klar
+Datum tillagd
+Uppladdningshastighet
+Ratio
+Endast överföring (> 0KB/s)
+Inställningar
+Om/ändringslogg
+Felrapport
+Ta bort
+Ta bort och radera data
+Ta bort data också
+Paus
+Återuppta
+Stoppa
+Starta
+Tvinga start
+Ange etikett
+Ange nedladdningsmapp
+Sätt som standard
+Standardsajt satt till
+Flytta upp
+Flytta ner
+Redigera trackers
+Invertera val
+
+Klistra in URLen för torrentfilen
+Det är inte en (giltig) URL
+Välj en lokal .torrent-fil
+Ingen stödd filhanterare, så som OI File Manager, kunde hittas. Vill du installera den från Android Market?\n\nDu kan annars öppna en icke-stödd filhanterare själv och skicka en .torrent-fil till Transdroid.
+Installera från Market
+Android Market programmet är inte installerat
+Barcode Scanner kunde inte hittas. Vill du installera den från Android Market?
+För att skicka en felrapport behöver du Log Collector, en applikation som är gratis och med öppen källkod. Vill du installera den från Android Market?
+Log Collector applikationen kommer nu ta enhetens loggfil och skicka den till transdroid.org@gmail.com.\nDu kommer ha möjlighet att granska och modifiera informationen innan den skickas.
+En fjärrvisare, som ex. VLC Remote kunde inte hittas. Vill du installera VLC Remote från Android Market?
+Du har inte installerat en kompatibel FTP-klient.\nVill du installera AndFTP från Android Market?
+
+Maximal nedladdningshastighet
+Maximal uppladdningshastighet
+Enbart numeriska värden, i KB/s
+Återställ
+Din torrentklient stödjer inte inställningar av överföringsgränser eller så är det inte implementerat ännu.
+Överföringsgränser uppdaterade
+Tar bort torrent
+Är du säker på att du vill radera denna torrenten?
+Tilläggning misslyckades
+%1$s kunde inte läggas till just nu.\nVill du försöka igen eller köa den för att automatiskt lägga till den senare?
+%1$s kunde inte läggas till just nu.\nVill du försöka igen?
+Försök igen
+Lägg till senare
+
+Söker...
+Sök efter torrents online
+Torrenter
+Ubuntu
+Resultat från
+Lägg till alla markerade
+Inga resultat hittades för din sökning
+Ingen sökfråga angavs
+Byt sajt
+Ladda ner nu
+Öppna webbplats
+Öppna med...
+Dela länk...
+Spara som RSS-flöde
+Använd som ny sökning
+Sökning sparad som RSS-flöde
+Sparning stödjs inte för den här sajten
+Torrent Search är nu en separat modul, vilket innebär engångsinstallation från Android Market. Installera nu?
+
+Transdroid-inställningar
+Lägg till ny server
+Lägg till webbsöksajt
+Lägg till RSS-flöde
+I-program sökning
+Webbaserad sökning
+Andra inställningar
+
+Serverprocess
+Enkla inställningar
+Namn
+Valfritt personligt namn
+Servertyp
+IP eller domännamn
+Utan http:// eller portnummer
+Port
+Vanligtvis
+Använd autentisering
+Du behöver användarnamn och lösenord
+Användarnamn
+Lösenord
+Serveroperativ
+SCGI-mapp
+Vanligtvis /RPC2
+Mapp
+Till exempel /torrentflux
+Vanligtvis tom
+Avancerade inställningar (tillval)
+Nedladdningsmapp
+Den absoluta sökvägen till nedladdningsmappen på din server
+Basurl (S)FTP
+Till exempel ftp://me@server.com/downloads/
+Anslutningstimeout
+Antal sekunder innan ett anslutningsförsök får timeout
+SSL
+Välj för att använda HTTPS
+Eget SSL-fingeravtryck
+Tillåt endast anslutningar till detta specifika certifikat
+Godta alla SSL-certifikat
+Välj om certifikatet är självsignerat
+
+Sökmotor
+Ange standardsajt
+Direkt sökURL
+%s kommer att ersättas av sökfrågan
+Antal resultat
+Sorteringsordning
+RSS-flöden
+Flödesinställningar
+Flödes-URL
+Kräver autentisering
+Öppnar länkar i webbläsaren för att autentisera
+ezRSS flödeskomponerare
+Gör ett RSS-flöde för TV-serier
+Serienamn
+Kvalitet
+Utgivningsgrupp
+Kvalitet och utgivningsgrupp är valfritt.\nStöds av http://www.ezrss.it
+exakt matchning ↴
+Ett exempel visas efter du matat in din fråga
+Laddar...
+Denna förfrågan ger en tom avsnittslista
+
+Gränsnittsinställningar
+Endast överföring (> 0KB/s)
+Visa torrenter som laddar ner i 0KBs/s som inaktiva
+Svep etiketter
+Svep mellan etiketter istället för servrar
+Uppdateringsintervall
+Göm uppdatering
+Visa inte \'Torrentlista uppdaterad\' meddelande
+Töm sökhistorik
+Radering av sökhistoriken lyckades
+Bekräfta borttagning
+Bekräfta borttagning av torrent
+Importera inställningar
+Transdroid försöker importera server, webbsökning och RSS-inställningar från:
+Import av inställningar lyckades
+Välj fil
+Exportera inställningar
+Transdroid exporterar server (inklusive lösenord), webbsökningar och RSS-inställningar till följande textfil:
+Export av inställningar lyckades
+Välj mapp
+Tillåt annonser
+Visa annonser längst ner på skärmen
+
+Alarmtjänstsinställningar
+Aktivera alarmtjänst
+Varna mig vid statusändring på torrent
+Alarmintervall
+Hur ofta ska mina torrenter kontrolleras
+Nedladdningsalarm
+Meddela när torrent är färdig
+Nytt torrentalarm
+Meddela när ny torrent läggs till
+Aktivera alarmljud
+Spela notifieringsljud vid alarm
+Alarmljud
+Notifieringsljud att spela vid alarm
+Aktivera vibration
+Vibrera vid alarm
+Kontrollera RSS-flöde
+Spela alarm när nya torrenter är tillgängliga
+Aktivera ADW-notifieringar
+Visa torrenträknare i ADW-uppstartare
+Räkna endast nedladdningar
+ADW-räknare inkluderar endast nedladdande torrenter
+
+Väntar på kontroll...
+Verifierar lokal data...
+Väntar på att ladda ner %s
+Fel...
+%1$s av %2$s (%3$s)
+%1$s, uppladdat %2$s
+~ %1$s
+okänd ETA
+ratio %1$s
+%1$s av %2$s noder
+↑ %1$s
+↓ %1$s
+Pausad
+Stoppad
+Okänd
+/s
+
+Uppdaterar...
+Lägger till torrent...
+Laddar upp torrent...
+Tar bort torrent...
+Pausar torrent...
+Pausar alla torrenter...
+Återupptar torrent...
+Återupptar alla torrenter...
+Stoppar torrent...
+Stoppar alla torrenter...
+Startar torrent...
+Startar alla torrenter...
+Hämtar filer...
+Sätter filegenskaper...
+Sätter överföringsgränser...
+Tilldelar etikett...
+Flyttar torrent...
+Byter läge...
+
+Torrentlista uppdaterad
+Torrent lades till (uppdaterar)
+borttagen
+borttagen och data raderad
+återupptar (uppdaterar)
+stoppad
+startad (uppdaterar)
+pausad
+Torrenterna är pausade
+Torrenterna återupptar (uppdaterar)
+Torrenterna är stoppade
+Torrenterna startade (uppdaterar)
+Trackers uppdaterade
+Torrent flyttad till \'%1$s\'
+
+Detaljer
+Filer
+Storlek:
+Läge:
+Nedladdat:
+Uppladdat:
+Rate:
+Eta:
+Tillgängligt:
+Noder:
+Etikett:
+Trackers:
+%1$s (expandera)
+(kollapsa)
+Fel:
+Listning av filer stödjs inte av din torrentklient eller så är det inte implementerat ännu
+Filprioritet uppdaterad
+
+Av
+Låg
+Normal
+Hög
+Fjärruppspelning i VLC
+Ladda ned med (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Uppdateringsintervall
+Stil
+Lägg till widget
+NL @
+upp
+UL @
+inaktiv
+/s
+eta
+okänd eta
+ny
+
+Ny torrent tillagd
+Torrentnedladdning klar
+Nya torrenter tillgängliga
+%d nya RSS-flödestorrenter
+
+RSS
+Inga RSS-flöden installerade\n\nAnvänd menyn för att lägga till nya flöden
+Laddar RSS-flöde
+Ansluten, men RSS-flödet är tomt
+
+Fel uppstod under kommunikationen med servern
+Fel i begäran
+Fel i att läsa serversvar (kontrollera dina inställningar)
+Webbgränssnittet inte anslutet till en startad process
+Åtkomst nekad (kontrollera inställningar)
+Kan inte läsa .torrent filen
+Fel under läsning av RSS-flöde
+URLen var inte giltigt utformad
+Din webbsökningsURL är ogiltig:
+Inmatningen är inte en giltig IP-adress eller värdnamn
+Portnumret är alltid numeriskt
+Sökväg slutar med / eller \
+Timeout kan inte vara tomt och är ett positivt nummer
+RSS-flödet innehåller inte en URL eller länk som pekar till .torrent-filen
+RSS-flödet innehåller inte en länk att bläddra till
+URL:en är inte ett giltigt RSS-flöde
+SD-kortet inte tillgängligt för läsning/skrivning
+Filen verkar inte innehålla några Transdroid-inställningar
+Ingen inställningsfil hittades
+
+Xirvik erbjuder delade, halvdelade eller dedikerade seedboxar. Transdroid tillhandahåller enkel uppsättning för alla Xirvik-servrar.\n\nLäs mer på www.xirvik.com
+Lägg till Xirvik-server
+Xirvik-serverinställningar
+Servertyp
+Delad, halvdelad eller dedikerad
+Servernamn
+T.ex dedi000.xirvik.com
+Ogiltig server (använd fullständigt värdnamn, som dedi000.xirvik.com)
+
+SeedM8 erbjuder GBit seedboxhosting. Transdroid tillhandahåller enkel uppsättning för SeedM8-servrar\n\nLäs mer på www.seedm8.com
+Lägg till SeedM8-server
+SeedM8-serverinställningar
+Servernamn
+T.ex: alpha.seedm8.com
+Ogiltig server (använd fullständigt värdnamn, som alpha.seedm8.com)
+
+
+Kombinerad ordning
+antal seeders/leechers
+
+
+
+Ingen automatisk uppdatering
+2 sekunder
+5 sekunder
+15 sekunder
+1 minut
+5 minuter
+15 minuter
+1 timme
+
+
+
+1 minut
+10 minuter
+30 minuter
+1 timme
+3 timmar
+12 timmar
+1 dag
+
+
+
+Android 1.5
+Android 1.6
+Snabbsökruta
+Svart
+Transparent
+
+
diff --git a/android/res/values-tr/strings.xml b/android/res/values-tr/strings.xml
new file mode 100644
index 00000000..b9058bfc
--- /dev/null
+++ b/android/res/values-tr/strings.xml
@@ -0,0 +1,93 @@
+
+
+
+Kaydet
+
+
+
+Ekle
+Sunucu Değiştir
+Hepsini Durdur
+Hepsini Başlat
+Tümünü durdur
+Tümünü başlat
+İsim
+Durum
+Ayarlar
+Hakkında/Değişiklikler
+Çıkar
+Duraklat
+Durdur
+Başlat
+Yukarı taşı
+Aşağı Taşı
+
+
+Tekrar
+Sonra ekle
+
+Aranıyor...
+Şimdi indir
+Website aç
+
+
+Temel ayarlar
+Server tipi
+Kullanıcı Adı
+Şifre
+Klasör
+Örneğin ftp://me@server.com/downloads/
+
+Arama motoru
+
+
+
+
+
+
+
+Kapalı
+Düşük
+Normal
+Yüksek
+
+
+
+
+
+
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values-xlarge-v11/styles.xml b/android/res/values-xlarge-v11/styles.xml
new file mode 100644
index 00000000..cd560528
--- /dev/null
+++ b/android/res/values-xlarge-v11/styles.xml
@@ -0,0 +1,8 @@
+
+
+ 20dip
+ 28dip
+
+
\ No newline at end of file
diff --git a/android/res/values-zh-rTW/strings.xml b/android/res/values-zh-rTW/strings.xml
new file mode 100644
index 00000000..3b25bb05
--- /dev/null
+++ b/android/res/values-zh-rTW/strings.xml
@@ -0,0 +1,373 @@
+
+
+內置搜尋、RSS支援和監控小工具的用戶端
+
+開啟設定選單進入伺服器細節訊息。
+開啟設定選單輸入您的伺服器細節訊息。\n\n安裝說明:www.transdroid.org/download
+開啟設定
+嘗試連線到伺服器...
+已連線,但是伺服器上沒有種子。
+已連線,但是伺服器上沒有正在下載的種子。
+已連線,但是伺服器上沒有正在做種的種子。
+已連線,但是伺服器上沒有非活動中的種子。
+您的用戶端不支援上傳.torrent檔案或並未實作此功能。
+您的用戶端不支援magnet連結或並未實作此功能。
+儲存
+忽略
+Torrent伺服器
+未有已設定的伺服器
+
+顯示所有
+未標籤
+新標籤
+您的用戶端不支援設定標籤
+
+顯示所有種子
+顯示下載中種子
+顯示做種中種子
+顯示未活動種子
+
+新增
+掃瞄條碼
+RSS
+切換伺服器
+設定傳輸速度
+設定全部
+暫停全部
+還原全部
+停止全部
+開始全部
+過濾清單
+排序(反向排序)
+名字
+狀態
+完成日期
+新增日期
+上傳速度
+比率
+限制傳輸(> 0KB/s)
+設定
+關於/更新日誌
+錯誤報告
+移除
+移除並刪除資料
+同時也刪除資料
+暫停
+繼續
+停止
+開始
+強制開始
+設定標籤
+設定存放位置
+設為預設
+設定預設站台為
+上移
+下移
+編輯Tackers
+
+貼上URL或種子檔案
+URL位址格式不對
+選取一個本機.torrent種子檔案
+沒有發現支援的檔案管理器,比如OI File Manager。您想從Android Market安裝嗎?\n\n另外您也可以開啟一個不支援的檔案管理器並傳送一個.torrent種子檔案到Transdroid。
+從Market安裝
+未安裝Android Market
+尚未安裝條碼掃描器,您想從Android Market安裝嗎?
+您需要安裝Log Collector程式來傳送錯誤報告,您想從Android Market安裝嗎?
+Log Collector將會收集您的設備日誌並傳送到transdroid.org@gmail.com,\n你可以預覽和修改將要傳送的資料。
+尚未安裝遠端檔案瀏覽器,如VLC Remote;您想從Android Market安裝VLC Remote嗎?
+尚未安裝相容的FTP用戶端,\n您想從Android Market安裝AndFTP嗎?
+
+最大下載速率
+最大上傳速率
+只允許數字,以KB/s為單位
+重設
+您的用戶端不支援設定傳輸速率,或並未實作此功能。
+傳輸速率已更新
+移除種子
+確定要移除這個種子嗎?
+重試
+稍候新增
+
+搜尋中...
+搜尋線上種子
+總子
+Ubuntu
+搜尋結果
+新增所有已選檔案
+沒有搜尋結果
+沒有輸入查詢條件
+切換站台
+馬上下載
+開啟網站
+開啟方式...
+分享連結...
+另存為RSS摘要
+將搜尋另存為RSS摘要
+站台不支援儲存
+搜尋種子功能分開在另一模組,您想從Android Market安裝嗎?
+
+Transdroid偏好設定
+新增新伺服器
+新增網頁搜尋站台
+新增RSS摘要
+程式內搜尋
+網頁搜尋
+其他設定
+
+伺服器常駐執行
+基礎設定
+名字
+可選使用者名
+伺服器類型
+IP位址或者域名
+不帶http://或者通訊埠名
+通訊埠
+通常是
+使用認證
+您需要一個使用者名稱和密碼
+使用者名稱
+密碼
+伺服器作業系統
+SCGI目錄
+通常是/RPC2
+資料夾
+例如是 /torrentflux
+通常是空白
+進階選項(可選)
+下載目錄
+您伺服器上的下載目錄,絕對位址
+基本 (S)FTP url
+例如是 ftp://me@server.com/downloads/
+SSL
+選取此項使用https
+自訂SSL thumbprint
+保持連線到指定的憑證
+接受所有的SSL憑證
+選取自認證憑證
+
+搜尋引擎
+設定預設站台
+直接搜尋位址
+%s將會被替換為搜尋語法
+結果數量
+結果排序
+RSS摘要
+摘要設定
+RSS摘要位址
+需要認證
+開啟瀏覽器進行認證
+ezRSS摘要產生器
+Build a TV show RSS feed
+顯示名字
+品質
+發佈組
+品質和發佈組是可選的\nPowered by http://www.ezrss.it
+精確比對↴
+輸入查詢後會顯示RSS摘要範例
+載入中...
+這個查詢返回一個空清單
+
+介面設定
+限制傳輸(> 0KB/s)
+將0KB/s的種子顯示為未活動
+Swipe labels
+Swipe between labels instead of servers
+更新間隔
+隱藏更新
+不顯示\'種子清單已更新\'訊息
+清除搜尋紀錄
+成功清除搜尋紀錄
+確認移除
+移除種子時要求確認
+匯入設定檔
+Transdroid將會從下列文字檔匯入伺服器(包括密碼)、搜尋以及RSS設定:
+匯入設定成功
+選擇檔案
+匯出設定檔
+Transdroid將會匯出伺服器(包括密碼)、搜尋以及RSS設定到下列文字檔:
+匯出設定成功
+選擇目錄
+啟用廣告
+顯示螢幕底部的廣告
+
+提醒服務設定
+啟用提醒服務
+種子狀態改變時提醒我
+提醒間隔
+檢查種子狀態的間隔
+下載完成提醒
+種子完檔時通知
+新增種子提醒
+新增種子時通知
+啟用提醒音效
+提醒時播放通知音效
+提醒音效
+欲播放的通知音效
+啟用震動
+提醒時震動
+檢查RSS摘要
+有新種子的時候提醒我
+啟用ADW通知
+在ADW Launcher中顯示種子數
+只計算下載中數量
+ADW只包括下載中種子的數量
+
+等待檢查...
+驗證本機資料
+等待下載%s
+%1$s於%2$s (%3$s)
+%1$s,已上傳%2$s
+~ %1$s
+未知預計完成時間
+比率%1$s
+%1$s於%2$s節點
+↑ %1$s
+↓ %1$s
+已暫停
+已停止
+未知
+/秒
+
+更新...
+新增種子...
+上傳種子...
+移除種子...
+暫停種子...
+暫停所有種子...
+繼續種子...
+繼續所有種子...
+停止種子...
+停止所有種子...
+開始種子...
+開始種子...
+檢索檔案...
+設定檔案內容...
+設定傳輸速率...
+指定標籤...
+移動種子...
+
+種子清單已更新
+種子已新增(更新中)
+已移除
+種子已移除且資料已刪除
+已繼續(更新中)
+已停止
+已開始(更新中)
+已暫停
+種子已暫停
+種子已繼續(更新中)
+種子已停止
+種子已開始(更新中)
+Trackers已最新
+種子已移到\'%1$s\'
+
+詳情
+檔案
+大小:
+狀態:
+已下載:
+已上傳:
+速度:
+預計完成時間:
+可用度:
+節點:
+標籤:
+Tracker:
+您的用戶端不支援種子清單或並未實作此功能。
+檔案優先順序已更新
+
+關
+低
+中
+高
+在VLC中遠端播放
+使用(S)FTP下載
+
+Transdroid 4x1
+Transdroid 2x1
+伺服器
+更新間隔
+風格
+新增小工具
+DL @
+up
+UP @
+未啟用
+/秒
+預計完成時間
+未知預計完成時間
+新的
+
+新增的種子
+結束下載的種子
+可下載的新種子
+%d 個新的RSS摘要種子
+
+RSS
+沒有RSS摘要\n\n請使用選單新增RSS摘要
+正在載入RSS摘要
+已連線,但RSS摘要無內容
+
+與伺服器通信中發生錯誤
+建立要求時發生錯誤
+伺服器回應剖析發生錯誤(請檢查設定)
+網頁介面沒有連線到正在執行的常駐服務
+拒絕登入(請檢查設定)
+種子讀取錯誤
+RSS摘要剖析錯誤
+URL格式不正確
+網頁搜尋位址錯誤:
+IP位址或主機名稱輸入錯誤
+通訊埠號只能是數字
+目錄路徑應該以/或者\結尾
+RSS項目沒有提供種子的連結
+RSS摘要沒有提供可以瀏覽的連結
+URL不是正確的RSS位址
+記憶卡無法存取
+檔案未包含Transdroid的設定
+未能找到設定檔
+
+Xirvik提供共用的,半獨立或者完全獨立的Seedboxes,Transdroid為所有的Xirvik伺服器提供簡單設定。\n\n訪問www.xirvik.com獲得更多訊息
+新增Xirvik伺服器
+Xirvik伺服器設定
+伺服器類型
+共用,半獨立或完全獨立
+伺服器名
+像是 dedi000.xirvik.com
+錯誤的伺服器(請使用完整主機名,像是dedi000.xirvik.com)
+
+
+
+合併排序
+供檔者/吸血者數量
+
+
+
+不自動更新
+2秒
+5秒
+15秒
+1分鐘
+5分鐘
+15分鐘
+1小時
+
+
+
+1分鐘
+10分鐘
+30分鐘
+1小時
+3小時
+12小時
+1天
+
+
+
+Android 1.5
+Android 1.6
+快速搜尋欄
+黑色
+Transparent
+
+
diff --git a/android/res/values-zh/strings.xml b/android/res/values-zh/strings.xml
new file mode 100644
index 00000000..761824db
--- /dev/null
+++ b/android/res/values-zh/strings.xml
@@ -0,0 +1,392 @@
+
+
+内置搜索、RSS支持和监控小控件的BT客户端
+
+打开设置菜单进入服务器详细信息。
+打开设置菜单输入您的服务器详细信息.\n\n安装帮助:www.transdroid.org/download
+打开设置iory
+尝试连接到服务器...
+已连接,但是服务器上没有种子.
+已连接,但是服务器上没有正在下载的种子.
+已连接,但是服务器上没有正在上传的种子.
+已连接,但是服务器上没有活动的种子.
+您的BT程序不支持.torrent文件格式上传或者还未部署这个功能.
+你的BT程序不支持磁性链接或者还没被实行
+保存
+忽略
+Torrent服务器
+当前没有配置服务器
+
+显示所有
+未标签
+新建标签
+您的客户端不支持设定标签.
+
+切换视图
+显示所有种子
+显示下载中的种子
+显示做种中的种子
+显示未激活的种子
+
+添加
+扫描条形码
+RSS
+切换服务器
+设定传输速度
+设定全部
+暂停全部
+恢复全部
+停止全部
+开始全部
+过滤列表
+排序(按反序排列)
+名字
+状态
+完成日期
+添加日期
+上传速度
+比率
+限制传输(> 0KB/s)
+设置
+关于/更新日志
+错误报告
+删除
+移除并删除数据
+删除已下载数据
+暂停
+继续
+停止
+开始
+强制开始
+设定标签...
+设定下载位置
+设为默认
+设定默认站点为
+上移
+下移
+编辑 Trackers
+反向选择
+
+粘贴种子文件地址
+URL地址格式不对
+选择一个本地.torrent种子文件
+没有发现支持的文件管理器,比如OI文件管理器.您想从Android市场安装它吗?\n\n或者,你可以打开一个不支持的文件管理器并发送一个.torrent格式的种子文件到Transdroid.
+从市场安装
+市场软件没有安装
+您没有安装Barcode Scanner.您想从市场安装它吗?
+您需要安装Log Collector 程序来发送错误报告.您想从市场安装它吗?
+Log Collector 将会收集您的设备日志并发送到transdroid.org@gmail.com.\n你可以预览和修改将要发送的数据.
+没有发现如VLC一样的远程文件浏览器.您想从市场安装VLC Remote吗?
+您没有安装可兼容的FTP客户端.\n您想从市场安装AndFTP吗?
+
+最大下载速率
+最大上传速率
+只允许数字,已KB/s为单位
+重置
+您的BT客户端不支持设定传输速率,或者这个功能还未部署.
+传输速率已更新
+移除种子
+确定要移除这个种子吗?
+添加失败
+%1$s 现在无法加入.\ n要重试或自动添加到队列中 呢?
+%1$s 现在无法加入.\ n要重试吗?
+重试
+稍后添加
+
+搜索中...
+搜索在线种子文件
+种子
+Ubuntu
+搜索结果
+添加所有已选文件
+您的搜索没有搜索到结果
+没有输入查询条件
+切换站点
+马上下载
+打开网站
+打开方式
+共享链接
+保存为RSS feed
+使用新的搜索
+搜索保持为RSS feed
+保存不被本页面支持的
+Torrent搜索到一个新的模块,现在安装?
+
+Transdroid选项
+添加新服务器
+添加网页搜索站点
+添加RSS源
+程序内搜索
+网页搜索
+其他设置项
+
+服务器守护进程
+基础设置
+名字
+可选用户名
+服务器类型
+IP地址或者域名
+不带http://或者端口名
+端口
+通常是
+使用认证
+你需要一个用户名和密码
+用户名
+密码
+服务器操作系统
+SCGI目录
+通常是/RPC2
+目录
+比如 /torrentflux
+通常是空白的
+高级选项 (可选)
+下载目录
+您服务器的下载目录,绝对地址
+基本 (S)FTP url
+比如 ftp://me@server.com/downloads/
+连接超时
+连接尝试次数超出设置
+SSL
+选择此项使用https
+自定义SSL指纹
+只固定特定证书的链接
+接收全部SSL证书
+选择自认证证书
+
+搜索引擎
+设置默认站点
+直接搜索地址
+%s将会被替换为搜索语句
+记过数量
+结果排序顺序
+RSS源
+Feed设置
+RSS源地址
+需要验证
+在浏览器中进行验证
+ezRSS 源创建器
+创建一个电视剧RSS源
+显示名字
+质量
+发布组
+质量和发布组是可选的\n由http://www.ezrss.it提供支持
+释放匹配↴
+在您输入您的查询后会显示一个RSS源样例.
+加载中...
+这个查询返回一个空列表.
+
+界面设置
+限制传输(> 0KB/s)
+将0KB/s的种子显示为活动.
+刷新标签
+刷新标签代替服务器
+刷新间隔
+隐藏刷新
+不显示\'种子列表已刷新\'信息
+清除搜索历史
+成功清除搜索历史
+确认移除
+移除种子文件时要求确认
+导入设定
+Transdroid将试着导入服务器,网页搜索和RSS设定从:
+设定导入成功完成
+载入文件
+输出设定
+Transdroid将会把服务器(包含密码),WEB搜索和RSS设定导出到下列文本文件
+设定导出成功完成
+载入目录
+允许显示广告
+在屏幕的底部显示广告
+
+提醒服务设置
+启用提醒服务
+种子状态改变时提醒我
+检查间隔
+检查种子状态的频率
+下载完成提醒
+种子下载完成时提醒我
+新种子提醒
+添加新种子时提醒我
+允许报警声
+播放报警通知声
+报警声
+用报警声进行通知
+允许可变
+报警声可变
+检查RSS订阅
+有新种子可用时提醒我
+启用ADW通知
+在ADW启动器中显示种子统计
+只统计下载
+在ADW启动器中只显示下载的种子统计
+
+等待检查
+验证本地数据
+等待下载
+错误...
+%1$s于%2$s (%3$s)
+%1$s,已上传%2$s
+~ %1$s
+未知预计完成时间
+比率%1$s
+%1$s于%2$s节点
+↑ %1$s
+↓ %1$s
+已暂停
+已停止
+未知
+/秒
+
+刷新...
+添加种子...
+上传种子...
+移除种子...
+暂停种子...
+暂停所有种子...
+恢复种子...
+恢复所有种子...
+停止种子...
+停止所有种子...
+开始种子...
+开始所有种子...
+检索文件...
+设置文件属性
+设置传输比率
+指定标签
+移动种子...
+切换模式
+
+种子列表已刷新
+种子已添加(刷新中)
+已移除
+种子已移除且数据已删除
+已恢复(刷新中)
+已停止
+已开始(刷新中)
+已暂停
+种子已暂停
+种子已恢复(刷新中)
+种子已停止
+种子已开始(刷新中)
+种子已更新
+种子被移动到 \'%1$s\'
+
+详情
+文件
+大小:
+状态:
+已下载:
+已上传:
+速度:
+预计完成时间:
+可用度:
+节点:
+标签:
+Trackers:
+%1$s (展开)
+(折叠)
+错误...
+您的客户端不支持列表文件,或者该功能未部署.
+文件优先级已更新
+
+关
+低
+中等
+高
+在VLC中远程播放
+使用(S)FTP下载
+
+Transdroid 4x1
+Transdroid 2x1
+服务器
+刷新间隔
+风格
+添加该窗口小部件
+DL @
+up
+UP @
+未激活
+/秒
+预计完成时间
+未知预计完成时间
+新的
+
+新添加的种子
+结束下载的种子
+可用的新种子
+%d 新的RSS feed种子
+
+RSS
+没有RSS源\n\n请使用菜单添加RSS源
+正在载入RSS源
+已连接,但是RSS源中没有内容
+
+和服务器通信时发生错误
+建立请求时发生错误
+处理服务器返回是时发生错误(请检查设置)
+网页界面没有连接到正在运行的守护进程
+拒绝登录(请检查设置)
+种子文件读取错误
+RSS源处理错误
+URL格式不正确
+网页搜索地址错误:
+IP地址或域名错误
+端口号应该是数字
+目录路径应该以/或者结尾
+超时项不能为空,必须是一个正数
+RSS条目没有提供指向种子文件URL或者连接标签
+RSS源没有提供可以浏览的连接
+URL不是正确的RSS地址
+无法读写SD卡
+文件不包含Transdroid设定
+无法找到设定文件
+
+Xirvik提供共享的,半独立或者完全独立的种子盒子.Transdroid为所有的Xirvik服务器提供简单设置.\n\n访问www.xirvik.com获得更多消息
+添加Xirvik服务器
+Xirvik服务器设置
+服务器类型
+共享,半独立或完全独立
+服务器名
+比如 dedi000.xirvik.com
+错误的服务器(请使用完整主机名,比如dedi000.xirvik.com)
+
+添加SeedM8服务器
+SeedM8服务器设置
+服务器名
+比如 alpha.seedm8.com
+错误的服务器(请使用完整主机名,比如alpha.seedm8.com)
+
+
+联合排序
+供种者/吸血者数量
+
+
+
+不自动刷新
+2 秒
+5 秒
+15 秒
+1 分钟
+5 分钟
+15 分钟
+1 小时
+
+
+
+1 分钟
+10 分钟
+30 分钟
+1 小时
+3 小时
+12 小时
+1 天
+
+
+
+Android 1.5
+Android 1.6
+快速搜索框
+黑色
+Transparent
+
+
diff --git a/android/res/values/arrays.xml b/android/res/values/arrays.xml
new file mode 100644
index 00000000..81daccb5
--- /dev/null
+++ b/android/res/values/arrays.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+ Bitflu 1.2+
+ BitTorrent 6+
+ Buffalo NAS -1.31
+ Deluge 1.2+
+ DLink Router BT
+ Ktorrent
+ qBittorrent
+ rTorrent
+ Torrentflux-b4rt
+ Transmission
+ µTorrent
+ Vuze
+
+
+ daemon_bitflu
+ daemon_bittorrent
+ daemon_buffalonas
+ daemon_deluge
+ daemon_dlinkrouterbt
+ daemon_ktorrent
+ daemon_qbittorrent
+ daemon_rtorrent
+ daemon_tfb4rt
+ daemon_transmission
+ daemon_utorrent
+ daemon_vuze
+
+
+
+ Windows
+ Mac
+ Linux
+
+
+ type_windows
+ type_mac
+ type_linux
+
+
+
+ Shared
+ Semi-dedicated
+ Dedicated
+
+
+ type_shared
+ type_semi
+ type_dedicated
+
+
+
+ 10
+ 25
+ 50
+
+
+ 10
+ 25
+ 50
+
+
+
+
+ sort_combined
+ sort_seeders
+
+
+
+
+ -1
+ 2
+ 5
+ 15
+ 60
+ 300
+ 900
+ 3600
+
+
+
+
+ 60
+ 600
+ 1800
+ 3600
+ 10800
+ 43200
+ 86400
+
+
+
+
+ style_15
+ style_16
+ style_qsb
+ style_black
+ style_transparent
+
+
+
diff --git a/android/res/values/attrs.xml b/android/res/values/attrs.xml
new file mode 100644
index 00000000..c8139ba8
--- /dev/null
+++ b/android/res/values/attrs.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/values/changelog.xml b/android/res/values/changelog.xml
new file mode 100644
index 00000000..2ab233c5
--- /dev/null
+++ b/android/res/values/changelog.xml
@@ -0,0 +1,32 @@
+
+
+
+Transdroid 1.1.0\n
+- Unified phone/tablet interface\n
+- Critical Transmission 2.40+ bugfix\n
+\n
+Transdroid 1.0.4\n
+- (Tracker) error reporting\n
+- 4x1 widget fixed\n
+- Customizable timeout per server\n
+\n
+Transdroid 1.0.3\n
+- Simplified multi-select\n
+- Transparent 4x1 widget\n
+- Removed all ads (and the READ_PHONE_STATE permission)\n
+\n
+Transdroid 1.0.2\n
+- ezRSS in search\n
+- Turtle mode for Transmission\n
+- Bugfix for Torrentflux in web root\n
+- Bugfix for Transmission 2.30+\n
+\n
+Transdroid 1.0.0\n
+- Show trackers in details\n
+- Improved torrent view selection\n
+- Buffalo NAS (pre-uTorrent) support\n
+- Display advertisements (optional)\n
+\n
+Older changes: http://www.transdroid.org/about/changelog/
+
+
diff --git a/android/res/values/colors.xml b/android/res/values/colors.xml
new file mode 100644
index 00000000..f77a4ab1
--- /dev/null
+++ b/android/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #000
+ #7dbb21
+ #fff
+ #000
+ #aada62
+ #000
+ #fff
+
\ No newline at end of file
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
new file mode 100644
index 00000000..034f64de
--- /dev/null
+++ b/android/res/values/strings.xml
@@ -0,0 +1,396 @@
+
+
+Torrent client manager with integrated search, RSS support and monitoring widget
+
+Open the settings menu to enter your server daemon details.
+New to Transdroid? You can get install help at www.transdroid.org/download\n\nTo start torrenting, please enter your server settings:
+Open settings
+Trying to connect to the server...
+Connected, but no torrents on the server.
+Connected, but no downloading torrents on the server.
+Connected, but no seeding torrents on the server.
+Connected, but no inactive torrents on the server.
+Your torrent client does not support .torrent file uploads or this is not yet implemented.
+Your torrent client does not support .magnet links or this is not yet implemented.
+Save
+Dismiss
+Refresh
+Torrent server
+No servers have been configured yet
+
+All labels
+Unlabeled
+New label
+Setting a label is not supported by your client
+
+Switch view
+All torrents
+Downloading torrents
+Seeding torrents
+Inactive torrents
+
+Add
+Scan barcode
+RSS
+Switch server
+Set transfer rates
+Do for all
+Pause all
+Resume all
+Stop all
+Start all
+Filter list
+Sort by (resort to reverse order)
+Name
+Status
+Date done
+Date added
+Upload speed
+Ratio
+Only transferring (> 0KB/s)
+Settings
+About/Change log
+Error report
+Remove
+Remove and delete data
+Also delete data
+Pause
+Resume
+Stop
+Start
+Force start
+Set label
+Set download location
+Set as default
+Default site set to
+Move up
+Move down
+Edit trackers
+Invert selection
+Turtle mode
+
+Paste the URL of the torrent file
+The provided input is not a (valid) URL
+Select a local .torrent file
+No supported file manager, such as OI File Manager, could be found. Would you like to install it from the Android Market?\n\nAlternatively, you can open an unsupported file manager yourself and send a .torrent file to Transdroid.
+Install from market
+The Android Market application is not installed
+The Barcode Scanner could not be found. Would you like to install it from the Android Market?
+To send an error report, you need the free and open-source Log Collector application. Would you like to install it from the Android Market?
+The Log Collector application will now collect the device log and send it to transdroid.org@gmail.com.\nYou will have an opportunity to review and modify the data being sent.
+A remote file viewer, such as VLC Remote, could not be found. Would you like to install VLC Remote from the Android Market?
+You have not installed a compatible FTP client.\nWould you like to install AndFTP from the Android Market?
+
+Maximum download rate
+Maximum upload rate
+Only numeric values, in KB/s
+Reset
+Your torrent client does not support setting of transfer rates or this is not yet implemented.
+Transfer rates updated
+Removing torrent
+Are you sure you want to remove this torrent?
+Adding failed
+%1$s could not be added right now.\nWould you like to retry or queue it to automatically add it later?
+%1$s could not be added right now.\nWould you like to retry?
+Retry
+Add later
+
+Search
+Searching...
+Search on-line for torrents
+Torrents
+Ubuntu
+Results from
+Add all selected
+No results found for your query
+No search query was provided
+Switch site
+Download now
+Open website
+Open with...
+Share link...
+Save as RSS feed
+Use as new search
+Search saved as RSS feed
+Saving not supported for this site
+Torrent Search is now a separate module, which means a one-time install from the Android Market. Install it now?
+
+Transdroid preferences
+Add new server
+Add web search site
+Add RSS feed
+In-app searching
+Web-based searching
+Other settings
+
+Server daemon
+Basic settings
+Name
+Optional personal name
+Server type
+IP or domain name
+Without http:// or port number
+Port
+Usually is
+Use authentication
+You\'ll need a username and password
+Username
+Password
+Server OS
+SCGI folder
+Usually is /RPC2
+Folder
+For example /torrentflux
+Usually empty
+Advanced settings (optional)
+Downloads directory
+The absolute path to the downloads directory on your server
+Base (S)FTP url
+For example ftp://me@server.com/downloads/
+Connection timeout
+Number of seconds before timing out a connection attempt
+SSL
+Select to use https
+Custom SSL thumbprint
+Permit only connections to this specific certificate
+Accept all SSL certificates
+Select to allow connections from any thumbprint
+
+Search engine
+Set default site
+Direct search URL
+%s will be replaced by the search query
+Number of results
+Result sort order
+RSS feeds
+Feed settings
+Feed URL
+Requires authentication
+Opens links in the browser to authenticate
+ezRSS feed builder
+Build a TV show RSS feed
+Show name
+Quality
+Release group
+Quality and release group are optional\nPowered by http://www.ezrss.it
+exact match ↴
+A feed example will show here after entering your query
+Loading...
+This query gives an empty episode listing
+
+Interface settings
+Only transferring (> 0KB/s)
+Show torrents running at 0KB/s as inactive
+Swipe labels
+Swipe between labels instead of servers
+Refresh interval
+Hide refresh
+Don\'t show \'Torrent list refreshed\' message
+Clear search history
+History cleared successfully
+Confirm removing
+Ask to confirm the removal of a torrent
+Import settings
+Transdroid will try to import server, web search and RSS settings from:
+Settings successfully imported
+Pick file
+Export settings
+Transdroid will export server (including passwords), web search and RSS settings to the following plain text file:
+Settings successfully exported
+Pick directory
+Enable ads
+Show advertisements in bottom of the screen
+
+Alarm service settings
+Enable alarm service
+Alarm me on torrent status changes
+Alarm interval
+How often to check my torrents
+Download alarm
+Notify when a torrent finishes
+New torrent alarm
+Notify when a new torrent was added
+Enable alarm sound
+Play notification sound with alarm
+Alarm sound
+Notification sound to play with alarm
+Enable vibration
+Vibrate on alarm
+Check RSS feeds
+Alarm when new torrents are available
+Enable ADW notifications
+Show torrent counter in ADW Launcher
+Count only downloads
+ADW counter only includes downloading torrents
+
+Waiting to check...
+Verifying local data...
+Waiting to download %s
+Error...
+%1$s of %2$s (%3$s)
+%1$s, uploaded %2$s
+~ %1$s
+unknown eta
+ratio %1$s
+%1$s of %2$s peers
+↑ %1$s
+↓ %1$s
+Paused
+Stopped
+Unknown
+/s
+
+Refreshing...
+Adding torrent...
+Uploading torrent...
+Removing torrent...
+Pausing torrent...
+Pausing all torrents...
+Resuming torrent...
+Resuming all torrents...
+Stopping torrent...
+Stopping all torrents...
+Starting torrent...
+Starting all torrents...
+Retrieving files...
+Setting file properties...
+Setting transfer rates...
+Assigning label...
+Moving torrent...
+Switching mode...
+
+Torrent list refreshed
+Torrent added (refreshing)
+removed
+removed and data deleted
+resumed (refreshing)
+stopped
+started (refreshing)
+paused
+Torrents paused
+Torrents resumed (refreshing)
+Torrents stopped
+Torrents started (refreshing)
+Trackers updated
+Torrent moved to \'%1$s\'
+
+Details
+Files
+Size:
+State:
+Downloaded:
+Uploaded:
+Rate:
+Eta:
+Availability:
+Peers:
+Label:
+Trackers:
+%1$s (expand)
+(collapse)
+Errors:
+Listing the files is not supported by your torrent client or it is not yet implemented
+File priorities updated
+
+Off
+Low
+Normal
+High
+Remote play in VLC
+Download using (S)FTP
+
+Transdroid 4x1
+Transdroid 2x1
+Server
+Refresh interval
+Style
+Add this widget
+DL @
+up
+UP @
+inactive
+/s
+eta
+unknown eta
+new
+
+New torrent added
+Torrent finished downloading
+New torrents available
+%d new RSS feed torrents
+
+RSS
+No RSS feeds installed\n\nUse the menu to add new feeds
+Loading RSS feed
+Connected, but the RSS feed is empty
+
+Error during communication with server
+Error building request
+Error parsing of server response (please check your settings)
+Web interface not connected to a running daemon
+Access denied (please check your settings)
+Can\'t read .torrent file
+Error while parsing the RSS feed
+This URL is not well-formed
+Your web search URL is invalid:
+Input is not a valid IP address or host name
+Port number is always numeric
+Directory paths end with a / or \
+Timeout can not be empty and is a positive number
+The RSS feed item didn\'t provide an URL enclosure or link tag pointing to the .torrent file
+The RSS feed item does not provide a link to browse to
+URL is no (valid) RSS feed
+SD card not available to read/write
+File does not seem to contain Transdroid settings
+There is no settings file found
+
+Xirvik offers shared, semi-dedicated or dedicated seedboxes. Transdroid provides easy setup for all Xirvik servers.\n\nRead more at www.xirvik.com
+Add Xirvik server
+Xirvik server settings
+Server type
+Shared, semi- or dedicated
+Server name
+Like dedi000.xirvik.com
+Invalid server (use the full host name, like dedi000.xirvik.com)
+
+SeedM8 offers unmetered GBit seedbox hosting. Transdroid provides easy setup for SeedM8 servers.\n\nRead more at www.seedm8.com
+Add SeedM8 server
+SeedM8 server settings
+Server name
+Like alpha.seedm8.com
+Invalid server (use the full host name, like alpha.seedm8.com)
+
+
+Combined ordering
+Number of seeders/leechers
+
+
+
+No automatic refresh
+2 seconds
+5 seconds
+15 seconds
+1 minute
+5 minutes
+15 minutes
+1 hour
+
+
+
+1 minute
+10 minutes
+30 minutes
+1 hour
+3 hours
+12 hours
+1 day
+
+
+
+Android 1.5
+Android 1.6
+Quick Search Box
+Black
+Transparent
+
+
diff --git a/android/res/values/styles.xml b/android/res/values/styles.xml
new file mode 100644
index 00000000..0c49b5c1
--- /dev/null
+++ b/android/res/values/styles.xml
@@ -0,0 +1,51 @@
+
+
+ 16dip
+ 24dip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/values/themes.xml b/android/res/values/themes.xml
new file mode 100644
index 00000000..b83dc756
--- /dev/null
+++ b/android/res/values/themes.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/xml/appwidget_medium.xml b/android/res/xml/appwidget_medium.xml
new file mode 100644
index 00000000..f236cab8
--- /dev/null
+++ b/android/res/xml/appwidget_medium.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/android/res/xml/appwidget_small.xml b/android/res/xml/appwidget_small.xml
new file mode 100644
index 00000000..3ead2a55
--- /dev/null
+++ b/android/res/xml/appwidget_small.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/android/res/xml/globalsearchable.xml b/android/res/xml/globalsearchable.xml
new file mode 100644
index 00000000..e4e7fc6b
--- /dev/null
+++ b/android/res/xml/globalsearchable.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/android/res/xml/preferences_interface.xml b/android/res/xml/preferences_interface.xml
new file mode 100644
index 00000000..eaa38066
--- /dev/null
+++ b/android/res/xml/preferences_interface.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/res/xml/searchable.xml b/android/res/xml/searchable.xml
new file mode 100644
index 00000000..7af135c6
--- /dev/null
+++ b/android/res/xml/searchable.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/src/com/commonsware/cwac/merge/MergeAdapter.java b/android/src/com/commonsware/cwac/merge/MergeAdapter.java
new file mode 100644
index 00000000..460d4da0
--- /dev/null
+++ b/android/src/com/commonsware/cwac/merge/MergeAdapter.java
@@ -0,0 +1,279 @@
+/***
+ Copyright (c) 2008-2009 CommonsWare, LLC
+ Portions (c) 2009 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package com.commonsware.cwac.merge;
+
+import android.database.DataSetObserver;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+import java.util.ArrayList;
+import java.util.List;
+import com.commonsware.cwac.sacklist.SackOfViewsAdapter;
+
+/**
+ * Adapter that merges multiple child adapters and views
+ * into a single contiguous whole.
+ *
+ * Adapters used as pieces within MergeAdapter must
+ * have view type IDs monotonically increasing from 0. Ideally,
+ * adapters also have distinct ranges for their row ids, as
+ * returned by getItemId().
+ *
+ */
+public class MergeAdapter extends BaseAdapter {
+ private ArrayList pieces=new ArrayList();
+
+ /**
+ * Stock constructor, simply chaining to the superclass.
+ */
+ public MergeAdapter() {
+ super();
+ }
+
+ /**
+ * Adds a new adapter to the roster of things to appear
+ * in the aggregate list.
+ * @param adapter Source for row views for this section
+ */
+ public void addAdapter(ListAdapter adapter) {
+ pieces.add(adapter);
+ adapter.registerDataSetObserver(new CascadeDataSetObserver());
+ }
+
+ /**
+ * Adds a new View to the roster of things to appear
+ * in the aggregate list.
+ * @param view Single view to add
+ */
+ public void addView(View view) {
+ addView(view, false);
+ }
+
+ /**
+ * Adds a new View to the roster of things to appear
+ * in the aggregate list.
+ * @param view Single view to add
+ * @param enabled false if views are disabled, true if enabled
+ */
+ public void addView(View view, boolean enabled) {
+ ArrayList list=new ArrayList(1);
+
+ list.add(view);
+
+ addViews(list, enabled);
+ }
+
+ /**
+ * Adds a list of views to the roster of things to appear
+ * in the aggregate list.
+ * @param views List of views to add
+ */
+ public void addViews(List views) {
+ addViews(views, false);
+ }
+
+ /**
+ * Adds a list of views to the roster of things to appear
+ * in the aggregate list.
+ * @param views List of views to add
+ * @param enabled false if views are disabled, true if enabled
+ */
+ public void addViews(List views, boolean enabled) {
+ if (enabled) {
+ addAdapter(new EnabledSackAdapter(views));
+ }
+ else {
+ addAdapter(new SackOfViewsAdapter(views));
+ }
+ }
+
+ /**
+ * Get the data item associated with the specified
+ * position in the data set.
+ * @param position Position of the item whose data we want
+ */
+ @Override
+ public Object getItem(int position) {
+ for (ListAdapter piece : pieces) {
+ int size=piece.getCount();
+
+ if (position views) {
+ super(views);
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return(true);
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return(true);
+ }
+ }
+
+ private class CascadeDataSetObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ notifyDataSetInvalidated();
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/src/com/commonsware/cwac/sacklist/SackOfViewsAdapter.java b/android/src/com/commonsware/cwac/sacklist/SackOfViewsAdapter.java
new file mode 100644
index 00000000..51059a21
--- /dev/null
+++ b/android/src/com/commonsware/cwac/sacklist/SackOfViewsAdapter.java
@@ -0,0 +1,174 @@
+/***
+ Copyright (c) 2008-2009 CommonsWare, LLC
+ Portions (c) 2009 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package com.commonsware.cwac.sacklist;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+/**
+ * Adapter that simply returns row views from a list.
+ *
+ * If you supply a size, you must implement newView(), to
+ * create a required view. The adapter will then cache these
+ * views.
+ *
+ * If you supply a list of views in the constructor, that
+ * list will be used directly. If any elements in the list
+ * are null, then newView() will be called just for those
+ * slots.
+ *
+ * Subclasses may also wish to override areAllItemsEnabled()
+ * (default: false) and isEnabled() (default: false), if some
+ * of their rows should be selectable.
+ *
+ * It is assumed each view is unique, and therefore will not
+ * get recycled.
+ *
+ * Note that this adapter is not designed for long lists. It
+ * is more for screens that should behave like a list. This
+ * is particularly useful if you combine this with other
+ * adapters (e.g., SectionedAdapter) that might have an
+ * arbitrary number of rows, so it all appears seamless.
+ */
+public class SackOfViewsAdapter extends BaseAdapter {
+ private List views=null;
+
+ /**
+ * Constructor creating an empty list of views, but with
+ * a specified count. Subclasses must override newView().
+ */
+ public SackOfViewsAdapter(int count) {
+ super();
+
+ views=new ArrayList(count);
+
+ for (int i=0;i views) {
+ super();
+
+ this.views=views;
+ }
+
+ /**
+ * Get the data item associated with the specified
+ * position in the data set.
+ * @param position Position of the item whose data we want
+ */
+ @Override
+ public Object getItem(int position) {
+ return(views.get(position));
+ }
+
+ /**
+ * How many items are in the data set represented by this
+ * Adapter.
+ */
+ @Override
+ public int getCount() {
+ return(views.size());
+ }
+
+ /**
+ * Returns the number of types of Views that will be
+ * created by getView().
+ */
+ @Override
+ public int getViewTypeCount() {
+ return(getCount());
+ }
+
+ /**
+ * Get the type of View that will be created by getView()
+ * for the specified item.
+ * @param position Position of the item whose data we want
+ */
+ @Override
+ public int getItemViewType(int position) {
+ return(position);
+ }
+
+ /**
+ * Are all items in this ListAdapter enabled? If yes it
+ * means all items are selectable and clickable.
+ */
+ @Override
+ public boolean areAllItemsEnabled() {
+ return(false);
+ }
+
+ /**
+ * Returns true if the item at the specified position is
+ * not a separator.
+ * @param position Position of the item whose data we want
+ */
+ @Override
+ public boolean isEnabled(int position) {
+ return(false);
+ }
+
+ /**
+ * Get a View that displays the data at the specified
+ * position in the data set.
+ * @param position Position of the item whose data we want
+ * @param convertView View to recycle, if not null
+ * @param parent ViewGroup containing the returned View
+ */
+ @Override
+ public View getView(int position, View convertView,
+ ViewGroup parent) {
+ View result=views.get(position);
+
+ if (result==null) {
+ result=newView(position, parent);
+ views.set(position, result);
+ }
+
+ return(result);
+ }
+
+ /**
+ * Get the row id associated with the specified position
+ * in the list.
+ * @param position Position of the item whose data we want
+ */
+ @Override
+ public long getItemId(int position) {
+ return(position);
+ }
+
+ /**
+ * Create a new View to go into the list at the specified
+ * position.
+ * @param position Position of the item whose data we want
+ * @param parent ViewGroup containing the returned View
+ */
+ protected View newView(int position, ViewGroup parent) {
+ throw new RuntimeException("You must override newView()!");
+ }
+}
\ No newline at end of file
diff --git a/android/src/com/seedm8/transdroid/preferences/PreferencesSeedM8Server.java b/android/src/com/seedm8/transdroid/preferences/PreferencesSeedM8Server.java
new file mode 100644
index 00000000..7096200b
--- /dev/null
+++ b/android/src/com/seedm8/transdroid/preferences/PreferencesSeedM8Server.java
@@ -0,0 +1,261 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package com.seedm8.transdroid.preferences;
+
+import org.transdroid.R;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.preferences.TransdroidCheckBoxPreference;
+import org.transdroid.preferences.TransdroidEditTextPreference;
+import org.transdroid.preferences.TransdroidListPreference;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.text.InputType;
+import android.text.method.PasswordTransformationMethod;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.ListView;
+import android.widget.Toast;
+
+public class PreferencesSeedM8Server extends PreferenceActivity {
+
+ public static final String PREFERENCES_8SERVER_KEY = "PREFERENCES_8SERVER_POSTFIX";
+ public static final String[] validAddressEnding = { ".seedm8.com" };
+
+ private String serverPostfix;
+ // These preferences are members so they can be accessed by the updateOptionAvailibility event
+ private TransdroidEditTextPreference name;
+ private TransdroidEditTextPreference server;
+ private TransdroidEditTextPreference user;
+ private TransdroidEditTextPreference dpass;
+ private TransdroidEditTextPreference dport;
+ private TransdroidEditTextPreference tpass;
+ private TransdroidEditTextPreference tport;
+ private TransdroidEditTextPreference rpass;
+ private TransdroidEditTextPreference spass;
+ private TransdroidCheckBoxPreference alarmFinished;
+ private TransdroidCheckBoxPreference alarmNew;
+
+ private String nameValue = null;
+ private String serverValue = null;
+ private String userValue = null;
+ private String dportValue;
+ private String tportValue;
+ //private String passValue = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // For which server?
+ serverPostfix = getIntent().getStringExtra(PREFERENCES_8SERVER_KEY);
+ // Create the preferences screen here: this takes care of saving/loading, but also contains the ListView adapter, etc.
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(this));
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ nameValue = prefs.getString(Preferences.KEY_PREF_8NAME + serverPostfix, null);
+ serverValue = prefs.getString(Preferences.KEY_PREF_8SERVER + serverPostfix, null);
+ userValue = prefs.getString(Preferences.KEY_PREF_8USER + serverPostfix, null);
+ dportValue = prefs.getString(Preferences.KEY_PREF_8DPORT + serverPostfix, null);
+ tportValue = prefs.getString(Preferences.KEY_PREF_8TPORT + serverPostfix, null);
+
+ // Create preference objects
+ getPreferenceScreen().setTitle(R.string.seedm8_pref_title);
+ // Name
+ name = new TransdroidEditTextPreference(this);
+ name.setTitle(R.string.pref_name);
+ name.setKey(Preferences.KEY_PREF_8NAME + serverPostfix);
+ name.getEditText().setSingleLine();
+ name.setDialogTitle(R.string.pref_name);
+ name.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(name);
+ // Server
+ server = new TransdroidEditTextPreference(this);
+ server.setTitle(R.string.seedm8_pref_server);
+ server.setKey(Preferences.KEY_PREF_8SERVER + serverPostfix);
+ server.getEditText().setSingleLine();
+ server.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
+ server.setDialogTitle(R.string.seedm8_pref_server);
+ server.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(server);
+ // User
+ user = new TransdroidEditTextPreference(this);
+ user.setTitle(R.string.pref_user);
+ user.setKey(Preferences.KEY_PREF_8USER + serverPostfix);
+ user.getEditText().setSingleLine();
+ user.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER);
+ user.setDialogTitle(R.string.pref_user);
+ user.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(user);
+
+ // Deluge Port
+ dport = new TransdroidEditTextPreference(this);
+ dport.setTitle("Deluge " + getString(R.string.pref_port));
+ dport.setKey(Preferences.KEY_PREF_8DPORT + serverPostfix);
+ dport.getEditText().setSingleLine();
+ dport.getEditText().setInputType(dport.getEditText().getInputType() | EditorInfo.TYPE_CLASS_NUMBER);
+ dport.setDialogTitle(R.string.pref_port);
+ dport.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(dport);
+ // Deluge Pass
+ dpass = new TransdroidEditTextPreference(this);
+ dpass.setTitle("Deluge " + getString(R.string.pref_pass));
+ dpass.setKey(Preferences.KEY_PREF_8DPASS + serverPostfix);
+ dpass.getEditText().setSingleLine();
+ dpass.getEditText().setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ dpass.getEditText().setTransformationMethod(new PasswordTransformationMethod());
+ dpass.setDialogTitle(R.string.pref_pass);
+ dpass.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(dpass);
+
+ // Transmission Port
+ tport = new TransdroidEditTextPreference(this);
+ tport.setTitle("Transmission " + getString(R.string.pref_port));
+ tport.setKey(Preferences.KEY_PREF_8TPORT + serverPostfix);
+ tport.getEditText().setSingleLine();
+ tport.getEditText().setInputType(tport.getEditText().getInputType() | EditorInfo.TYPE_CLASS_NUMBER);
+ tport.setDialogTitle(R.string.pref_port);
+ tport.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(tport);
+ // Transmission Pass
+ tpass = new TransdroidEditTextPreference(this);
+ tpass.setTitle("Transmission " + getString(R.string.pref_pass));
+ tpass.setKey(Preferences.KEY_PREF_8TPASS + serverPostfix);
+ tpass.getEditText().setSingleLine();
+ tpass.getEditText().setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ tpass.getEditText().setTransformationMethod(new PasswordTransformationMethod());
+ tpass.setDialogTitle(R.string.pref_pass);
+ tpass.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(tpass);
+
+ // rTorrent Pass
+ rpass = new TransdroidEditTextPreference(this);
+ rpass.setTitle("rTorrent RPC " + getString(R.string.pref_pass));
+ rpass.setKey(Preferences.KEY_PREF_8RPASS + serverPostfix);
+ rpass.getEditText().setSingleLine();
+ rpass.getEditText().setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ rpass.getEditText().setTransformationMethod(new PasswordTransformationMethod());
+ rpass.setDialogTitle(R.string.pref_pass);
+ rpass.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(rpass);
+
+ // SFTP Pass
+ spass = new TransdroidEditTextPreference(this);
+ spass.setTitle("SFTP " + getString(R.string.pref_pass));
+ spass.setKey(Preferences.KEY_PREF_8RPASS + serverPostfix);
+ spass.getEditText().setSingleLine();
+ spass.getEditText().setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ spass.getEditText().setTransformationMethod(new PasswordTransformationMethod());
+ spass.setDialogTitle(R.string.pref_pass);
+ spass.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(spass);
+
+ // AlertFinished
+ alarmFinished = new TransdroidCheckBoxPreference(this);
+ alarmFinished.setDefaultValue(true);
+ alarmFinished.setTitle(R.string.pref_alarmfinished);
+ alarmFinished.setSummary(R.string.pref_alarmfinished_info);
+ alarmFinished.setKey(Preferences.KEY_PREF_8ALARMFINISHED + serverPostfix);
+ alarmFinished.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(alarmFinished);
+ // AlertNew
+ alarmNew = new TransdroidCheckBoxPreference(this);
+ alarmNew.setTitle(R.string.pref_alarmnew);
+ alarmNew.setSummary(R.string.pref_alarmnew_info);
+ alarmNew.setKey(Preferences.KEY_PREF_8ALARMNEW + serverPostfix);
+ alarmNew.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(alarmNew);
+
+ updateDescriptionTexts();
+
+ }
+
+ private OnPreferenceChangeListener updateHandler = new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == name) {
+ nameValue = (String) newValue;
+ } else if (preference == server) {
+ String newServer = (String) newValue;
+ // Validate SeedM8 server address
+ boolean valid = newServer != null && !newServer.equals("") && newServer.indexOf(" ") == -1;
+ boolean validEnd = false;
+ for (int i = 0; i < validAddressEnding.length && valid; i++) {
+ validEnd |= newServer.endsWith(validAddressEnding[i]);
+ }
+ if (!valid || !validEnd) {
+ Toast.makeText(getApplicationContext(), R.string.seedm8_error_invalid_servername, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ serverValue = newServer;
+ } else if (preference == user) {
+ userValue = (String) newValue;
+ } else if (preference == dport) {
+ dportValue = (String) newValue;
+ // Validate user port input (should be non-empty; the text box already ensures that any input is actually a number)
+ if (((String)newValue).equals("")) {
+ Toast.makeText(getApplicationContext(), R.string.error_invalid_port_number, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ } else if (preference == tport) {
+ tportValue = (String) newValue;
+ // Validate user port input (should be non-empty; the text box already ensures that any input is actually a number)
+ if (((String)newValue).equals("")) {
+ Toast.makeText(getApplicationContext(), R.string.error_invalid_port_number, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ }
+ updateDescriptionTexts();
+ // Set the value as usual
+ return true;
+ }
+ };
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+
+ // Perform click action, which always is a Preference
+ Preference item = (Preference) getListAdapter().getItem(position);
+
+ // Let the Preference open the right dialog
+ if (item instanceof TransdroidListPreference) {
+ ((TransdroidListPreference)item).click();
+ } else if (item instanceof TransdroidCheckBoxPreference) {
+ ((TransdroidCheckBoxPreference)item).click();
+ } else if (item instanceof TransdroidEditTextPreference) {
+ ((TransdroidEditTextPreference)item).click();
+ }
+
+ }
+
+ private void updateDescriptionTexts() {
+
+ // Update the 'summary' labels of all preferences to show their current value
+ name.setSummary(nameValue == null? getText(R.string.pref_name_info): nameValue);
+ server.setSummary(serverValue == null? getText(R.string.seedm8_pref_server_info): serverValue);
+ user.setSummary(userValue == null? "": userValue);
+ dport.setSummary(dportValue == null? "": dportValue);
+ tport.setSummary(tportValue == null? "": tportValue);
+
+ }
+
+}
diff --git a/android/src/com/seedm8/transdroid/preferences/SeedM8Settings.java b/android/src/com/seedm8/transdroid/preferences/SeedM8Settings.java
new file mode 100644
index 00000000..01a83d2f
--- /dev/null
+++ b/android/src/com/seedm8/transdroid/preferences/SeedM8Settings.java
@@ -0,0 +1,171 @@
+package com.seedm8.transdroid.preferences;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.daemon.OS;
+import org.transdroid.daemon.util.HttpHelper;
+
+
+public class SeedM8Settings {
+
+ private static final String DEFAULT_NAME = "SeedM8";
+
+ final private String name;
+ final private String server;
+ final private String username;
+ final private int delugePort;
+ final private String delugePassword;
+ final private int transmissionPort;
+ final private String transmissionPassword;
+ final private String rtorrentPassword;
+ final private String sftpPassword;
+ final private boolean alarmOnFinishedDownload;
+ final private boolean alarmOnNewTorrent;
+ final private String idString;
+
+ public SeedM8Settings(String name, String server, String username, int delugePort,
+ String delugePassword, int transmissionPort, String transmissionPassword,
+ String rtorrentPassword, String sftpPassword, boolean alarmOnFinishedDownload, boolean alarmOnNewTorrent,
+ String idString) {
+ this.name = name;
+ this.server = server;
+ this.username = username;
+ this.delugePort = delugePort;
+ this.delugePassword = delugePassword;
+ this.transmissionPort = transmissionPort;
+ this.transmissionPassword = transmissionPassword;
+ this.rtorrentPassword = rtorrentPassword;
+ this.sftpPassword = sftpPassword;
+ this.alarmOnFinishedDownload = alarmOnFinishedDownload;
+ this.alarmOnNewTorrent = alarmOnNewTorrent;
+ this.idString = idString;
+ }
+
+ public String getName() {
+ return (name == null || name.equals("")? DEFAULT_NAME: name);
+ }
+ public String getServer() {
+ return server;
+ }
+ public String getUsername() {
+ return username;
+ }
+ public String getDelugePassword() {
+ return delugePassword;
+ }
+ public int getDelugePort() {
+ return delugePort;
+ }
+ public String getTransmissionPassword() {
+ return transmissionPassword;
+ }
+ public int getTransmissionPort() {
+ return transmissionPort;
+ }
+ public String getRtorrentPassword() {
+ return rtorrentPassword;
+ }
+ public String getSftpPassword() {
+ return sftpPassword;
+ }
+ public boolean shouldAlarmOnFinishedDownload() {
+ return alarmOnFinishedDownload;
+ }
+ public boolean shouldAlarmOnNewTorrent() {
+ return alarmOnNewTorrent;
+ }
+ public String getIdString() {
+ return idString;
+ }
+
+ /**
+ * Builds a text that can be used by a human reader to identify this daemon settings
+ * @return A concatenation of username, address, port and folder, where applicable
+ */
+ public String getHumanReadableIdentifier() {
+ return this.getUsername() + "@" + getServer();
+ }
+
+ @Override
+ public String toString() {
+ return getHumanReadableIdentifier();
+ }
+
+ public List createDaemonSettings(int startID) {
+ List daemons = new ArrayList();
+ // Deluge
+ if (getDelugePassword() != null && !getDelugePassword().equals("")) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + " Deluge",
+ Daemon.Deluge,
+ getUsername() + "." + getServer(),
+ getDelugePort(),
+ false,
+ false,
+ null,
+ null,
+ true,
+ getUsername(),
+ getDelugePassword(),
+ OS.Linux,
+ null,
+ "sftp://" + getServer() + "/home/" + getUsername() + "/private/deluge/data/",
+ getSftpPassword(),
+ HttpHelper.DEFAULT_CONNECTION_TIMEOUT,
+ shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ // Transmission
+ if (getTransmissionPassword() != null && !getTransmissionPassword().equals("")) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + " Transmission",
+ Daemon.Transmission,
+ getServer(),
+ getTransmissionPort(),
+ false,
+ false,
+ null,
+ null,
+ true,
+ getUsername(),
+ getTransmissionPassword(),
+ OS.Linux,
+ null,
+ "sftp://" + getServer() + "/home/" + getUsername() + "/private/transmission/data/",
+ getSftpPassword(),
+ HttpHelper.DEFAULT_CONNECTION_TIMEOUT,
+ shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ // rTorrent
+ if (getRtorrentPassword() != null && !getRtorrentPassword().equals("")) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + " rTorrent",
+ Daemon.rTorrent,
+ getUsername() + "." + getServer(),
+ 80,
+ false,
+ false,
+ null,
+ "/" + getUsername() + "/RPC",
+ true,
+ "rutorrent",
+ getRtorrentPassword(),
+ OS.Linux,
+ null,
+ "sftp://" + getUsername() + "@" + getServer() + "/home/" + getUsername() + "/private/rtorrent/data/",
+ getSftpPassword(),
+ HttpHelper.DEFAULT_CONNECTION_TIMEOUT,
+ shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ return daemons;
+ }
+
+}
diff --git a/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java b/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java
new file mode 100644
index 00000000..e6392f16
--- /dev/null
+++ b/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java
@@ -0,0 +1,205 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package com.xirvik.transdroid.preferences;
+
+import org.transdroid.R;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.preferences.TransdroidCheckBoxPreference;
+import org.transdroid.preferences.TransdroidEditTextPreference;
+import org.transdroid.preferences.TransdroidListPreference;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.text.InputType;
+import android.text.method.PasswordTransformationMethod;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.ListView;
+import android.widget.Toast;
+
+public class PreferencesXirvikServer extends PreferenceActivity {
+
+ public static final String PREFERENCES_XSERVER_KEY = "PREFERENCES_XSERVER_POSTFIX";
+ /*public static final String[] validAddressStart = { "dedi", "semi" };*/
+ public static final String[] validAddressEnding = { ".xirvik.com", ".xirvik.net" };
+
+ private String serverPostfix;
+ // These preferences are members so they can be accessed by the updateOptionAvailibility event
+ private TransdroidEditTextPreference name;
+ private TransdroidListPreference type;
+ private TransdroidEditTextPreference server;
+ private TransdroidEditTextPreference user;
+ private TransdroidEditTextPreference pass;
+ private TransdroidCheckBoxPreference alarmFinished;
+ private TransdroidCheckBoxPreference alarmNew;
+
+ private String nameValue = null;
+ private String typeValue = null;
+ private String serverValue = null;
+ private String userValue = null;
+ //private String passValue = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // For which server?
+ serverPostfix = getIntent().getStringExtra(PREFERENCES_XSERVER_KEY);
+ // Create the preferences screen here: this takes care of saving/loading, but also contains the ListView adapter, etc.
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(this));
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ nameValue = prefs.getString(Preferences.KEY_PREF_XNAME + serverPostfix, null);
+ typeValue = prefs.getString(Preferences.KEY_PREF_XTYPE + serverPostfix, null);
+ serverValue = prefs.getString(Preferences.KEY_PREF_XSERVER + serverPostfix, null);
+ userValue = prefs.getString(Preferences.KEY_PREF_XUSER + serverPostfix, null);
+ //passValue = prefs.getString(Preferences.KEY_PREF_XPASS + serverPostfix, null);
+
+ // Create preference objects
+ getPreferenceScreen().setTitle(R.string.xirvik_pref_title);
+ // Name
+ name = new TransdroidEditTextPreference(this);
+ name.setTitle(R.string.pref_name);
+ name.setKey(Preferences.KEY_PREF_XNAME + serverPostfix);
+ name.getEditText().setSingleLine();
+ name.setDialogTitle(R.string.pref_name);
+ name.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(name);
+ // Type
+ type = new TransdroidListPreference(this);
+ type.setTitle(R.string.xirvik_pref_type);
+ type.setKey(Preferences.KEY_PREF_XTYPE + serverPostfix);
+ type.setEntries(R.array.pref_xirvik_types);
+ type.setEntryValues(R.array.pref_xirvik_values);
+ type.setDialogTitle(R.string.xirvik_pref_type);
+ type.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(type);
+ // Server
+ server = new TransdroidEditTextPreference(this);
+ server.setTitle(R.string.xirvik_pref_server);
+ server.setKey(Preferences.KEY_PREF_XSERVER + serverPostfix);
+ server.getEditText().setSingleLine();
+ server.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
+ server.setDialogTitle(R.string.xirvik_pref_server);
+ server.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(server);
+ // User
+ user = new TransdroidEditTextPreference(this);
+ user.setTitle(R.string.pref_user);
+ user.setKey(Preferences.KEY_PREF_XUSER + serverPostfix);
+ user.getEditText().setSingleLine();
+ user.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER);
+ user.setDialogTitle(R.string.pref_user);
+ user.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(user);
+ // Pass
+ pass = new TransdroidEditTextPreference(this);
+ pass.setTitle(R.string.pref_pass);
+ pass.setKey(Preferences.KEY_PREF_XPASS + serverPostfix);
+ pass.getEditText().setSingleLine();
+ pass.getEditText().setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ pass.getEditText().setTransformationMethod(new PasswordTransformationMethod());
+ pass.setDialogTitle(R.string.pref_pass);
+ pass.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(pass);
+
+ // AlertFinished
+ alarmFinished = new TransdroidCheckBoxPreference(this);
+ alarmFinished.setDefaultValue(true);
+ alarmFinished.setTitle(R.string.pref_alarmfinished);
+ alarmFinished.setSummary(R.string.pref_alarmfinished_info);
+ alarmFinished.setKey(Preferences.KEY_PREF_XALARMFINISHED + serverPostfix);
+ alarmFinished.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(alarmFinished);
+ // AlertNew
+ alarmNew = new TransdroidCheckBoxPreference(this);
+ alarmNew.setTitle(R.string.pref_alarmnew);
+ alarmNew.setSummary(R.string.pref_alarmnew_info);
+ alarmNew.setKey(Preferences.KEY_PREF_XALARMNEW + serverPostfix);
+ alarmNew.setOnPreferenceChangeListener(updateHandler);
+ getPreferenceScreen().addItemFromInflater(alarmNew);
+
+ updateDescriptionTexts();
+
+ }
+
+ private OnPreferenceChangeListener updateHandler = new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == name) {
+ nameValue = (String) newValue;
+ } else if (preference == type) {
+ typeValue = (String) newValue;
+ } else if (preference == server) {
+ String newServer = (String) newValue;
+ // Validate Xirvik server address
+ boolean valid = newServer != null && !newServer.equals("") && !(newServer.indexOf(" ") >= 0);
+ boolean validEnd = false;
+ for (int i = 0; i < validAddressEnding.length && valid; i++) {
+ validEnd |= newServer.endsWith(validAddressEnding[i]);
+ }
+ if (!valid || !validEnd) {
+ Toast.makeText(getApplicationContext(), R.string.xirvik_error_invalid_servername, Toast.LENGTH_LONG).show();
+ return false;
+ }
+ serverValue = newServer;
+ } else if (preference == user) {
+ userValue = (String) newValue;
+ } else if (preference == pass) {
+ //passValue = (String) newValue;
+ }
+ updateDescriptionTexts();
+ // Set the value as usual
+ return true;
+ }
+ };
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+
+ // Perform click action, which always is a Preference
+ Preference item = (Preference) getListAdapter().getItem(position);
+
+ // Let the Preference open the right dialog
+ if (item instanceof TransdroidListPreference) {
+ ((TransdroidListPreference)item).click();
+ } else if (item instanceof TransdroidCheckBoxPreference) {
+ ((TransdroidCheckBoxPreference)item).click();
+ } else if (item instanceof TransdroidEditTextPreference) {
+ ((TransdroidEditTextPreference)item).click();
+ }
+
+ }
+
+ private void updateDescriptionTexts() {
+
+ // Update the 'summary' labels of all preferences to show their current value
+ XirvikServerType typeType = XirvikServerType.fromCode(typeValue);
+
+ name.setSummary(nameValue == null? getText(R.string.pref_name_info): nameValue);
+ type.setSummary(typeType == null? getText(R.string.xirvik_pref_type_info): typeType.toString());
+ server.setSummary(serverValue == null? getText(R.string.xirvik_pref_server_info): serverValue);
+ user.setSummary(userValue == null? "": userValue);
+
+ }
+
+}
diff --git a/android/src/com/xirvik/transdroid/preferences/XirvikServerType.java b/android/src/com/xirvik/transdroid/preferences/XirvikServerType.java
new file mode 100644
index 00000000..082cca21
--- /dev/null
+++ b/android/src/com/xirvik/transdroid/preferences/XirvikServerType.java
@@ -0,0 +1,53 @@
+package com.xirvik.transdroid.preferences;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+public enum XirvikServerType {
+
+ Dedicated (1),
+ SemiDedicated (2),
+ Shared (3);
+
+ private int code;
+ private static final Map lookup = new HashMap();
+
+ static {
+ for(XirvikServerType s : EnumSet.allOf(XirvikServerType.class))
+ lookup.put(s.getCode(), s);
+ }
+
+ XirvikServerType(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public static XirvikServerType getStatus(int code) {
+ return lookup.get(code);
+ }
+
+ /**
+ * Returns the type of xirvik server
+ * @param code A string with the code, similar to that used in arrays.xml
+ * @return The xirvik server type; or null if the code was null or empty
+ */
+ public static XirvikServerType fromCode(String code) {
+ if (code == null) {
+ return null;
+ }
+ if (code.equals("type_dedicated")) {
+ return Dedicated;
+ }
+ if (code.equals("type_semi")) {
+ return SemiDedicated;
+ }
+ if (code.equals("type_shared")) {
+ return Shared;
+ }
+ return null;
+ }
+}
diff --git a/android/src/com/xirvik/transdroid/preferences/XirvikSettings.java b/android/src/com/xirvik/transdroid/preferences/XirvikSettings.java
new file mode 100644
index 00000000..2aff675b
--- /dev/null
+++ b/android/src/com/xirvik/transdroid/preferences/XirvikSettings.java
@@ -0,0 +1,147 @@
+package com.xirvik.transdroid.preferences;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.daemon.OS;
+import org.transdroid.daemon.util.HttpHelper;
+
+
+public class XirvikSettings {
+
+ private static final String DEFAULT_NAME = "Xirvik";
+
+ private static final int TFB4RT_PORT = 443;
+ private static final String TFB4RT_FOLDER = "/tfx";
+ private static final int RTORRENT_PORT = 443;
+ private static final String RTORRENT_FOLDER_DEDI = "/RPC2";
+ private static final String RTORRENT_FOLDER_SEMI = "/RPC2";
+ private static final int UTORRENT_PORT = 5010;
+
+ final private String name;
+ final private XirvikServerType type;
+ final private String server;
+ final private String username;
+ final private String password;
+ final private boolean alarmOnFinishedDownload;
+ final private boolean alarmOnNewTorrent;
+ final private String idString;
+
+ public XirvikSettings(String name, XirvikServerType type, String server, String username,
+ String password, boolean alarmOnFinishedDownload, boolean alarmOnNewTorrent,
+ String idString) {
+ this.name = name;
+ this.type = type;
+ this.server = server;
+ this.username = username;
+ this.password = password;
+ this.alarmOnFinishedDownload = alarmOnFinishedDownload;
+ this.alarmOnNewTorrent = alarmOnNewTorrent;
+ this.idString = idString;
+ }
+
+ public String getName() {
+ return (name == null || name.equals("")? DEFAULT_NAME: name);
+ }
+ public XirvikServerType getType() {
+ return type;
+ }
+ public String getServer() {
+ return server;
+ }
+ public String getUsername() {
+ return username;
+ }
+ public String getPassword() {
+ return password;
+ }
+ public boolean shouldAlarmOnFinishedDownload() {
+ return alarmOnFinishedDownload;
+ }
+ public boolean shouldAlarmOnNewTorrent() {
+ return alarmOnNewTorrent;
+ }
+ public String getIdString() {
+ return idString;
+ }
+
+ /**
+ * Builds a text that can be used by a human reader to identify this daemon settings
+ * @return A concatenation of username, address, port and folder, where applicable
+ */
+ public String getHumanReadableIdentifier() {
+ return this.getUsername() + "@" + getServer();
+ }
+
+ @Override
+ public String toString() {
+ return getHumanReadableIdentifier();
+ }
+
+ public List createDaemonSettings(int startID) {
+ List daemons = new ArrayList();
+ boolean isDedi = getType() == XirvikServerType.Dedicated;
+ if (getType() == XirvikServerType.Shared || isDedi) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + (isDedi? " Torrentflux-b4rt": ""),
+ Daemon.Tfb4rt, getServer(), TFB4RT_PORT,
+ true, true, null,
+ TFB4RT_FOLDER, true, getUsername(), getPassword(),
+ OS.Linux, "/", "ftp://" + getName() + ":" + getServer() + "/",
+ getPassword(), HttpHelper.DEFAULT_CONNECTION_TIMEOUT, shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ if (getType() == XirvikServerType.SemiDedicated || isDedi) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + (isDedi? " rTorrent": ""),
+ Daemon.rTorrent, getServer(), RTORRENT_PORT,
+ true, true, null,
+ (isDedi? RTORRENT_FOLDER_DEDI: getSemiFoldername()), true, getUsername(), getPassword(),
+ OS.Linux, "/", "ftp://" + getName() + ":" + getServer() + "/",
+ getPassword(), HttpHelper.DEFAULT_CONNECTION_TIMEOUT, shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ if (isDedi) {
+ daemons.add(
+ new DaemonSettings(
+ getName() + " uTorrent",
+ Daemon.uTorrent, getServer(), UTORRENT_PORT,
+ false, false, null,
+ null, true, getUsername(), getPassword(),
+ OS.Linux, "/", "ftp://" + getName() + ":" + getServer() + "/",
+ getPassword(), HttpHelper.DEFAULT_CONNECTION_TIMEOUT, shouldAlarmOnFinishedDownload(),
+ shouldAlarmOnNewTorrent(), "" + startID++, true));
+ }
+ return daemons;
+ }
+
+ /**
+ * Returns the rTorrent folder name for a semi-dedicated server, based on the server, i.e. 'store001a.xirvik.com'
+ * @return The full folder name, i.e. '/RPC2'
+ */
+ private String getSemiFoldername() {
+ /*int nr = 0;
+ if (getServer().length() > 1) {
+ switch (getServer().charAt(getServer().indexOf(".") - 1)) {
+ case 'a':
+ nr = 1;
+ break;
+ case 'b':
+ nr = 2;
+ break;
+ case 'c':
+ nr = 3;
+ break;
+ case 'd':
+ nr = 4;
+ break;
+ }
+ }*/
+ return RTORRENT_FOLDER_SEMI;
+ }
+
+}
diff --git a/android/src/org/example/qberticus/quickactions/BetterPopupWindow.java b/android/src/org/example/qberticus/quickactions/BetterPopupWindow.java
new file mode 100644
index 00000000..ddf2bef9
--- /dev/null
+++ b/android/src/org/example/qberticus/quickactions/BetterPopupWindow.java
@@ -0,0 +1,201 @@
+package org.example.qberticus.quickactions;
+
+import org.transdroid.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+import android.widget.PopupWindow;
+
+/**
+ * This class does most of the work of wrapping the {@link PopupWindow} so it's simpler to use.
+ *
+ * @author qberticus
+ *
+ */
+public class BetterPopupWindow {
+ protected final View anchor;
+ private final PopupWindow window;
+ private View root;
+ private Drawable background = null;
+ private final WindowManager windowManager;
+
+ /**
+ * Create a BetterPopupWindow
+ *
+ * @param anchor
+ * the view that the BetterPopupWindow will be displaying 'from'
+ */
+ public BetterPopupWindow(View anchor) {
+ this.anchor = anchor;
+ this.window = new PopupWindow(anchor.getContext());
+
+ // when a touch even happens outside of the window
+ // make the window go away
+ this.window.setTouchInterceptor(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if(event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ BetterPopupWindow.this.window.dismiss();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ this.windowManager = (WindowManager) this.anchor.getContext().getSystemService(Context.WINDOW_SERVICE);
+ onCreate();
+ }
+
+ /**
+ * Anything you want to have happen when created. Probably should create a view and setup the event listeners on
+ * child views.
+ */
+ protected void onCreate() {}
+
+ /**
+ * In case there is stuff to do right before displaying.
+ */
+ protected void onShow() {}
+
+ private void preShow() {
+ if(this.root == null) {
+ throw new IllegalStateException("setContentView was not called with a view to display.");
+ }
+ onShow();
+
+ if(this.background == null) {
+ this.window.setBackgroundDrawable(new BitmapDrawable());
+ } else {
+ this.window.setBackgroundDrawable(this.background);
+ }
+
+ // if using PopupWindow#setBackgroundDrawable this is the only values of the width and hight that make it work
+ // otherwise you need to set the background of the root viewgroup
+ // and set the popupwindow background to an empty BitmapDrawable
+ this.window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
+ this.window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
+ this.window.setTouchable(true);
+ this.window.setFocusable(true);
+ this.window.setOutsideTouchable(true);
+
+ this.window.setContentView(this.root);
+ }
+
+ public void setBackgroundDrawable(Drawable background) {
+ this.background = background;
+ }
+
+ /**
+ * Sets the content view. Probably should be called from {@link onCreate}
+ *
+ * @param root
+ * the view the popup will display
+ */
+ public void setContentView(View root) {
+ this.root = root;
+ this.window.setContentView(root);
+ }
+
+ /**
+ * Will inflate and set the view from a resource id
+ *
+ * @param layoutResID
+ */
+ public void setContentView(int layoutResID) {
+ LayoutInflater inflator =
+ (LayoutInflater) this.anchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ this.setContentView(inflator.inflate(layoutResID, null));
+ }
+
+ /**
+ * If you want to do anything when {@link dismiss} is called
+ *
+ * @param listener
+ */
+ public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+ this.window.setOnDismissListener(listener);
+ }
+
+ /**
+ * Displays like a popdown menu from the anchor view
+ */
+ public void showLikePopDownMenu() {
+ this.showLikePopDownMenu(0, 0);
+ }
+
+ /**
+ * Displays like a popdown menu from the anchor view.
+ *
+ * @param xOffset
+ * offset in X direction
+ * @param yOffset
+ * offset in Y direction
+ */
+ public void showLikePopDownMenu(int xOffset, int yOffset) {
+ this.preShow();
+
+ this.window.setAnimationStyle(R.style.Animations_PopDownMenu);
+
+ this.window.showAsDropDown(this.anchor, xOffset, yOffset);
+ }
+
+ /**
+ * Displays like a QuickAction from the anchor view.
+ */
+ public void showLikeQuickAction() {
+ this.showLikeQuickAction(0, 0);
+ }
+
+ /**
+ * Displays like a QuickAction from the anchor view.
+ *
+ * @param xOffset
+ * offset in the X direction
+ * @param yOffset
+ * offset in the Y direction
+ */
+ public void showLikeQuickAction(int xOffset, int yOffset) {
+ this.preShow();
+
+ this.window.setAnimationStyle(R.style.Animations_GrowFromBottom);
+
+ int[] location = new int[2];
+ this.anchor.getLocationOnScreen(location);
+
+ Rect anchorRect =
+ new Rect(location[0], location[1], location[0] + this.anchor.getWidth(), location[1]
+ + this.anchor.getHeight());
+
+ this.root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+
+ int rootWidth = this.root.getMeasuredWidth();
+ int rootHeight = this.root.getMeasuredHeight();
+
+ int screenWidth = this.windowManager.getDefaultDisplay().getWidth();
+ //int screenHeight = this.windowManager.getDefaultDisplay().getHeight();
+
+ int xPos = ((screenWidth - rootWidth) / 2) + xOffset;
+ int yPos = anchorRect.top - rootHeight + yOffset;
+
+ // display on bottom
+ if(rootHeight > anchorRect.top) {
+ yPos = anchorRect.bottom + yOffset;
+ this.window.setAnimationStyle(R.style.Animations_GrowFromTop);
+ }
+
+ this.window.showAtLocation(this.anchor, Gravity.NO_GRAVITY, xPos, yPos);
+ }
+
+ public void dismiss() {
+ this.window.dismiss();
+ }
+}
diff --git a/android/src/org/ifies/android/sax/Channel.java b/android/src/org/ifies/android/sax/Channel.java
new file mode 100644
index 00000000..4835e323
--- /dev/null
+++ b/android/src/org/ifies/android/sax/Channel.java
@@ -0,0 +1,107 @@
+/*
+ * Taken from the 'Learning Android' project,;
+ * released as Public Domain software at
+ * http://github.com/digitalspaghetti/learning-android
+ */
+package org.ifies.android.sax;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class Channel {
+
+ public Channel() {
+ setCategories(new ArrayList());
+ setItems(new ArrayList());
+ }
+
+ public void setId(int id) {
+ m_Id = id;
+ }
+ public int getId() {
+ return m_Id;
+ }
+
+ public void setTitle(String title) {
+ m_Title = title;
+ }
+
+ public String getTitle() {
+ return m_Title;
+ }
+
+ public void setLink(String link) {
+ m_Link = link;
+ }
+
+ public String getLink() {
+ return m_Link;
+ }
+
+ public void setDescription(String description) {
+ m_Description = description;
+ }
+
+ public String getDescription() {
+ return m_Description;
+ }
+
+ public void setPubDate(Date date) {
+ m_PubDate = date;
+ }
+
+ public Date getPubDate() {
+ return m_PubDate;
+ }
+
+ public void setLastBuildDate(long lastBuildDate) {
+ m_LastBuildDate = lastBuildDate;
+ }
+
+ public long getLastBuildDate() {
+ return m_LastBuildDate;
+ }
+
+ public void setCategories(List categories) {
+ m_Categories = categories;
+ }
+
+ public void addCategory(String category) {
+ m_Categories.add(category);
+ }
+
+ public List getCategories() {
+ return m_Categories;
+ }
+
+ public void setItems(List items) {
+ m_Items = items;
+ }
+
+ public void addItem(Item item) {
+ m_Items.add(item);
+ }
+
+ public List getItems() {
+ return m_Items;
+ }
+
+ public void setImage(String image) {
+ m_Image = image;
+ }
+
+ public String getImage() {
+ return m_Image;
+ }
+
+ private int m_Id;
+ private String m_Title;
+ private String m_Link;
+ private String m_Description;
+ private Date m_PubDate;
+ private long m_LastBuildDate;
+ private List m_Categories;
+ private List m_Items;
+ private String m_Image;
+}
\ No newline at end of file
diff --git a/android/src/org/ifies/android/sax/Item.java b/android/src/org/ifies/android/sax/Item.java
new file mode 100644
index 00000000..3ace7c72
--- /dev/null
+++ b/android/src/org/ifies/android/sax/Item.java
@@ -0,0 +1,99 @@
+/*
+ * Taken from the 'Learning Android' project,;
+ * released as Public Domain software at
+ * http://github.com/digitalspaghetti/learning-android
+ */
+package org.ifies.android.sax;
+
+import java.util.Date;
+
+public class Item implements Comparable {
+
+ public void setId(int id) {
+ this._id = id;
+ }
+
+ public int getId() {
+ return _id;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ return this.title;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public void setLink(String link) {
+ this.link = link;
+ }
+
+ public String getLink() {
+ return this.link;
+ }
+
+ public void setPubdate(Date pubdate) {
+ this.pubDate = pubdate;
+ }
+
+ public Date getPubdate() {
+ return this.pubDate;
+ }
+
+ public void setEnclosureUrl(String enclosureUrl) {
+ this.enclosureUrl = enclosureUrl;
+ }
+
+ public void setEnclosureType(String enclosureType) {
+ this.enclosureType = enclosureType;
+ }
+
+ public String getEnclosureUrl() {
+ return this.enclosureUrl;
+ }
+
+ public String getEnclosureType() {
+ return this.enclosureType;
+ }
+
+ private int _id;
+ private String title;
+ private String link;
+ private String description;
+ private Date pubDate;
+ private String enclosureUrl;
+ private String enclosureType;
+
+ /**
+ * Returns 'the' item link, which preferably is the enclosure url, but otherwise the link (or null if that is empty too)
+ * @return A single link url to be used
+ */
+ public String getTheLink() {
+ if (this.getEnclosureUrl() != null) {
+ return this.getEnclosureUrl();
+ } else {
+ return this.getLink();
+ }
+ }
+
+ /**
+ * CompareTo is used to compare (and sort) item based on their publication dates
+ */
+ @Override
+ public int compareTo(Item another) {
+ if (another == null || this.pubDate == null || another.getPubdate() == null) {
+ return 0;
+ }
+ return this.pubDate.compareTo(another.getPubdate());
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/org/ifies/android/sax/RssParser.java b/android/src/org/ifies/android/sax/RssParser.java
new file mode 100644
index 00000000..c2c260a2
--- /dev/null
+++ b/android/src/org/ifies/android/sax/RssParser.java
@@ -0,0 +1,230 @@
+/*
+ * Taken from the 'Learning Android' project,;
+ * released as Public Domain software at
+ * http://github.com/digitalspaghetti/learning-android
+ * and modified heavily for Transdroid
+ */
+package org.ifies.android.sax;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.transdroid.daemon.DaemonException;
+import org.transdroid.daemon.util.FakeSocketFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class RssParser extends DefaultHandler
+{
+ /**
+ * The constructor for the RSS Parser
+ * @param url
+ */
+ public RssParser(String url) {
+ this.urlString = url;
+ this.text = new StringBuilder();
+ }
+
+ /**
+ * Returns the feed as a RssFeed, which is a ListArray
+ * @return RssFeed rssFeed
+ */
+ public Channel getChannel() {
+ return (this.channel);
+ }
+
+ public void parse() throws ParserConfigurationException, SAXException, IOException {
+
+ DefaultHttpClient httpclient = initialise();
+ HttpResponse result = httpclient.execute(new HttpGet(urlString));
+ //FileInputStream urlInputStream = new FileInputStream("/sdcard/rsstest2.txt");
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ if (spf != null) {
+ SAXParser sp = spf.newSAXParser();
+ sp.parse(result.getEntity().getContent(), this);
+ }
+
+ }
+
+ /**
+ * Instantiates an HTTP client that can be used for all Torrentflux-b4rt requests.
+ * @param connectionTimeout The connection timeout in milliseconds
+ * @return
+ * @throws DaemonException On conflicting or missing settings
+ */
+ private DefaultHttpClient initialise() {
+
+ SchemeRegistry registry = new SchemeRegistry();
+ registry.register(new Scheme("http", new PlainSocketFactory(), 80));
+ registry.register(new Scheme("https", new FakeSocketFactory(), 443));
+
+ HttpParams httpparams = new BasicHttpParams();
+ HttpConnectionParams.setConnectionTimeout(httpparams, 5000);
+ HttpConnectionParams.setSoTimeout(httpparams, 5000);
+ DefaultHttpClient httpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpparams, registry), httpparams);
+
+ return httpclient;
+
+ }
+
+ /**
+ * By default creates a standard Item (with title, description and links), which
+ * may to overriden to add more data.
+ * @return A possibly decorated Item instance
+ */
+ protected Item createNewItem() {
+ return new Item();
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) {
+
+ /** First lets check for the channel */
+ if (localName.equalsIgnoreCase("channel")) {
+ this.channel = new Channel();
+ }
+
+ /** Now lets check for an item */
+ if (localName.equalsIgnoreCase("item") && (this.channel != null)) {
+ this.item = createNewItem();
+ this.channel.addItem(this.item);
+ }
+
+ /** Now lets check for an image */
+ if (localName.equalsIgnoreCase("image") && (this.channel != null)) {
+ this.imgStatus = true;
+ }
+
+ /** Checking for a enclosure */
+ if (localName.equalsIgnoreCase("enclosure")) {
+ /** Lets check we are in an item */
+ if (this.item != null && attributes != null && attributes.getLength() > 0) {
+ this.item.setEnclosureUrl(parseLink(attributes.getValue("url")));
+ this.item.setEnclosureType(attributes.getValue("type"));
+ }
+ }
+
+ }
+
+ /**
+ * This is where we actually parse for the elements contents
+ */
+ public void endElement(String uri, String localName, String qName) {
+ /** Check we have an RSS Feed */
+ if (this.channel == null) {
+ return;
+ }
+
+ /** Check are at the end of an item */
+ if (localName.equalsIgnoreCase("item")) {
+ this.item = null;
+ }
+
+ /** Check we are at the end of an image */
+ if (localName.equalsIgnoreCase("image"))
+ this.imgStatus = false;
+
+ /** Now we need to parse which title we are in */
+ if (localName.equalsIgnoreCase("title"))
+ {
+ /** We are an item, so we set the item title */
+ if (this.item != null){
+ this.item.setTitle(this.text.toString().trim());
+ /** We are in an image */
+ } else {
+ this.channel.setTitle(this.text.toString().trim());
+ }
+ }
+
+ /** Now we are checking for a link */
+ if (localName.equalsIgnoreCase("link")) {
+ /** Check we are in an item **/
+ if (this.item != null) {
+ this.item.setLink(parseLink(this.text.toString()));
+ /** Check we are in an image */
+ } else if (this.imgStatus) {
+ this.channel.setImage(parseLink(this.text.toString()));
+ /** Check we are in a channel */
+ } else {
+ this.channel.setLink(parseLink(this.text.toString()));
+ }
+ }
+
+ /** Checking for a description */
+ if (localName.equalsIgnoreCase("description")) {
+ /** Lets check we are in an item */
+ if (this.item != null) {
+ this.item.setDescription(this.text.toString().trim());
+ /** Lets check we are in the channel */
+ } else {
+ this.channel.setDescription(this.text.toString().trim());
+ }
+ }
+
+ /** Checking for a pubdate */
+ if (localName.equalsIgnoreCase("pubDate")) {
+ /** Lets check we are in an item */
+ if (this.item != null) {
+ try {
+ this.item.setPubdate(new Date(Date.parse(this.text.toString().trim())));
+ } catch (Exception e) {
+ // Date is malformed (not parsable by Date.parse)
+ }
+ /** Lets check we are in the channel */
+ } else {
+ try {
+ this.channel.setPubDate(new Date(Date.parse(this.text.toString().trim())));
+ } catch (Exception e) {
+ // Date is malformed (not parsable by Date.parse)
+ }
+ }
+ }
+
+ /** Check for the category */
+ if (localName.equalsIgnoreCase("category") && (this.item != null)) {
+ this.channel.addCategory(this.text.toString().trim());
+ }
+
+ addAdditionalData(localName, this.item, this.text.toString());
+
+ this.text.setLength(0);
+ }
+
+ /**
+ * May be overridden to add additional data from tags that are not standard in RSS.
+ * Not used by this default RSS style parser.
+ * @param localName The tag name
+ * @param item The Item we are currently parsing
+ * @param text The new text content
+ */
+ protected void addAdditionalData(String localName, Item item, String text) { }
+
+ public void characters(char[] ch, int start, int length) {
+ this.text.append(ch, start, length);
+ }
+
+ private String parseLink(String string) {
+ return string.trim();
+ }
+
+ private String urlString;
+ private Channel channel;
+ private StringBuilder text;
+ private Item item;
+ private boolean imgStatus;
+
+}
\ No newline at end of file
diff --git a/android/src/org/transdroid/gui/Add.java b/android/src/org/transdroid/gui/Add.java
new file mode 100644
index 00000000..fe06d262
--- /dev/null
+++ b/android/src/org/transdroid/gui/Add.java
@@ -0,0 +1,165 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.transdroid.R;
+import org.transdroid.gui.util.ActivityUtil;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.Toast;
+
+/**
+ * Provides an activity in which the user can input a URL using a text box.
+ * Alternatively a file selector can be started for a local .torrent file. The
+ * URL or file location will then be forwarded to the Transdroid application.
+ *
+ * @author erickok
+ *
+ */
+public class Add extends Activity {
+
+ //private static final String LOG_NAME = "Add";
+ private final static String PICK_FILE_INTENT = "org.openintents.action.PICK_FILE";
+ private final static Uri OIFM_MARKET_URI = Uri.parse("market://search?q=pname:org.openintents.filemanager");
+ public static final int FILE_REQUEST_CODE = 1;
+
+ private static final int DIALOG_INSTALLFILEMANAGER = 1;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.activity_add);
+
+ // Add button click handlers
+ findViewById(R.id.ok).setOnClickListener(new OnClickListener() {
+ public void onClick(View arg0) {
+ parseInput();
+ }
+ });
+ findViewById(R.id.cancel).setOnClickListener(new OnClickListener() {
+ public void onClick(View arg0) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ findViewById(R.id.selectfile).setOnClickListener(new OnClickListener() {
+ public void onClick(View arg0) {
+ StartSelectorIntent();
+ }
+ });
+ }
+
+ /**
+ * Parse the text input and return the given URL
+ */
+ private void parseInput() {
+
+ // Get the URL text
+ EditText url = (EditText) findViewById(R.id.url);
+ String urlText = url.getText().toString();
+
+ // Check if no URL given
+ if (urlText == null || urlText.length() <= 0) {
+ Toast.makeText(this, R.string.no_valid_url, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Check URL structure
+ try {
+ new URL(urlText); // Nothing is actually done with it; only for parsing
+ } catch (MalformedURLException e) {
+ Toast.makeText(this, R.string.no_valid_url, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Create a result for the calling activity
+ Intent i = new Intent(this, Torrents.class);
+ i.setData(Uri.parse(urlText));
+ startActivity(i);
+ setResult(RESULT_OK);
+ finish();
+
+ }
+
+ /**
+ * Starts an Intent to pick a local .torrent file (usually form the SD card)
+ */
+ private void StartSelectorIntent() {
+
+ // Test to see if a file manager is available that can handle the PICK_FILE intent, such as IO File Manager
+ Intent pick = new Intent(PICK_FILE_INTENT);
+ if (ActivityUtil.isIntentAvailable(this, pick)) {
+ // Ask the file manager to allow the user to pick a file
+ startActivityForResult(pick, FILE_REQUEST_CODE);
+ } else {
+ // Show a message if the user should install OI File Manager for this feature
+ showDialog(DIALOG_INSTALLFILEMANAGER);
+ }
+
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_INSTALLFILEMANAGER:
+ return ActivityUtil.buildInstallDialog(this, R.string.oifm_not_found, OIFM_MARKET_URI);
+ }
+ return null;
+ }
+
+ /**
+ * A result was returned from the on of the intents
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ switch (requestCode) {
+ case FILE_REQUEST_CODE:
+ // Did we receive a file name?
+ if (data != null && data.getData() != null && data.getData().toString() != "") {
+
+ // Create a result for the calling activity
+ Intent i = new Intent(this, Torrents.class);
+ i.setData(data.getData());
+ startActivity(i);
+ setResult(RESULT_OK);
+ finish();
+
+ }
+ break;
+
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/Details.java b/android/src/org/transdroid/gui/Details.java
new file mode 100644
index 00000000..3fa042c4
--- /dev/null
+++ b/android/src/org/transdroid/gui/Details.java
@@ -0,0 +1,61 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import org.transdroid.R;
+import org.transdroid.daemon.Torrent;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+public class Details extends FragmentActivity {
+
+ //private static final String LOG_NAME = "Details";
+
+ public static final String STATE_DAEMON = "transdroid_state_details_daemon";
+ public static final String STATE_LABELS = "transdroid_state_details_labels";
+ public static final String STATE_TORRENT = "transdroid_state_details_torrent";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_details);
+
+ getSupportActionBar().setDisplayShowTitleEnabled(true);
+
+ if (savedInstanceState == null) {
+ Intent i = getIntent();
+ // Get torrent and daemon form the new intent
+ int daemonNumber = i.getIntExtra(STATE_DAEMON, 0);
+ String[] existingLabels = i.getStringArrayExtra(STATE_LABELS);
+ Torrent torrent = i.getParcelableExtra(STATE_TORRENT);
+
+ // Start the fragment for this torrent
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.details, new DetailsFragment(daemonNumber, torrent, existingLabels));
+ if (getSupportFragmentManager().findFragmentById(R.id.details) != null) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/org/transdroid/gui/DetailsFragment.java b/android/src/org/transdroid/gui/DetailsFragment.java
new file mode 100644
index 00000000..80e98c7d
--- /dev/null
+++ b/android/src/org/transdroid/gui/DetailsFragment.java
@@ -0,0 +1,765 @@
+package org.transdroid.gui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.transdroid.R;
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.daemon.IDaemonAdapter;
+import org.transdroid.daemon.IDaemonCallback;
+import org.transdroid.daemon.Priority;
+import org.transdroid.daemon.TaskQueue;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.daemon.TorrentDetails;
+import org.transdroid.daemon.TorrentFile;
+import org.transdroid.daemon.TorrentFilesComparator;
+import org.transdroid.daemon.TorrentFilesSortBy;
+import org.transdroid.daemon.task.DaemonTask;
+import org.transdroid.daemon.task.DaemonTaskFailureResult;
+import org.transdroid.daemon.task.DaemonTaskSuccessResult;
+import org.transdroid.daemon.task.GetFileListTask;
+import org.transdroid.daemon.task.GetFileListTaskSuccessResult;
+import org.transdroid.daemon.task.GetTorrentDetailsTask;
+import org.transdroid.daemon.task.GetTorrentDetailsTaskSuccessResult;
+import org.transdroid.daemon.task.PauseTask;
+import org.transdroid.daemon.task.RemoveTask;
+import org.transdroid.daemon.task.ResumeTask;
+import org.transdroid.daemon.task.RetrieveTask;
+import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
+import org.transdroid.daemon.task.SetDownloadLocationTask;
+import org.transdroid.daemon.task.SetFilePriorityTask;
+import org.transdroid.daemon.task.SetLabelTask;
+import org.transdroid.daemon.task.SetTrackersTask;
+import org.transdroid.daemon.task.StartTask;
+import org.transdroid.daemon.task.StopTask;
+import org.transdroid.gui.SetLabelDialog.ResultListener;
+import org.transdroid.gui.util.ActivityUtil;
+import org.transdroid.gui.util.DialogWrapper;
+import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.util.TLog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.Menu;
+import android.support.v4.view.MenuItem;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.Toast;
+
+public class DetailsFragment extends Fragment implements IDaemonCallback, OnSelectedChangedListener {
+
+ private static final String LOG_NAME = "Details fragment";
+
+ private static final int FILEMENU_SETPRIORITY_ID = 0;
+ private static final int FILEMENU_SETOFF_ID = 1;
+ private static final int FILEMENU_SETLOW_ID = 2;
+ private static final int FILEMENU_SETNORMAL_ID = 3;
+ private static final int FILEMENU_SETHIGH_ID = 4;
+ private static final int FILEMENU_REMOTESTART_ID = 5;
+ private static final int FILEMENU_FTPDOWNLOAD_ID = 6;
+
+ private static final int MENU_FORCESTART_ID = 0;
+ private static final int MENU_SETLOCATION_ID = 1;
+ private static final int MENU_EDITTRACKERS_ID = 2;
+ private static final int MENU_INVERTSELECTION_ID = 3;
+ private static final int MENU_REFRESH_ID = 4;
+
+ static final int DIALOG_ASKREMOVE = 11;
+ private static final int DIALOG_INSTALLVLC = 12;
+ private static final int DIALOG_INSTALLFTPCLIENT = 13;
+ static final int DIALOG_SETLABEL = 14;
+ private static final int DIALOG_SETLOCATION = 15;
+ private static final int DIALOG_EDITTRACKERS = 16;
+
+ TorrentFilesSortBy sortSetting = TorrentFilesSortBy.Alphanumeric;
+ boolean sortReversed = false;
+
+ private final int daemonNumber;
+ private Torrent torrent;
+ private TorrentDetails fineDetails = null;
+ private String[] existingLabels;
+ private IDaemonAdapter daemon;
+ private TaskQueue queue;
+
+ private LinearLayout prioBar;
+ private Button prioOff, prioLow, prioNormal, prioHigh;
+
+ public DetailsFragment(int daemonNumber, Torrent torrent, String[] existingLabels) {
+ this.daemonNumber = daemonNumber;
+ this.torrent = torrent;
+ this.existingLabels = existingLabels;
+ setHasOptionsMenu(true);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_details, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ registerForContextMenu(getListView());
+ getListView().setTextFilterEnabled(true);
+ getListView().setOnItemClickListener(onFileClicked);
+
+ prioBar = (LinearLayout) findViewById(R.id.setprio);
+ prioOff = (Button) findViewById(R.id.setprio_off);
+ prioLow = (Button) findViewById(R.id.setprio_low);
+ prioNormal = (Button) findViewById(R.id.setprio_normal);
+ prioHigh = (Button) findViewById(R.id.setprio_high);
+
+ prioOff.setOnClickListener(setPriorityOffClicked);
+ prioLow.setOnClickListener(setPriorityLowClicked);
+ prioNormal.setOnClickListener(setPriorityNormalClicked);
+ prioHigh.setOnClickListener(setPriorityHighClicked);
+
+ // Set up a task queue
+ queue = new TaskQueue(new TaskResultHandler(this));
+ queue.start();
+
+ loadData(true);
+ }
+
+ private void loadData(boolean clearOldData) {
+
+ if (torrent == null) {
+ TLog.d(LOG_NAME, "No torrent was provided in either the Intent or savedInstanceState.");
+ return;
+ }
+
+ // Setup the daemon
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ DaemonSettings daemonSettings = Preferences.readAllDaemonSettings(prefs).get(daemonNumber);
+ daemon = daemonSettings.getType().createAdapter(daemonSettings);
+
+ // Show the torrent details
+ getListView().setAdapter(new DetailsListAdapter(this, torrent, fineDetails));
+ getSupportActivity().setTitle(torrent.getName());
+
+ if (Daemon.supportsFileListing(daemon.getType())) {
+
+ // Remove possibly old data and start loading the new file list
+ if (clearOldData) {
+ getDetailsListAdapter().getTorrentFileAdapter().clear();
+ queue.enqueue(GetFileListTask.create(daemon, torrent));
+ }
+
+ } else {
+ // Show that details are not (yet) supported by this adapter
+ // TODO: Show this in a textview rather than as a toast pop-up
+ Toast.makeText(getActivity(), R.string.details_notsupported, Toast.LENGTH_LONG).show();
+ }
+
+ if (Daemon.supportsFineDetails(daemon.getType()) && clearOldData) {
+ queue.enqueue(GetTorrentDetailsTask.create(daemon, torrent));
+ }
+
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ TorrentFile file = getDetailsListAdapter().getTorrentFileAdapter().getItem(
+ (int) ((AdapterContextMenuInfo) menuInfo).id);
+
+ if (Daemon.supportsFilePrioritySetting(daemon.getType())) {
+ menu.add(FILEMENU_SETPRIORITY_ID, FILEMENU_SETOFF_ID, 0, R.string.file_off);
+ menu.add(FILEMENU_SETPRIORITY_ID, FILEMENU_SETLOW_ID, 0, R.string.file_low);
+ menu.add(FILEMENU_SETPRIORITY_ID, FILEMENU_SETNORMAL_ID, 0, R.string.file_normal);
+ menu.add(FILEMENU_SETPRIORITY_ID, FILEMENU_SETHIGH_ID, 0, R.string.file_high);
+ }
+ // Show a remote play option if the server supports file paths and a mime type for this file can be
+ // inferred
+ if (Daemon.supportsFilePaths(daemon.getType()) && torrent.getLocationDir() != null
+ && file.getMimeType() != null) {
+ menu.add(FILEMENU_REMOTESTART_ID, FILEMENU_REMOTESTART_ID, 0, R.string.file_remotestart);
+ }
+ if (daemon.getSettings().getFtpUrl() != null && !daemon.getSettings().getFtpUrl().equals("")) {
+ menu.add(FILEMENU_FTPDOWNLOAD_ID, FILEMENU_FTPDOWNLOAD_ID, 0, R.string.file_ftpdownload);
+ }
+
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem item) {
+
+ // Get the selected file
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ TorrentFile file = getDetailsListAdapter().getTorrentFileAdapter().getItem((int) info.id);
+
+ if (item.getItemId() >= FILEMENU_SETOFF_ID && item.getItemId() <= FILEMENU_SETHIGH_ID) {
+ // Update the priority for this file
+ Priority newPriority = file.getPriority();
+ switch (item.getItemId()) {
+ case FILEMENU_SETOFF_ID:
+ newPriority = Priority.Off;
+ break;
+ case FILEMENU_SETLOW_ID:
+ newPriority = Priority.Low;
+ break;
+ case FILEMENU_SETNORMAL_ID:
+ newPriority = Priority.Normal;
+ break;
+ case FILEMENU_SETHIGH_ID:
+ newPriority = Priority.High;
+ break;
+ }
+
+ // Schedule a task to update this file's priority
+ queue.enqueue(SetFilePriorityTask.create(daemon, torrent, newPriority, file));
+ }
+
+ if (item.getItemId() == FILEMENU_REMOTESTART_ID) {
+ // Set up an intent to remotely play this file (in VLC)
+ Intent remote = new Intent(Transdroid.REMOTEINTENT);
+ remote.addCategory(Intent.CATEGORY_DEFAULT);
+ // TODO: See if this still works
+ remote.setDataAndType(Uri.parse(file.getFullPathUri()), file.getMimeType());
+ remote.putExtra(Transdroid.REMOTEINTENT_HOST, daemon.getSettings().getAddress());
+
+ TLog.d(LOG_NAME, "Remote start requested for " + remote.getData() + " (" + remote.getType() + ")");
+ if (ActivityUtil.isIntentAvailable(getActivity(), remote)) {
+ startActivity(remote);
+ } else {
+ showDialog(DIALOG_INSTALLVLC);
+ }
+ }
+
+ if (item.getItemId() == FILEMENU_FTPDOWNLOAD_ID) {
+ // Set up an intent to download this file using the partial user-specified FTP URL
+ Uri ftpUri = Uri.parse(daemon.getSettings().getFtpUrl() + file.getRelativePath());
+ Intent dl = new Intent(Intent.ACTION_PICK);
+ dl.setDataAndType(Uri.parse(ftpUri.getScheme() + "://" + ftpUri.getHost()), Transdroid.ANDFTP_INTENT_TYPE);
+ dl.putExtra(Transdroid.ANDFTP_INTENT_USER, (ftpUri.getEncodedUserInfo() == null ? daemon.getSettings()
+ .getUsername() : ftpUri.getEncodedUserInfo()));
+ dl.putExtra(Transdroid.ANDFTP_INTENT_PASS, daemon.getSettings().getFtpPassword());
+ dl.putExtra(Transdroid.ANDFTP_INTENT_PASV, "true");
+ dl.putExtra(Transdroid.ANDFTP_INTENT_CMD, "download");
+ dl.putExtra(Transdroid.ANDFTP_INTENT_FILE, ftpUri.getEncodedPath());
+ dl.putExtra(Transdroid.ANDFTP_INTENT_LOCAL, "/sdcard/download");
+
+ TLog.d(LOG_NAME, "Requesting FTP transfer for " + dl.getStringExtra(Transdroid.ANDFTP_INTENT_FILE)
+ + " from " + dl.getDataString());
+ if (ActivityUtil.isIntentAvailable(getActivity(), dl)) {
+ startActivity(dl);
+ } else {
+ showDialog(DIALOG_INSTALLFTPCLIENT);
+ }
+ }
+
+ return true;
+
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if (getActivity() instanceof Details) {
+ // Add title bar buttons
+ MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
+ miRefresh.setIcon(R.drawable.icon_refresh_title);
+ miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
+ if (Daemon.supportsForcedStarting(daemon.getType())) {
+ MenuItem forced = menu.add(0, MENU_FORCESTART_ID, MENU_FORCESTART_ID, R.string.menu_forcestart);
+ forced.setIcon(R.drawable.icon_start_menu);
+ }
+ if (Daemon.supportsSetDownloadLocation(daemon.getType())) {
+ MenuItem location = menu
+ .add(0, MENU_SETLOCATION_ID, MENU_SETLOCATION_ID, R.string.menu_setdownloadlocation);
+ location.setIcon(android.R.drawable.ic_menu_upload);
+ }
+ if (Daemon.supportsSetTrackers(daemon.getType()) && fineDetails != null) {
+ MenuItem trackers = menu.add(0, MENU_EDITTRACKERS_ID, MENU_EDITTRACKERS_ID, R.string.menu_edittrackers);
+ trackers.setIcon(R.drawable.icon_trackers);
+ }
+ MenuItem invert = menu.add(0, MENU_INVERTSELECTION_ID, MENU_INVERTSELECTION_ID, R.string.menu_invertselection);
+ invert.setIcon(R.drawable.icon_mark);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_REFRESH_ID:
+ refreshActivity();
+ break;
+ case MENU_FORCESTART_ID:
+ queue.enqueue(StartTask.create(daemon, torrent, true));
+ return true;
+
+ case MENU_SETLOCATION_ID:
+ showDialog(DIALOG_SETLOCATION);
+ return true;
+
+ case MENU_EDITTRACKERS_ID:
+ showDialog(DIALOG_EDITTRACKERS);
+ return true;
+
+ case MENU_INVERTSELECTION_ID:
+ // Invert the current file selection
+ getDetailsListAdapter().getTorrentFileAdapter().invertSelection();
+ getListView().invalidateViews();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void onTorrentFilesLoaded(List allFiles) {
+ if (allFiles != null && getView() != null) {
+ Collections.sort(allFiles, new TorrentFilesComparator(TorrentFilesSortBy.Alphanumeric, false));
+ getDetailsListAdapter().getTorrentFileAdapter().replace(allFiles);
+ }
+ }
+
+ OnClickListener onResumePause = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (torrent.canPause()) {
+ queue.enqueue(PauseTask.create(daemon, torrent));
+ } else {
+ queue.enqueue(ResumeTask.create(daemon, torrent));
+ }
+ }
+ };
+
+ OnClickListener onStartStop = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (torrent.canStop()) {
+ queue.enqueue(StopTask.create(daemon, torrent));
+ } else {
+ queue.enqueue(StartTask.create(daemon, torrent, false));
+ }
+ }
+ };
+
+ OnClickListener onRemove = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(DIALOG_ASKREMOVE);
+ }
+ };
+
+ OnClickListener onSetLabel = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(DIALOG_SETLABEL);
+ }
+ };
+
+ private void setNewLabel(String newLabel) {
+
+ if (!Daemon.supportsSetLabel(daemon.getType())) {
+ // The daemon type does not support setting the label of a torrent
+ Toast.makeText(getActivity(), R.string.labels_no_support, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // Mimic that we have already set the label (for a response feel)
+ torrent.mimicNewLabel(newLabel);
+ getDetailsListAdapter().updateViewsAndButtonStates();
+
+ String saveLabel = newLabel;
+ if (newLabel.equals(getString(R.string.labels_unlabeled).toString())) {
+ // Setting a torrent to 'unlabeled' is actually setting the label to an empty string
+ saveLabel = "";
+ }
+ queue.enqueue(SetLabelTask.create(daemon, torrent, saveLabel));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+
+ protected Dialog onCreateDialog(int id) {
+
+ switch (id) {
+ case DIALOG_ASKREMOVE:
+
+ // Build a dialog that asks to confirm the deletions of a torrent
+ AlertDialog.Builder askRemoveDialog = new AlertDialog.Builder(getActivity());
+ askRemoveDialog.setTitle(R.string.askremove_title);
+ askRemoveDialog.setMessage(R.string.askremove);
+ askRemoveDialog.setPositiveButton(R.string.menu_remove, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ // Starts the remove task; we won't close this details dialog until its result is returned
+ queue.enqueue(RemoveTask.create(daemon, torrent, false));
+ dismissDialog(DIALOG_ASKREMOVE);
+ }
+ });
+ askRemoveDialog.setNeutralButton(R.string.menu_also_data, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ // Starts the remove task; we won't close this details dialog until its result is returned
+ queue.enqueue(RemoveTask.create(daemon, torrent, true));
+ dismissDialog(DIALOG_ASKREMOVE);
+ }
+ });
+ askRemoveDialog.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ dismissDialog(DIALOG_ASKREMOVE);
+ }
+ });
+ return askRemoveDialog.create();
+
+ case DIALOG_SETLABEL:
+
+ // Build a dialog that asks for a new or selected an existing label to assign to the selected
+ // torrent
+ SetLabelDialog setLabelDialog = new SetLabelDialog(getActivity(), new ResultListener() {
+ @Override
+ public void onLabelResult(String newLabel) {
+ if (newLabel.equals(getString(R.string.labels_unlabeled).toString())) {
+ // Setting a torrent to 'unlabeled' is actually setting the label to an empty string
+ newLabel = "";
+ }
+ setNewLabel(newLabel);
+ }
+ }, existingLabels, torrent.getLabelName());
+ setLabelDialog.setTitle(R.string.labels_newlabel);
+
+ return setLabelDialog;
+
+ case DIALOG_SETLOCATION:
+
+ // Build a dialog that asks for a new download location for the torrent
+ final View setLocationLayout = LayoutInflater.from(getActivity()).inflate(
+ R.layout.dialog_set_download_location, null);
+ final EditText newLocation = (EditText) setLocationLayout.findViewById(R.id.download_location);
+ AlertDialog.Builder setLocationDialog = new AlertDialog.Builder(getActivity());
+ setLocationDialog.setTitle(R.string.menu_setdownloadlocation);
+ setLocationDialog.setView(setLocationLayout);
+ setLocationDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ queue.enqueue(SetDownloadLocationTask.create(daemon, torrent, newLocation.getText().toString()));
+ }
+ });
+ setLocationDialog.setNegativeButton(android.R.string.cancel, null);
+ return setLocationDialog.create();
+
+ case DIALOG_EDITTRACKERS:
+
+ // Build a dialog that allows for the editing of the trackers
+ final View editTrackersLayout = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_edittrackers,
+ null);
+ final EditText trackersText = (EditText) editTrackersLayout.findViewById(R.id.trackers);
+ AlertDialog.Builder editTrackersDialog = new AlertDialog.Builder(getActivity());
+ editTrackersDialog.setTitle(R.string.menu_edittrackers);
+ editTrackersDialog.setView(editTrackersLayout);
+ editTrackersDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ queue.enqueue(SetTrackersTask.create(daemon, torrent, Arrays.asList(trackersText.getText()
+ .toString().split("\n"))));
+ }
+ });
+ editTrackersDialog.setNegativeButton(android.R.string.cancel, null);
+ return editTrackersDialog.create();
+
+ case DIALOG_INSTALLVLC:
+ return ActivityUtil.buildInstallDialog(getActivity(), R.string.vlcremote_not_found,
+ Transdroid.VLCREMOTE_MARKET_URI);
+ case DIALOG_INSTALLFTPCLIENT:
+ return ActivityUtil.buildInstallDialog(getActivity(), R.string.ftpclient_not_found,
+ Transdroid.ANDFTP_MARKET_URI);
+ }
+ return null;
+
+ }
+
+ /*
+ * @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog);
+ *
+ * switch (id) { case DIALOG_SETLABEL:
+ *
+ * // Re-populate the dialog adapter with the available labels SetLabelDialog setLabelDialog =
+ * (SetLabelDialog) dialog; setLabelDialog.resetDialog(this, existingLabels, torrent.getLabelName());
+ * break;
+ *
+ * case DIALOG_SETLOCATION:
+ *
+ * // Show the existing download location final EditText newLocation = (EditText)
+ * dialog.findViewById(R.id.download_location); newLocation.setText(torrent.getLocationDir()); break;
+ *
+ * case DIALOG_EDITTRACKERS:
+ *
+ * // Show the existing trackers final EditText trackersText = (EditText)
+ * dialog.findViewById(R.id.trackers); trackersText.setText(fineDetails.getTrackersText()); break;
+ *
+ * } }
+ */
+
+ @Override
+ public void onQueueEmpty() {
+ // No active task: turn off status indicator
+ // ((TransdroidListActivity)getActivity()).setProgressBar(false);
+ }
+
+ @Override
+ public void onQueuedTaskFinished(DaemonTask finished) {
+ }
+
+ @Override
+ public void onQueuedTaskStarted(DaemonTask started) {
+ // Started on a new task: turn on status indicator
+ // ((TransdroidListActivity)getActivity()).setProgressBar(true);
+ }
+
+ @Override
+ public void onTaskFailure(DaemonTaskFailureResult result) {
+
+ // Show error message
+ Toast.makeText(getActivity(), LocalTorrent.getResourceForDaemonException(result.getException()),
+ Toast.LENGTH_SHORT * 2).show();
+
+ }
+
+ @Override
+ public void onTaskSuccess(DaemonTaskSuccessResult result) {
+
+ if (getView() == null) {
+ // We are no longer visible: discard the result
+ return;
+ }
+
+ switch (result.getMethod()) {
+ case Retrieve:
+ // In the full updated list of torrents, look for the one we are showing
+ // (Of course ideally we would only request info on this torrent, but there is no such
+ // DaemonMethod for that at the moment)
+ List list = ((RetrieveTaskSuccessResult) result).getTorrents();
+ if (list != null) {
+ for (Torrent t : list) {
+ if (torrent.getUniqueID().equals(t.getUniqueID())) {
+
+ // This is the updated torrent data for the torrent we are showing
+ torrent = t;
+ getDetailsListAdapter().setTorrent(torrent);
+ getDetailsListAdapter().updateViewsAndButtonStates();
+
+ // Force a label name (use 'unlabeled' if none is provided)
+ if (torrent.getLabelName() == null || torrent.getLabelName().equals("")) {
+ torrent.mimicNewLabel(getText(R.string.labels_unlabeled).toString());
+ }
+
+ break;
+ }
+ }
+ }
+ break;
+
+ case GetTorrentDetails:
+ fineDetails = ((GetTorrentDetailsTaskSuccessResult) result).getTorrentDetails();
+ getDetailsListAdapter().setTorrentDetails(fineDetails);
+ getDetailsListAdapter().updateViewsAndButtonStates();
+ break;
+
+ case GetFileList:
+ onTorrentFilesLoaded(((GetFileListTaskSuccessResult) result).getFiles());
+ break;
+
+ case SetFilePriorities:
+ // Queue a new task to update the file listing
+ Toast.makeText(getActivity(), R.string.details_priorities_updated, Toast.LENGTH_SHORT).show();
+ queue.enqueue(GetFileListTask.create(daemon, torrent));
+ break;
+
+ case Pause:
+ torrent.mimicPause();
+ getDetailsListAdapter().updateViewsAndButtonStates();
+ break;
+
+ case Resume:
+ torrent.mimicResume();
+ getDetailsListAdapter().updateViewsAndButtonStates();
+ queue.enqueue(RetrieveTask.create(daemon));
+ queue.enqueue(GetFileListTask.create(daemon, torrent));
+ break;
+
+ case Stop:
+ torrent.mimicStop();
+ getDetailsListAdapter().updateViewsAndButtonStates();
+ break;
+
+ case Start:
+ torrent.mimicStart();
+ getDetailsListAdapter().updateViewsAndButtonStates();
+ queue.enqueue(RetrieveTask.create(daemon));
+ queue.enqueue(GetFileListTask.create(daemon, torrent));
+ break;
+
+ case Remove:
+ boolean includingData = ((RemoveTask) result.getTask()).includingData();
+ Toast.makeText(
+ getActivity(),
+ "'" + result.getTargetTorrent().getName() + "' "
+ + getText(includingData ? R.string.torrent_removed_with_data : R.string.torrent_removed),
+ Toast.LENGTH_SHORT).show();
+ // Close this details fragment
+ FragmentTransaction ft = getSupportActivity().getSupportFragmentManager().beginTransaction();
+ ft.remove(this);
+ ft.addToBackStack(null);
+ ft.commit();
+ break;
+
+ case SetDownloadLocation:
+ Toast.makeText(getActivity(),
+ getString(R.string.torrent_locationset, ((SetDownloadLocationTask) result.getTask()).getNewLocation()),
+ Toast.LENGTH_SHORT).show();
+ // TODO: Show the download location in the details
+ break;
+
+ case SetTrackers:
+ Toast.makeText(getActivity(), R.string.torrent_trackersupdated, Toast.LENGTH_SHORT).show();
+ break;
+
+ }
+
+ }
+
+ public void onSelectedResultsChanged() {
+ if (getDetailsListAdapter().getTorrentFileAdapter().getSelected().size() == 0) {
+ // Hide the bar with priority setting buttons
+ prioBar.setVisibility(View.GONE);
+ } else if (Daemon.supportsFilePrioritySetting(daemon.getType())) {
+ prioBar.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private OnItemClickListener onFileClicked = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View v, int position, long id) {
+ // If something was already selected before, use an item click as selection click
+ if (!getDetailsListAdapter().getTorrentFileAdapter().getSelected().isEmpty()) {
+ TorrentFile file = getDetailsListAdapter().getTorrentFileAdapter().getItem(position - 1);
+ getDetailsListAdapter().getTorrentFileAdapter().itemChecked(file,
+ !getDetailsListAdapter().getTorrentFileAdapter().isItemChecked(file));
+ getListView().invalidateViews();
+ }
+ }
+ };
+
+ private OnClickListener setPriorityOffClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Queue a task to set the priority of all selected files
+ queueSetFilePrioritiesTask(Priority.Off, getDetailsListAdapter().getTorrentFileAdapter().getSelected());
+ }
+ };
+
+ private OnClickListener setPriorityLowClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Queue a task to set the priority of all selected files
+ queueSetFilePrioritiesTask(Priority.Low, getDetailsListAdapter().getTorrentFileAdapter().getSelected());
+ }
+ };
+
+ private OnClickListener setPriorityNormalClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Queue a task to set the priority of all selected files
+ queueSetFilePrioritiesTask(Priority.Normal, getDetailsListAdapter().getTorrentFileAdapter().getSelected());
+ }
+ };
+
+ private OnClickListener setPriorityHighClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Queue a task to set the priority of all selected files
+ queueSetFilePrioritiesTask(Priority.High, getDetailsListAdapter().getTorrentFileAdapter().getSelected());
+ }
+ };
+
+ private void queueSetFilePrioritiesTask(Priority newPriority, List selected) {
+ // Queue a task to set the priority of all selected files
+ queue.enqueue(SetFilePriorityTask.create(daemon, torrent, newPriority, (ArrayList) selected));
+ // Clear the selection
+ // TorrentFileListAdapter adapter = (TorrentFileListAdapter) fileslist.getAdapter();
+ // adapter.clearSelection();
+ }
+
+ public void pauseTorrent() {
+ queue.enqueue(PauseTask.create(daemon, torrent));
+ }
+
+ public void resumeTorrent() {
+ queue.enqueue(ResumeTask.create(daemon, torrent));
+ }
+
+ public void stopTorrent() {
+ queue.enqueue(StopTask.create(daemon, torrent));
+ }
+
+ public void startTorrent(boolean forced) {
+ queue.enqueue(StartTask.create(daemon, torrent, forced));
+ }
+
+ protected void refreshActivity() {
+ queue.enqueue(RetrieveTask.create(daemon));
+ if (Daemon.supportsFileListing(daemon.getType())) {
+ queue.enqueue(GetFileListTask.create(daemon, torrent));
+ }
+ if (Daemon.supportsFineDetails(daemon.getType())) {
+ queue.enqueue(GetTorrentDetailsTask.create(daemon, torrent));
+ }
+ }
+
+
+ protected View findViewById(int id) {
+ return getView().findViewById(id);
+ }
+
+ protected ListView getListView() {
+ return (ListView) findViewById(android.R.id.list);
+ }
+
+ private DetailsListAdapter getDetailsListAdapter() {
+ return (DetailsListAdapter) getListView().getAdapter();
+ }
+
+ public Daemon getActiveDaemonType() {
+ return daemon.getType();
+ }
+
+ public void showDialog(int id) {
+ new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG
+ + id);
+ }
+
+ protected void dismissDialog(int id) {
+ // Remove the dialog wrapper fragment for the dialog's ID
+ getSupportActivity().getSupportFragmentManager().beginTransaction().remove(
+ getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit();
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/DetailsListAdapter.java b/android/src/org/transdroid/gui/DetailsListAdapter.java
new file mode 100644
index 00000000..0ea03df2
--- /dev/null
+++ b/android/src/org/transdroid/gui/DetailsListAdapter.java
@@ -0,0 +1,257 @@
+package org.transdroid.gui;
+
+import java.util.ArrayList;
+
+import org.transdroid.R;
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.daemon.TorrentDetails;
+import org.transdroid.daemon.TorrentFile;
+import org.transdroid.daemon.TorrentStatus;
+import org.transdroid.daemon.util.FileSizeConverter;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+import com.commonsware.cwac.merge.MergeAdapter;
+
+public class DetailsListAdapter extends MergeAdapter {
+
+ private static final String DECIMAL_FORMATTER = "%.1f";
+
+ private DetailsFragment detailsFragment;
+ private Torrent torrent;
+ private TorrentDetails fineDetails;
+ private TorrentFileListAdapter filesAdapter;
+
+ private View detailsfields;
+ private TextView name, state, size, downloaded, uploaded, rate, eta, peers, availability, label, trackers, trackershint,
+ errors, errorshint;
+ private TableRow availabilityRow, labelRow, trackers1Row, trackers2Row, errors1Row, errors2Row;
+ private ImageButton resumepause, startstop, remove, setlabel;
+
+ private boolean showingTrackers = false;
+ private boolean showingErrors = false;
+
+ public DetailsListAdapter(DetailsFragment detailsFragment, Torrent torrent, TorrentDetails fineDetails) {
+ this.detailsFragment = detailsFragment;
+ this.torrent = torrent;
+ this.fineDetails = fineDetails;
+
+ // Add the standard details fields form details_header.xml
+ detailsfields = detailsFragment.getActivity().getLayoutInflater().inflate(R.layout.part_details_header, null);
+ addView(detailsfields);
+
+ name = (TextView) findViewById(R.id.details_name);
+ state = (TextView) findViewById(R.id.details_state);
+ size = (TextView) findViewById(R.id.details_size);
+ downloaded = (TextView) findViewById(R.id.details_downloaded);
+ uploaded = (TextView) findViewById(R.id.details_uploaded);
+ rate = (TextView) findViewById(R.id.details_rate);
+ eta = (TextView) findViewById(R.id.details_eta);
+ peers = (TextView) findViewById(R.id.details_peers);
+ availability = (TextView) findViewById(R.id.details_availability);
+ label = (TextView) findViewById(R.id.details_label);
+ trackers = (TextView) findViewById(R.id.details_trackers);
+ trackershint = (TextView) findViewById(R.id.details_trackershint);
+ trackershint.setOnClickListener(onTrackersExpandClick);
+ errors = (TextView) findViewById(R.id.details_errors);
+ errorshint = (TextView) findViewById(R.id.details_errorshint);
+ errorshint.setOnClickListener(onErrorsExpandClick);
+
+ availabilityRow = (TableRow) findViewById(R.id.detailsrow_availability);
+ labelRow = (TableRow) findViewById(R.id.detailsrow_label);
+ trackers1Row = (TableRow) findViewById(R.id.detailsrow_trackers1);
+ trackers2Row = (TableRow) findViewById(R.id.detailsrow_trackers2);
+ errors1Row = (TableRow) findViewById(R.id.detailsrow_errors1);
+ errors2Row = (TableRow) findViewById(R.id.detailsrow_errors2);
+
+ resumepause = (ImageButton) findViewById(R.id.resumepause);
+ startstop = (ImageButton) findViewById(R.id.startstop);
+ remove = (ImageButton) findViewById(R.id.remove);
+ setlabel = (ImageButton) findViewById(R.id.setlabel);
+ resumepause.setOnClickListener(onResumePause);
+ startstop.setOnClickListener(onStartStop);
+ remove.setOnClickListener(onRemove);
+ setlabel.setOnClickListener(onSetLabel);
+
+ filesAdapter = new TorrentFileListAdapter(detailsFragment, new ArrayList());
+ addAdapter(filesAdapter);
+
+ updateViewsAndButtonStates();
+ }
+
+ private View findViewById(int id) {
+ return detailsfields.findViewById(id);
+ }
+
+ public Torrent getTorrent() {
+ return this.torrent;
+ }
+
+ public TorrentFileListAdapter getTorrentFileAdapter() {
+ return filesAdapter;
+ }
+
+ public void setTorrent(Torrent torrent) {
+ this.torrent = torrent;
+ }
+
+ public void setTorrentDetails(TorrentDetails fineDetails) {
+ this.fineDetails = fineDetails;
+ }
+
+ void updateViewsAndButtonStates() {
+
+ if (name != null) {
+ // In case we have a name field (i.e. in tablet layouts)
+ name.setText(torrent.getName());
+ }
+
+ // Update textviews according to the torrent data
+ LocalTorrent local = LocalTorrent.fromTorrent(torrent);
+ state.setText(torrent.getStatusCode().toString());
+ size.setText(FileSizeConverter.getSize(torrent.getTotalSize()));
+ downloaded.setText(FileSizeConverter.getSize(torrent.getDownloadedEver()) + " (" +
+ String.format(DECIMAL_FORMATTER, torrent.getDownloadedPercentage() * 100) + "%)");
+ uploaded.setText(FileSizeConverter.getSize(torrent.getUploadedEver()) + " (" +
+ detailsFragment.getString(R.string.status_ratio, local.getRatioString()) + ")");
+ rate.setText(local.getProgressSpeedText(detailsFragment.getResources()));
+ if (torrent.getStatusCode() == TorrentStatus.Downloading) {
+ eta.setText(local.getRemainingTimeString(detailsFragment.getResources(), true));
+ availability.setText(String.format(DECIMAL_FORMATTER, torrent.getAvailability() * 100) + "%");
+ } else {
+ eta.setText("");
+ availability.setText("");
+ }
+ peers.setText(local.getProgressConnectionText(detailsFragment.getResources()));
+ label.setText((torrent.getLabelName() == null || torrent.getLabelName().equals(""))?
+ detailsFragment.getString(R.string.labels_unlabeled): torrent.getLabelName());
+ if (fineDetails == null || fineDetails.getTrackers() == null) {
+ trackers.setText("");
+ trackershint.setText("");
+ } else {
+ trackers.setText(fineDetails.getTrackersText());
+ if (showingTrackers) {
+ trackershint.setText(detailsFragment.getString(R.string.details_trackers_collapse));
+ } else {
+ trackershint.setText(detailsFragment.getString(R.string.details_trackers_expand,
+ fineDetails.getTrackers().size() > 0? fineDetails.getTrackers().get(0): ""));
+ }
+ }
+ String errorsText =
+ torrent.getError() != null? torrent.getError() +
+ (fineDetails != null && fineDetails.getErrors() != null && !fineDetails.getErrors().isEmpty()? "\n" + fineDetails.getErrorsText(): ""):
+ (fineDetails != null && fineDetails.getErrors() != null && !fineDetails.getErrors().isEmpty()? fineDetails.getErrorsText():
+ null);
+ if (errorsText == null) {
+ errors.setText("");
+ errorshint.setText("");
+ } else {
+ errors.setText(errorsText);
+ if (showingErrors) {
+ errorshint.setText(detailsFragment.getString(R.string.details_trackers_collapse));
+ } else {
+ errorshint.setText(detailsFragment.getString(R.string.details_trackers_expand,
+ errorsText.split("\n")[0]));
+ }
+ }
+
+ availabilityRow.setVisibility(Daemon.supportsAvailability(detailsFragment.getActiveDaemonType())? View.VISIBLE: View.GONE);
+ labelRow.setVisibility(Daemon.supportsLabels(detailsFragment.getActiveDaemonType())? View.VISIBLE: View.GONE);
+ trackers1Row.setVisibility(Daemon.supportsFineDetails(detailsFragment.getActiveDaemonType())? View.VISIBLE: View.GONE);
+ trackers2Row.setVisibility(showingTrackers? View.VISIBLE: View.GONE);
+ errors1Row.setVisibility(errorsText != null? View.VISIBLE: View.GONE);
+ errors2Row.setVisibility(showingErrors? View.VISIBLE: View.GONE);
+
+ // Update buttons
+ if (torrent.canPause()) {
+ resumepause.setImageResource(R.drawable.icon_pause);
+ } else {
+ resumepause.setImageResource(R.drawable.icon_resume);
+ }
+ if (Daemon.supportsStoppingStarting(detailsFragment.getActiveDaemonType())) {
+ if (torrent.canStop()) {
+ startstop.setImageResource(R.drawable.icon_stop);
+ } else {
+ startstop.setImageResource(R.drawable.icon_start);
+ }
+ } else {
+ startstop.setVisibility(View.GONE);
+ }
+ setlabel.setVisibility(Daemon.supportsSetLabel(detailsFragment.getActiveDaemonType())? View.VISIBLE: View.GONE);
+ }
+
+ private OnClickListener onTrackersExpandClick = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Show (or hide) the list of full trackers (and adjust the hint text accordingly)
+ showingTrackers = !showingTrackers;
+ trackers2Row.setVisibility(showingTrackers? View.VISIBLE: View.GONE);
+ if (showingTrackers) {
+ trackershint.setText(detailsFragment.getString(R.string.details_trackers_collapse));
+ } else {
+ trackershint.setText(detailsFragment.getString(R.string.details_trackers_expand,
+ fineDetails != null && fineDetails.getTrackers() != null && fineDetails.getTrackers().size() > 0?
+ fineDetails.getTrackers().get(0): ""));
+ }
+ }
+ };
+
+ private OnClickListener onErrorsExpandClick = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Show (or hide) the list of full trackers (and adjust the hint text accordingly)
+ showingErrors = (torrent.getError() != null || (fineDetails != null &&
+ fineDetails.getErrors() != null && !fineDetails.getErrors().isEmpty())) && !showingErrors;
+ errors2Row.setVisibility(showingErrors? View.VISIBLE: View.GONE);
+ if (showingErrors) {
+ errorshint.setText(detailsFragment.getString(R.string.details_trackers_collapse));
+ } else {
+ errorshint.setText(detailsFragment.getString(R.string.details_trackers_expand,
+ fineDetails != null && fineDetails.getErrors() != null && fineDetails.getErrors().size() > 0?
+ fineDetails.getErrors().get(0): ""));
+ }
+ }
+ };
+
+ private OnClickListener onResumePause = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (torrent.canPause()) {
+ detailsFragment.pauseTorrent();
+ } else {
+ detailsFragment.resumeTorrent();
+ }
+ }
+ };
+
+ private OnClickListener onStartStop = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (torrent.canStop()) {
+ detailsFragment.stopTorrent();
+ } else {
+ detailsFragment.startTorrent(false);
+ }
+ }
+ };
+
+ private OnClickListener onRemove = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ detailsFragment.showDialog(DetailsFragment.DIALOG_ASKREMOVE);
+ }
+ };
+
+ private OnClickListener onSetLabel = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ detailsFragment.showDialog(DetailsFragment.DIALOG_SETLABEL);
+ }
+ };
+
+}
diff --git a/android/src/org/transdroid/gui/LocalTorrent.java b/android/src/org/transdroid/gui/LocalTorrent.java
new file mode 100644
index 00000000..fc93c5ba
--- /dev/null
+++ b/android/src/org/transdroid/gui/LocalTorrent.java
@@ -0,0 +1,197 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import org.transdroid.R;
+import org.transdroid.daemon.DaemonException;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.daemon.TorrentStatus;
+import org.transdroid.daemon.util.FileSizeConverter;
+import org.transdroid.daemon.util.TimespanConverter;
+
+import android.content.res.Resources;
+
+/**
+ * Wrapper around Torrent to provide some addition getters that give translatable or
+ * otherwise formatted Strings of torrent statistics.
+ *
+ * @author erickok
+ */
+public class LocalTorrent {
+
+ /**
+ * Creates the LocalTorrent object so that the translatable/formattable
+ * version of a Torrent can be used.
+ * @param torrent The Torrent object
+ * @return The torrent 'casted' as LocalTorrent
+ */
+ public static LocalTorrent fromTorrent(Torrent torrent) {
+ return new LocalTorrent(torrent);
+ }
+
+ private final Torrent t;
+
+ private LocalTorrent(Torrent torrent) {
+ this.t = torrent;
+ }
+
+ private static final String DECIMAL_FORMATTER = "%.1f";
+
+ /**
+ * Builds a string showing the upload/download seed ratio. If not downloading,
+ * it will base the ratio on the total size; so if you created the torrent yourself
+ * you will have downloaded 0 bytes, but the ratio will pretend you have 100%.
+ * @return A nicely formatted string containing the upload/download seed ratio
+ */
+ public String getRatioString() {
+ long baseSize = t.getTotalSize();
+ if (t.getStatusCode() == TorrentStatus.Downloading) {
+ baseSize = t.getDownloadedEver();
+ }
+ if (baseSize <= 0) {
+ return String.format(DECIMAL_FORMATTER, 0d);
+ } else if (t.getRatio() == Double.POSITIVE_INFINITY) {
+ return "\u221E";
+ } else {
+ return String.format(DECIMAL_FORMATTER, t.getRatio());
+ }
+ }
+
+ public String getProgressSizeText(Resources r, boolean withAvailability) {
+
+ switch (t.getStatusCode()) {
+ case Waiting:
+ case Checking:
+ case Error:
+ // Not downloading yet
+ return r.getString(R.string.status_waitingtodl, FileSizeConverter.getSize(t.getTotalSize()));
+ case Downloading:
+ // Downloading
+ return r.getString(R.string.status_size1,
+ FileSizeConverter.getSize(t.getDownloadedEver()),
+ FileSizeConverter.getSize(t.getTotalSize()),
+ String.format(DECIMAL_FORMATTER, t.getDownloadedPercentage() * 100) + "%" +
+ (!withAvailability? "": "/" + String.format(DECIMAL_FORMATTER, t.getAvailability() * 100)+"%"));
+ case Seeding:
+ case Paused:
+ case Queued:
+ // Seeding or paused
+ return r.getString(R.string.status_size2, FileSizeConverter.getSize(t.getTotalSize()),
+ FileSizeConverter.getSize(t.getUploadedEver()));
+ default:
+ return "";
+ }
+
+ }
+
+ public String getProgressEtaRatioText(Resources r) {
+ switch (t.getStatusCode()) {
+ case Downloading:
+ // Downloading
+ return getRemainingTimeString(r, false);
+ case Seeding:
+ case Paused:
+ case Queued:
+ // Seeding or paused
+ return r.getString(R.string.status_ratio, getRatioString());
+ case Waiting:
+ case Checking:
+ case Error:
+ default:
+ return "";
+ }
+ }
+
+ public String getProgressConnectionText(Resources r) {
+
+ switch (t.getStatusCode()) {
+ case Waiting:
+ return r.getString(R.string.status_waiting);
+ case Checking:
+ return r.getString(R.string.status_checking);
+ case Downloading:
+ return r.getString(R.string.status_peers, t.getPeersSendingToUs(), t.getPeersConnected());
+ case Seeding:
+ return r.getString(R.string.status_peers, t.getPeersGettingFromUs(), t.getPeersConnected());
+ case Paused:
+ return r.getString(R.string.status_paused);
+ case Queued:
+ return r.getString(R.string.status_stopped);
+ case Error:
+ return r.getString(R.string.status_error);
+ default:
+ return r.getString(R.string.status_unknown);
+ }
+
+ }
+
+ public String getProgressSpeedText(Resources r) {
+
+ switch (t.getStatusCode()) {
+ case Waiting:
+ case Checking:
+ case Paused:
+ case Queued:
+ return "";
+ case Downloading:
+ return r.getString(R.string.status_speed_down,
+ FileSizeConverter.getSize(t.getRateDownload()) + r.getString(R.string.status_persecond)) + " " +
+ r.getString(R.string.status_speed_up,
+ FileSizeConverter.getSize(t.getRateUpload()) + r.getString(R.string.status_persecond));
+ case Seeding:
+ return r.getString(R.string.status_speed_up,
+ FileSizeConverter.getSize(t.getRateUpload()) + r.getString(R.string.status_persecond));
+ default:
+ return "";
+ }
+
+ }
+
+ public String getRemainingTimeString(Resources r, boolean inDays) {
+ if (t.getEta() == -1 || t.getEta() == -2) {
+ return r.getString(R.string.status_unknowneta);
+ }
+ return r.getString(R.string.status_eta, TimespanConverter.getTime(t.getEta(), inDays));
+ }
+
+ /**
+ * Convert a Daemon exception to a translatable human-readable error
+ * @param e The exception that was thrown by the daemon
+ * @return A string resource ID
+ */
+ public static int getResourceForDaemonException(DaemonException e) {
+ switch (e.getType()) {
+ case MethodUnsupported:
+ return R.string.error_jsonrequesterror;
+ case ConnectionError:
+ return R.string.error_httperror;
+ case UnexpectedResponse:
+ return R.string.error_jsonresponseerror;
+ case ParsingFailed:
+ return R.string.error_jsonrequesterror;
+ case NotConnected:
+ return R.string.error_daemonnotconnected;
+ case AuthenticationFailure:
+ return R.string.error_401;
+ case FileAccessError:
+ return R.string.error_torrentfile;
+ }
+ return R.string.error_httperror;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/MainViewType.java b/android/src/org/transdroid/gui/MainViewType.java
new file mode 100644
index 00000000..7c3c342d
--- /dev/null
+++ b/android/src/org/transdroid/gui/MainViewType.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+public enum MainViewType {
+ ShowAll (1),
+ OnlyDownloading (2),
+ OnlyUploading (3),
+ OnlyInactive (4);
+
+ private int code;
+ private static final Map lookup = new HashMap();
+
+ static {
+ for(MainViewType s : EnumSet.allOf(MainViewType.class))
+ lookup.put(s.getCode(), s);
+ }
+
+ MainViewType(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public static MainViewType getMainViewType(int code) {
+ return lookup.get(code);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/ServerSelection.java b/android/src/org/transdroid/gui/ServerSelection.java
new file mode 100644
index 00000000..486de1ad
--- /dev/null
+++ b/android/src/org/transdroid/gui/ServerSelection.java
@@ -0,0 +1,78 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import java.util.List;
+
+import org.transdroid.R;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.preferences.PreferencesAdapter;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.Intent.ShortcutIconResource;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.ListView;
+
+public class ServerSelection extends ListActivity {
+
+ private SharedPreferences prefs;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_serverselection);
+
+ prefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // List the daemons
+ List daemons = Preferences.readAllDaemonSettings(prefs);
+ setListAdapter(new PreferencesAdapter(this, daemons));
+
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+
+ // Perform click action depending on the clicked list item (note that dividers are ignored)
+ Object item = getListAdapter().getItem(position);
+
+ if (item instanceof DaemonSettings) {
+
+ // Get selected server
+ DaemonSettings daemon = (DaemonSettings) item;
+ Intent startIntent = new Intent(this, Torrents.class);
+ startIntent.putExtra(Transdroid.INTENT_OPENDAEMON, daemon.getIdString());
+
+ // Return the a shortcut intent for the selected server
+ Intent i = new Intent();
+ ShortcutIconResource icon = Intent.ShortcutIconResource.fromContext(this, R.drawable.icon);
+ i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, startIntent);
+ i.putExtra(Intent.EXTRA_SHORTCUT_NAME, daemon.getName());
+ i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
+ setResult(RESULT_OK, i);
+ finish();
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/SetLabelDialog.java b/android/src/org/transdroid/gui/SetLabelDialog.java
new file mode 100644
index 00000000..4e39258d
--- /dev/null
+++ b/android/src/org/transdroid/gui/SetLabelDialog.java
@@ -0,0 +1,99 @@
+package org.transdroid.gui;
+
+import org.transdroid.R;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.View;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * A dialog that shows a list of (existing) labels to choose from as well as
+ * give a free text input to assign a new label. If the chosen label is
+ * different form the current (already assigned) label, onLabelResult is
+ * called with the new-to-be-assigned label.
+ *
+ * @author erickok
+ */
+public class SetLabelDialog extends Dialog {
+
+ private ResultListener callback;
+ private String currentLabel;
+ private ListView existingLabelsList;
+ private EditText newLabelText;
+ private Button okButton;
+
+ /**
+ * Callback listener for when a label is either selected or entered by the user
+ */
+ public interface ResultListener {
+ /**
+ * Called when the label result is known and different form the current (already assigned) label
+ * @param label The chosen or newly entered label (to be assigned to a torrent)
+ */
+ public void onLabelResult(String label);
+ }
+
+ /**
+ * Constructor for the labels dialog
+ * @param context The activity context
+ * @param callback The activity that will handle the dialog result (being the to be assigned label string)
+ * @param existingLabels The labels to list as existing
+ * @param currentLabel The currently assigned label to the torrent
+ */
+ public SetLabelDialog(Context context, ResultListener callback, String[] existingLabels, String currentLabel) {
+ super(context);
+ this.callback = callback;
+ this.currentLabel = currentLabel;
+
+ // Custom layout
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.dialog_new_label);
+ existingLabelsList = (ListView) findViewById(R.id.labels);
+ newLabelText = (EditText) findViewById(R.id.new_label);
+ okButton = (Button) findViewById(R.id.set_button);
+
+ // Set content and attach listeners
+ existingLabelsList.setAdapter(new ArrayAdapter(context, R.layout.list_item_label, existingLabels));
+ existingLabelsList.setOnItemClickListener(onLabelSelected);
+ okButton.setOnClickListener(onNewLabelClick);
+ }
+
+ public void resetDialog(Context context, String[] existingLabels, String currentLabel) {
+ // Update the available existing labels and empty the text box
+ this.currentLabel = currentLabel;
+ existingLabelsList.setAdapter(new ArrayAdapter(context, R.layout.list_item_label, existingLabels));
+ newLabelText.setText("");
+ }
+
+ private OnItemClickListener onLabelSelected = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ // Set the result to be the selected item in the list
+ returnResult((String) existingLabelsList.getItemAtPosition(position));
+ }
+ };
+
+ private View.OnClickListener onNewLabelClick = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Set the result to be the current EditText input
+ returnResult(newLabelText.getText().toString());
+ }
+ };
+
+ private void returnResult(String label) {
+ // Return result (if needed) and close the dialog
+ if (currentLabel == null || !currentLabel.equals(label)) {
+ callback.onLabelResult(label);
+ }
+ dismiss();
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TaskResultHandler.java b/android/src/org/transdroid/gui/TaskResultHandler.java
new file mode 100644
index 00000000..4f676002
--- /dev/null
+++ b/android/src/org/transdroid/gui/TaskResultHandler.java
@@ -0,0 +1,94 @@
+package org.transdroid.gui;
+
+import org.transdroid.daemon.IDaemonCallback;
+import org.transdroid.daemon.task.DaemonTask;
+import org.transdroid.daemon.task.DaemonTaskFailureResult;
+import org.transdroid.daemon.task.DaemonTaskSuccessResult;
+
+import android.os.Handler;
+import android.os.Message;
+
+/**
+ * The Task result handler is a mediator between the worker and UI threads. It post
+ * back results from the executed tasks to itself (using the Handler class) and
+ * post this results (now on the UI thread) back to the original IDaemonCallback.
+ *
+ * @author erickok
+ *
+ */
+public class TaskResultHandler extends Handler implements IDaemonCallback {
+
+ private static final int QUEUE_EMPTY = 0;
+ private static final int TASK_FINISHED = 1;
+ private static final int TASK_STARTED = 2;
+ private static final int TASK_FAILURE = 3;
+ private static final int TASK_SUCCESS = 4;
+
+ private IDaemonCallback callback;
+
+ public TaskResultHandler(IDaemonCallback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ // We are now on the UI thread again, call the original method on the IDaemonCallback
+ switch (msg.what) {
+ case QUEUE_EMPTY:
+ callback.onQueueEmpty();
+ break;
+ case TASK_FINISHED:
+ callback.onQueuedTaskFinished((DaemonTask) msg.obj);
+ break;
+ case TASK_STARTED:
+ callback.onQueuedTaskStarted((DaemonTask) msg.obj);
+ break;
+ case TASK_FAILURE:
+ callback.onTaskFailure((DaemonTaskFailureResult) msg.obj);
+ break;
+ case TASK_SUCCESS:
+ callback.onTaskSuccess((DaemonTaskSuccessResult) msg.obj);
+ break;
+ }
+ }
+
+ @Override
+ public void onQueueEmpty() {
+ Message msg = Message.obtain(this);
+ msg.what = QUEUE_EMPTY;
+ sendMessage(msg);
+ }
+
+ @Override
+ public void onQueuedTaskFinished(DaemonTask finished) {
+ Message msg = Message.obtain(this);
+ msg.what = TASK_FINISHED;
+ msg.obj = finished;
+ sendMessage(msg);
+ }
+
+ @Override
+ public void onQueuedTaskStarted(DaemonTask started) {
+ Message msg = Message.obtain(this);
+ msg.what = TASK_STARTED;
+ msg.obj = started;
+ sendMessage(msg);
+ }
+
+ @Override
+ public void onTaskFailure(DaemonTaskFailureResult result) {
+ Message msg = Message.obtain(this);
+ msg.what = TASK_FAILURE;
+ msg.obj = result;
+ sendMessage(msg);
+ }
+
+ @Override
+ public void onTaskSuccess(DaemonTaskSuccessResult result) {
+ Message msg = Message.obtain(this);
+ msg.what = TASK_SUCCESS;
+ msg.obj = result;
+ sendMessage(msg);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentFileListAdapter.java b/android/src/org/transdroid/gui/TorrentFileListAdapter.java
new file mode 100644
index 00000000..f166f279
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentFileListAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import java.util.List;
+
+import org.transdroid.daemon.TorrentFile;
+import org.transdroid.gui.util.SelectableArrayAdapter;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * An adapter that can be mapped to a list of torrent files.
+ * @author erickok
+ *
+ */
+public class TorrentFileListAdapter extends SelectableArrayAdapter {
+
+ public TorrentFileListAdapter(DetailsFragment detailsActivity, List torrents) {
+ super(detailsActivity.getActivity(), torrents, detailsActivity);
+ }
+
+ public View getView(int position, View convertView, ViewGroup paret, boolean selected) {
+ // TODO: Try to reuse the convertView for better performance
+ return new TorrentFileListView(getContext(), this, getItem(position), selected);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentFileListView.java b/android/src/org/transdroid/gui/TorrentFileListView.java
new file mode 100644
index 00000000..cb928910
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentFileListView.java
@@ -0,0 +1,91 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import org.transdroid.R;
+import org.transdroid.daemon.TorrentFile;
+
+import android.content.Context;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+
+/**
+ * A view that shows a torrent file as a list item.
+ *
+ * @author erickok
+ *
+ */
+public class TorrentFileListView extends LinearLayout {
+
+ private TorrentFile file;
+ private TorrentFileListAdapter adapter;
+
+ /**
+ * Constructs a view that can display a torrent file (to use in a list)
+ * @param context The activity context
+ * @param torrent The torrent file to show the data for
+ */
+ public TorrentFileListView(Context context, TorrentFileListAdapter adapter, TorrentFile file, boolean initialyChecked) {
+ super(context);
+ this.adapter = adapter;
+
+ addView(inflate(context, R.layout.list_item_torrentfile, null));
+ setData(file, initialyChecked);
+ }
+
+ /**
+ * Sets the actual texts and images to the visible widgets (fields)
+ */
+ public void setData(TorrentFile file, boolean initialyChecked) {
+ this.file = file;
+ final CheckBox check = (CheckBox)findViewById(R.id.check);
+ check.setChecked(initialyChecked);
+ check.setOnCheckedChangeListener(itemSelection);
+
+ ((TextView)findViewById(R.id.name)).setText(file.getName());
+ ((TextView)findViewById(R.id.sizes)).setText(file.getDownloadedAndTotalSizeText());
+ ((TextView)findViewById(R.id.progress)).setText(file.getProgressText());
+ ImageView priority = (ImageView) findViewById(R.id.priority);
+ switch (file.getPriority()) {
+ case Off:
+ priority.setImageResource(R.drawable.icon_priority_off);
+ break;
+ case Low:
+ priority.setImageResource(R.drawable.icon_priority_low);
+ break;
+ case Normal:
+ priority.setImageResource(R.drawable.icon_priority_normal);
+ break;
+ case High:
+ priority.setImageResource(R.drawable.icon_priority_high);
+ break;
+ }
+ }
+
+ private OnCheckedChangeListener itemSelection = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ adapter.itemChecked(file, isChecked);
+ }
+ };
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentListAdapter.java b/android/src/org/transdroid/gui/TorrentListAdapter.java
new file mode 100644
index 00000000..4273e385
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentListAdapter.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import java.util.List;
+
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.gui.util.ArrayAdapter;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * An adapter that can be mapped to a list of torrents.
+ * @author erickok
+ *
+ */
+public class TorrentListAdapter extends ArrayAdapter {
+
+ TorrentsFragment mainScreen;
+
+ public TorrentListAdapter(TorrentsFragment mainScreen, List torrents) {
+ super(mainScreen.getActivity(), torrents);
+ this.mainScreen = mainScreen;
+ }
+
+ public View getView(int position, View convertView, ViewGroup paret) {
+ if (convertView == null) {
+ // Create a new view
+ return new TorrentListView(getContext(), getItem(position), Daemon.supportsAvailability(mainScreen.getActiveDaemonType()));
+ } else {
+ // Reuse view
+ TorrentListView setView = (TorrentListView) convertView;
+ setView.setData(getItem(position), Daemon.supportsAvailability(mainScreen.getActiveDaemonType()));
+ return setView;
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentListView.java b/android/src/org/transdroid/gui/TorrentListView.java
new file mode 100644
index 00000000..aaf68101
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentListView.java
@@ -0,0 +1,88 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import org.transdroid.R;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.daemon.TorrentStatus;
+
+import android.content.Context;
+import android.text.Html;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * A view that shows the torrent data as a list item.
+ *
+ * @author erickok
+ *
+ */
+public class TorrentListView extends LinearLayout {
+
+ private ViewHolder views;
+
+ /**
+ * Constructs a view that can display torrent data (to use in a list) and sets the display data
+ * @param context The activity context
+ * @param torrent The torrent info to show the data for
+ */
+ public TorrentListView(Context context, Torrent torrent, boolean withAvailability) {
+ super(context);
+ addView(inflate(context, R.layout.list_item_torrent, null));
+
+ setData(torrent, withAvailability);
+ }
+
+ /**
+ * Sets the actual texts and images to the visible widgets (fields)
+ */
+ public void setData(Torrent tor, boolean withAvailability) {
+ LocalTorrent torrent = LocalTorrent.fromTorrent(tor);
+ if (views == null) {
+ views = new ViewHolder();
+ views.name = (TextView) findViewById(R.id.name);
+ views.progressSize = (TextView) findViewById(R.id.progress_size);
+ views.progressEtaRatio = (TextView) findViewById(R.id.progress_eta_ratio);
+ views.pb = (TorrentProgressBar) findViewById(R.id.progressbar);
+ views.progressPeers = (TextView) findViewById(R.id.progress_peers);
+ views.progressSpeed = (TextView) findViewById(R.id.progress_speed);
+ }
+ views.name.setText(tor.getName());
+ views.progressSize.setText(Html.fromHtml(torrent.getProgressSizeText(getResources(), false)), TextView.BufferType.SPANNABLE);
+ views.progressEtaRatio.setText(Html.fromHtml(torrent.getProgressEtaRatioText(getResources())), TextView.BufferType.SPANNABLE);
+ views.pb.setProgress((int)(tor.getDownloadedPercentage() * 100));
+ views.pb.setActive(tor.canPause());
+ views.pb.setError(tor.getStatusCode() == TorrentStatus.Error);
+ views.progressPeers.setText(Html.fromHtml(torrent.getProgressConnectionText(getResources())), TextView.BufferType.SPANNABLE);
+ views.progressSpeed.setText(Html.fromHtml(torrent.getProgressSpeedText(getResources())), TextView.BufferType.SPANNABLE);
+
+ }
+
+ /**
+ * Used to further optimize the getting of Views
+ */
+ private static class ViewHolder {
+ TextView name;
+ TextView progressSize;
+ TextView progressEtaRatio;
+ TorrentProgressBar pb;
+ TextView progressPeers;
+ TextView progressSpeed;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentProgressBar.java b/android/src/org/transdroid/gui/TorrentProgressBar.java
new file mode 100644
index 00000000..e207800a
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentProgressBar.java
@@ -0,0 +1,118 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui;
+
+import org.transdroid.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class TorrentProgressBar extends View {
+
+ private final float scale = getContext().getResources().getDisplayMetrics().density;
+ private final float ROUND_SIZE = 3.3f * scale;
+ private final int MINIMUM_HEIGHT = (int)(8 * scale + 0.5f);
+ private final int RIGHT_MARGIN = (int)(3 * scale + 0.5f);
+
+ private int progress;
+ private boolean isActive;
+ private boolean isError;
+ private final Paint notdonePaint = new Paint();
+ private final Paint inactiveDonePaint = new Paint();
+ private final Paint inactivePaint = new Paint();
+ private final Paint progressPaint = new Paint();
+ private final Paint donePaint = new Paint();
+ private final Paint errorPaint = new Paint();
+
+ public void setProgress(int progress) {
+ this.progress = progress;
+ }
+
+ public void setActive(boolean isActive) {
+ this.isActive = isActive;
+ }
+
+ public void setError(boolean isError) {
+ this.isError = isError;
+ }
+
+ public TorrentProgressBar(Context context) {
+ super(context);
+ initPaints();
+ }
+
+ public TorrentProgressBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initPaints();
+
+ // Parse any set attributes from XML
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TorrentProgressBar);
+ if (a.hasValue(R.styleable.TorrentProgressBar_progress)) {
+ this.progress = a.getIndex(R.styleable.TorrentProgressBar_progress);
+ this.isActive = a.getBoolean(R.styleable.TorrentProgressBar_isActive, false);
+ }
+ a.recycle();
+ }
+
+ private void initPaints() {
+ notdonePaint.setColor(0xFFEEEEEE);
+ inactiveDonePaint.setColor(0xFFA759D4);
+ inactivePaint.setColor(0xFF9E9E9E);
+ progressPaint.setColor(0xFF42A8FA);
+ donePaint.setColor(0xFF8CCF29);
+ errorPaint.setColor(0xFFDE3939);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int ws = MeasureSpec.getSize(widthMeasureSpec) - RIGHT_MARGIN;
+ int hs = Math.max(getHeight(), MINIMUM_HEIGHT);
+ setMeasuredDimension(ws, hs);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int height = getHeight();
+ int width = getWidth();
+ RectF fullRect = new RectF(0, 0, width, height);
+
+ // Error?
+ if (isError) {
+ canvas.drawRoundRect(fullRect, ROUND_SIZE, ROUND_SIZE, errorPaint);
+ } else {
+ // Background rounded rectangle
+ canvas.drawRoundRect(fullRect, ROUND_SIZE, ROUND_SIZE, notdonePaint);
+
+ // Foreground progress indicator
+ if (progress > 0) {
+ RectF progressRect = new RectF(0, 0, width * ((float)progress / 100), height);
+ canvas.drawRoundRect(progressRect, ROUND_SIZE, ROUND_SIZE,
+ (isActive? (progress == 100? donePaint: progressPaint): (progress == 100? inactiveDonePaint: inactivePaint)));
+ }
+ }
+
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentViewSelectorWindow.java b/android/src/org/transdroid/gui/TorrentViewSelectorWindow.java
new file mode 100644
index 00000000..aac72db2
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentViewSelectorWindow.java
@@ -0,0 +1,133 @@
+package org.transdroid.gui;
+
+import java.util.List;
+
+import org.example.qberticus.quickactions.BetterPopupWindow;
+import org.transdroid.R;
+import org.transdroid.gui.util.ArrayAdapter;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class TorrentViewSelectorWindow extends BetterPopupWindow {
+
+ private final MainViewTypeSelectionListener mainViewTypeSelectionListener;
+ private final LabelSelectionListener labelSelectionListener;
+
+ private ViewGroup rootView;
+ private ListView labelsListView;
+ private LayoutInflater inflater;
+
+ public TorrentViewSelectorWindow(View anchor, MainViewTypeSelectionListener mainViewTypeSelectionListener, LabelSelectionListener labelSelectionListener) {
+ super(anchor);
+ this.mainViewTypeSelectionListener = mainViewTypeSelectionListener;
+ this.labelSelectionListener = labelSelectionListener;
+ }
+
+ @Override
+ protected void onCreate() {
+
+ // Inflate layout
+ inflater = (LayoutInflater) this.anchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ rootView = (ViewGroup) inflater.inflate(R.layout.part_quickaction, null);
+
+ // Setup button events
+ ((ImageButton)rootView.findViewById(R.id.showall)).setOnClickListener(getOnMainViewTypeClickListener(MainViewType.ShowAll));
+ ((ImageButton)rootView.findViewById(R.id.showdl)).setOnClickListener(getOnMainViewTypeClickListener(MainViewType.OnlyDownloading));
+ ((ImageButton)rootView.findViewById(R.id.showup)).setOnClickListener(getOnMainViewTypeClickListener(MainViewType.OnlyUploading));
+ ((ImageButton)rootView.findViewById(R.id.showinactive)).setOnClickListener(getOnMainViewTypeClickListener(MainViewType.OnlyInactive));
+ labelsListView = (ListView) rootView.findViewById(R.id.labelsList);
+ labelsListView.setOnItemClickListener(onLabelClickListener);
+
+ // set the inflated view as what we want to display
+ this.setContentView(rootView);
+
+ }
+
+ @Override
+ public void showLikePopDownMenu() {
+
+ // Place arrow
+ int[] location = new int[2];
+ anchor.getLocationOnScreen(location);
+ Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1] + anchor.getHeight());
+ final ImageView arrow = (ImageView) rootView.findViewById(R.id.arrow_up);
+ ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)arrow.getLayoutParams();
+ final int arrowWidth = arrow.getMeasuredWidth();
+ param.leftMargin = anchorRect.centerX() - arrowWidth / 2;
+
+ super.showLikePopDownMenu();
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public void updateLabels(List availableLabels) {
+ // Update the labels list
+ if (labelsListView.getAdapter() == null) {
+ labelsListView.setAdapter(new ArrayAdapter(this.anchor.getContext(), availableLabels) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // Get the right view, using a ViewHolder
+ ViewHolder holder;
+ if (convertView == null) {
+ convertView = inflater.inflate(R.layout.list_item_label, null);
+ holder = new ViewHolder();
+ holder.text1 = (TextView) convertView.findViewById(android.R.id.text1);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ // Bind the data
+ holder.text1.setText(getItem(position));
+ return convertView;
+ }
+ });
+ } else {
+ ((ArrayAdapter)labelsListView.getAdapter()).replace(availableLabels);
+ }
+ labelsListView.setVisibility(availableLabels.size() > 0? View.VISIBLE: View.GONE);
+ labelsListView.setOnItemClickListener(onLabelClickListener);
+ }
+
+ protected static class ViewHolder {
+ TextView text1;
+ }
+
+ private OnClickListener getOnMainViewTypeClickListener(final MainViewType type) {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mainViewTypeSelectionListener.onMainViewTypeSelected(type);
+ TorrentViewSelectorWindow.this.dismiss();
+ }
+ };
+ }
+
+ private OnItemClickListener onLabelClickListener = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ labelSelectionListener.onLabelSelected(position);
+ TorrentViewSelectorWindow.this.dismiss();
+ }
+ };
+
+ public static abstract class MainViewTypeSelectionListener {
+ public abstract void onMainViewTypeSelected(MainViewType newType);
+ }
+
+ public static abstract class LabelSelectionListener {
+ public abstract void onLabelSelected(int labelPosition);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/Torrents.java b/android/src/org/transdroid/gui/Torrents.java
new file mode 100644
index 00000000..3a7a8a19
--- /dev/null
+++ b/android/src/org/transdroid/gui/Torrents.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import org.transdroid.R;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.ActionBar;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+/**
+ * Activity that loads the torrents fragment and, on tablet interfaces, hosts
+ * the details fragment.
+ *
+ * @author erickok
+ */
+public class Torrents extends FragmentActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_torrents);
+
+ ActionBar bar = getSupportActionBar();
+ bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+
+ if (savedInstanceState == null) {
+
+ // Start the fragment for this torrent
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ TorrentsFragment fragment = new TorrentsFragment();
+ ft.replace(R.id.torrents, fragment);
+ ft.commit();
+
+ }
+
+ }
+
+ @Override
+ protected void onNewIntent(Intent i) {
+ loadData(i);
+ }
+
+ private void loadData(Intent i) {
+ ((TorrentsFragment)getSupportFragmentManager().findFragmentById(R.id.torrents)).handleIntent(i);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/TorrentsFragment.java b/android/src/org/transdroid/gui/TorrentsFragment.java
new file mode 100644
index 00000000..7d4d9c95
--- /dev/null
+++ b/android/src/org/transdroid/gui/TorrentsFragment.java
@@ -0,0 +1,2113 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.transdroid.R;
+import org.transdroid.daemon.Daemon;
+import org.transdroid.daemon.DaemonMethod;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.daemon.IDaemonAdapter;
+import org.transdroid.daemon.IDaemonCallback;
+import org.transdroid.daemon.TaskQueue;
+import org.transdroid.daemon.Torrent;
+import org.transdroid.daemon.TorrentStatus;
+import org.transdroid.daemon.TorrentsComparator;
+import org.transdroid.daemon.TorrentsSortBy;
+import org.transdroid.daemon.task.AddByFileTask;
+import org.transdroid.daemon.task.AddByMagnetUrlTask;
+import org.transdroid.daemon.task.AddByUrlTask;
+import org.transdroid.daemon.task.DaemonTask;
+import org.transdroid.daemon.task.DaemonTaskFailureResult;
+import org.transdroid.daemon.task.DaemonTaskSuccessResult;
+import org.transdroid.daemon.task.PauseAllTask;
+import org.transdroid.daemon.task.PauseTask;
+import org.transdroid.daemon.task.RemoveTask;
+import org.transdroid.daemon.task.ResumeAllTask;
+import org.transdroid.daemon.task.ResumeTask;
+import org.transdroid.daemon.task.RetrieveTask;
+import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
+import org.transdroid.daemon.task.SetAlternativeModeTask;
+import org.transdroid.daemon.task.SetDownloadLocationTask;
+import org.transdroid.daemon.task.SetLabelTask;
+import org.transdroid.daemon.task.SetTransferRatesTask;
+import org.transdroid.daemon.task.StartAllTask;
+import org.transdroid.daemon.task.StartTask;
+import org.transdroid.daemon.task.StopAllTask;
+import org.transdroid.daemon.task.StopTask;
+import org.transdroid.daemon.util.DLog;
+import org.transdroid.daemon.util.FileSizeConverter;
+import org.transdroid.daemon.util.HttpHelper;
+import org.transdroid.gui.SetLabelDialog.ResultListener;
+import org.transdroid.gui.TorrentViewSelectorWindow.LabelSelectionListener;
+import org.transdroid.gui.TorrentViewSelectorWindow.MainViewTypeSelectionListener;
+import org.transdroid.gui.rss.RssFeeds;
+import org.transdroid.gui.search.Search;
+import org.transdroid.gui.util.ActivityUtil;
+import org.transdroid.gui.util.DialogWrapper;
+import org.transdroid.gui.util.ErrorLogSender;
+import org.transdroid.gui.util.InterfaceSettings;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.preferences.PreferencesMain;
+import org.transdroid.search.barcode.GoogleWebSearchBarcodeResolver;
+import org.transdroid.service.AlarmSettings;
+import org.transdroid.service.BootReceiver;
+import org.transdroid.util.TLog;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.SearchManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.support.v4.app.ActionBar.OnNavigationListener;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.Menu;
+import android.support.v4.view.MenuItem;
+import android.support.v4.view.SubMenu;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SpinnerAdapter;
+import android.widget.TableLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * The main screen for the Transdroid application and provides most on-the-surface functionality
+ * as well. Server daemon and search engine communication is wrapped in adapters.
+ *
+ * @author erickok
+ *
+ */
+public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTouchListener {
+
+ private static final String LOG_NAME = "Main";
+
+ private static final int ACTIVITY_PREFERENCES = 0;
+ private static final int ACTIVITY_DETAILS = 1;
+ private static final int ACTIVITY_BARCODE = 0x0ba7c0de; // get it?
+
+ private static final int DIALOG_SERVERS = 0;
+ private static final int DIALOG_RATES = 1;
+ private static final int DIALOG_CHANGELOG = 2;
+ private static final int DIALOG_ASKREMOVE = 3;
+ private static final int DIALOG_SETLABEL = 4;
+ private static final int DIALOG_ADDFAILED = 5;
+ private static final int DIALOG_SETDOWNLOADLOCATION = 6;
+ private static final int DIALOG_REFRESH_INTERVAL = 7;
+ private static final int DIALOG_INSTALLBARCODESCANNER = 8;
+
+ private static final int MENU_ADD_ID = 1;
+ private static final int MENU_BARCODE_ID = 2;
+ private static final int MENU_RSS_ID = 3;
+ private static final int MENU_FORALL_ID = 4;
+ private static final int MENU_SORT_ID = 5;
+
+ private static final int MENU_SETTINGS_ID = 6;
+ private static final int MENU_CHANGELOG_ID = 7;
+ private static final int MENU_SWITCH_ID = 8;
+ private static final int MENU_RATES_ID = 9;
+ private static final int MENU_ERRORREPORT_ID = 10;
+
+ private static final int MENU_REFRESH_ID = 11;
+ private static final int MENU_SEARCH_ID = 12;
+ private static final int MENU_ALTMODE_ID = 13;
+
+ private static final int MENU_FORALL_GROUP_ID = 20;
+ private static final int MENU_FORALL_PAUSE_ID = 21;
+ private static final int MENU_FORALL_RESUME_ID = 22;
+ private static final int MENU_FORALL_STOP_ID = 23;
+ private static final int MENU_FORALL_START_ID = 24;
+
+ private static final int MENU_SORT_GROUP_ID = 30;
+ private static final int MENU_SORT_ALPHA_ID = 31;
+ private static final int MENU_SORT_STATUS_ID = 32;
+ private static final int MENU_SORT_DONE_ID = 33;
+ private static final int MENU_SORT_ADDED_ID = 34;
+ private static final int MENU_SORT_UPSPEED_ID = 35;
+ private static final int MENU_SORT_RATIO_ID = 36;
+ private static final int MENU_SORT_GTZERO_ID = 37;
+
+ private static final int MENU_PAUSE_ID = 41;
+ private static final int MENU_RESUME_ID = 42;
+ private static final int MENU_STOP_ID = 43;
+ private static final int MENU_START_ID = 44;
+ private static final int MENU_FORCESTART_ID = 45;
+ private static final int MENU_REMOVE_ID = 46;
+ private static final int MENU_REMOVE_DATA_ID = 47;
+ private static final int MENU_SETLABEL_ID = 48;
+ private static final int MENU_SETDOWNLOADLOCATION_ID = 49;
+
+ protected boolean useTabletInterface;
+ private Handler handler;
+ private Runnable refreshRunable;
+ private GestureDetector gestureDetector;
+ private TextView emptyText;
+ private TableLayout statusBox;
+ private TextView taskmessage, statusDown, statusUp, statusDownRate, statusUpRate;
+ private LinearLayout startsettings;
+ private ImageView viewtypeselector;
+ private TextView viewtype;
+ private LinearLayout controlbar;
+ private TorrentViewSelectorWindow viewtypeselectorpopup;
+
+ // Variables determining which view over the torrents to show
+ private TorrentsSortBy sortSetting = TorrentsSortBy.Alphanumeric;
+ private boolean sortReversed = false;
+ private MainViewType activeMainView = MainViewType.ShowAll;
+ private boolean onlyShowTransferring = false;
+ private List availableLabels;
+ private String activeLabel = null;
+ private boolean inAlternativeMode = false; // Whether the server is in alternative (speed) mode (i.e. Transmission's Turtle Mode)
+ protected boolean ignoreFirstListNavigation = true;
+
+ private List allTorrents;
+
+ private TaskQueue queue;
+ private boolean inProgress = false;
+
+ // Settings-related variables
+ private IDaemonAdapter daemon;
+ private static List allDaemonSettings;
+ private static int lastUsedDaemonSettings;
+ private static InterfaceSettings interfaceSettings;
+ private static AlarmSettings alarmServiceSettings;
+
+ // Variables to store data to use inside the dialogs that we pop up
+ private Torrent selectedTorrent;
+ private boolean selectedRemoveData;
+ private String failedTorrentUri;
+ private String failedTorrentTitle;
+
+ public TorrentsFragment() {
+ setHasOptionsMenu(true);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ ignoreFirstListNavigation = true;
+ return inflater.inflate(R.layout.fragment_torrents, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ // Attach the Android TLog to the daemon logger
+ DLog.setLogger(TLog.getInstance());
+
+ // Set activity screen features
+ useTabletInterface = Transdroid.isTablet(getResources());
+ registerForContextMenu(getListView());
+ getListView().setTextFilterEnabled(true);
+ getListView().setOnItemClickListener(onTorrentClicked);
+
+ // Access UI widgets and title
+ emptyText = (TextView) findViewById(android.R.id.empty);
+ startsettings = (LinearLayout) findViewById(R.id.startsettings);
+ taskmessage = (TextView) findViewById(R.id.taskmessage);
+ statusBox = (TableLayout) findViewById(R.id.st_box);
+ statusDown = (TextView) findViewById(R.id.st_down);
+ statusDownRate = (TextView) findViewById(R.id.st_downrate);
+ statusUp = (TextView) findViewById(R.id.st_up);
+ statusUpRate = (TextView) findViewById(R.id.st_uprate);
+ setProgressBar(false);
+
+ // Open settings button
+ Button startsettingsButton = (Button) findViewById(R.id.startsettings_button);
+ startsettingsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Open settings screen
+ startActivityForResult(new Intent(getActivity(), PreferencesMain.class), ACTIVITY_PREFERENCES);
+ }
+ });
+ // Show a dialog allowing control over max. upload and download speeds
+ statusBox.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(DIALOG_RATES);
+ }
+ });
+
+ // The control bar and view type selector (quickaction popup)
+ controlbar = (LinearLayout) findViewById(R.id.controlbar);
+ viewtype = (TextView) findViewById(R.id.viewtype);
+ viewtypeselector = (ImageView) findViewById(R.id.viewtypeselector);
+ viewtypeselectorpopup = new TorrentViewSelectorWindow(viewtypeselector, new MainViewTypeSelectionListener() {
+ @Override
+ public void onMainViewTypeSelected(MainViewType newType) {
+ if (activeMainView != newType) {
+ // Show torrents for the new main view selection
+ activeMainView = newType;
+ updateTorrentsView(true);
+ }
+ }
+ }, new LabelSelectionListener() {
+ @Override
+ public void onLabelSelected(int labelPosition) {
+ String newLabel = availableLabels.get(labelPosition);
+ if (activeLabel != newLabel) {
+ // Show torrents for the new label selection
+ activeLabel = newLabel;
+ updateTorrentsView(true);
+ }
+ }
+ });
+ viewtypeselector.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ viewtypeselectorpopup.showLikePopDownMenu();
+ }
+ });
+
+ // Swiping (flinging) between server configurations (or labels)
+ gestureDetector = new GestureDetector(new MainScreenGestureListener());
+ getListView().setOnTouchListener(this);
+ emptyText.setOnTouchListener(this);
+
+ // Attach auto refresh handler
+ handler = new Handler();
+ refreshRunable = new Runnable() {
+ public void run() {
+ updateTorrentList();
+ setupRefreshTimer();
+ }
+ };
+
+ // Read all the user preferences
+ readSettings();
+
+ // Setup the default server daemon
+ setupDaemon();
+
+ // Set up a task queue
+ queue = new TaskQueue(new TaskResultHandler(this));
+ queue.start();
+
+ // Start the alarm service, if needed
+ BootReceiver.startAlarm(getActivity().getApplicationContext());
+
+ handleIntent(getActivity().getIntent());
+
+ }
+
+ public void handleIntent(final Intent startIntent) {
+
+ // Handle new intents that come from either a regular application startup, a startup from a
+ // new intent or a new intent being send with the application already started
+ if (startIntent != null && (startIntent.getData() != null ||
+ (startIntent.getAction() != null && startIntent.getAction().equals(Transdroid.INTENT_ADD_MULTIPLE))) &&
+ !isLaunchedFromHistory(startIntent)) {
+
+ if (startIntent.getAction() != null && startIntent.getAction().equals(Transdroid.INTENT_ADD_MULTIPLE)) {
+
+ // Intent should have some extras pointing to possibly multiple torrents
+ String[] urls = startIntent.getStringArrayExtra(Transdroid.INTENT_TORRENT_URLS);
+ String[] titles = startIntent.getStringArrayExtra(Transdroid.INTENT_TORRENT_TITLES);
+ if (urls != null) {
+ for (int i = 0; i < urls.length; i++) {
+ addTorrentByUrl(urls[i], (titles != null && titles.length >= i? titles[i]: "Torrent"));
+ }
+ }
+
+ } else {
+
+ // Intent should have some Uri data pointing to a single torrent
+ String data = startIntent.getDataString();
+ if (data != null && startIntent.getData() != null && startIntent.getData().getScheme() != null) {
+ if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_HTTP)) {
+ // From a global intent to add a .torrent file via URL (maybe form the browser)
+ String title = data.substring(data.lastIndexOf("/"));
+ if (startIntent.hasExtra(Transdroid.INTENT_TORRENT_TITLE)) {
+ title = startIntent.getStringExtra(Transdroid.INTENT_TORRENT_TITLE);
+ }
+ addTorrentByUrl(data, title);
+ } else if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_MAGNET)) {
+ // From a global intent to add a magnet link via URL (usually from the browser)
+ addTorrentByMagnetUrl(data);
+ } else if (startIntent.getData().getScheme().equals(HttpHelper.SCHEME_FILE)) {
+ // From a global intent to add via the contents of a local .torrent file (maybe form a file manager)
+ addTorrentByFile(data);
+ }
+ }
+
+ }
+
+ }
+
+ // Possibly switch to a specific daemon (other than the last used)
+ boolean forceUpdate = false;
+ if (startIntent != null && !isLaunchedFromHistory(startIntent) &&
+ startIntent.hasExtra(Transdroid.INTENT_OPENDAEMON)) {
+ String openDaemon = startIntent.getStringExtra(Transdroid.INTENT_OPENDAEMON);
+ if (!daemon.getSettings().getIdString().equals(openDaemon)) {
+ int openDaemonI = (openDaemon == null || openDaemon.equals("")? 0: Integer.parseInt(openDaemon));
+ if (openDaemonI >= allDaemonSettings.size()) {
+ openDaemonI = 0;
+ }
+ forceUpdate = true;
+ switchDaemonConfig(openDaemonI);
+ }
+
+ }
+
+ if (forceUpdate || allTorrents == null) {
+ // Not swithcing to another daemon and no known list of torrents: update
+ updateTorrentList();
+ } else {
+ // We retained the list of torrents form the fragment state: show again
+ updateStatusText(null);
+ updateTorrentsView(false);
+ }
+
+ }
+
+ private boolean isLaunchedFromHistory(final Intent startIntent) {
+ return (startIntent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0;
+ }
+
+ public void onResume() {
+ super.onResume();
+ queue.start();
+ setupRefreshTimer();
+ }
+
+ public void onPause() {
+ super.onPause();
+ queue.requestStop();
+ handler.removeCallbacks(refreshRunable);
+ }
+
+ /**
+ * Start a refresh timer, if the user enabled this in the settings
+ */
+ private void setupRefreshTimer() {
+ if (interfaceSettings != null && interfaceSettings.getRefreshTimerInterval() > 0) {
+ handler.postDelayed(refreshRunable, interfaceSettings.getRefreshTimerInterval() * 1000);
+ }
+ }
+
+ private void readSettings() {
+
+ TLog.d(LOG_NAME, "Reading settings");
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ allDaemonSettings = Preferences.readAllDaemonSettings(prefs);
+ lastUsedDaemonSettings = Preferences.readLastUsedDaemonOrderNumber(prefs, allDaemonSettings);
+ interfaceSettings = Preferences.readInterfaceSettings(prefs);
+ sortSetting = TorrentsSortBy.getStatus(prefs.getInt(Preferences.KEY_PREF_LASTSORTBY, TorrentsSortBy.Alphanumeric.getCode()));
+ sortReversed = prefs.getBoolean(Preferences.KEY_PREF_LASTSORTORD, false);
+ onlyShowTransferring = prefs.getBoolean(Preferences.KEY_PREF_LASTSORTGTZERO, false);
+ alarmServiceSettings = Preferences.readAlarmSettings(prefs);
+
+ // Update the navigation list of the action bar
+ ignoreFirstListNavigation = true;
+ getSupportActivity().getSupportActionBar().setListNavigationCallbacks(buildServerListAdapter(), onServerChanged );
+
+ }
+
+ private void setupDaemon() {
+
+ // If preferences are set, create the daemon adapter
+ if (allDaemonSettings != null && allDaemonSettings.size() > lastUsedDaemonSettings &&
+ allDaemonSettings.get(lastUsedDaemonSettings) != null && allDaemonSettings.get(lastUsedDaemonSettings).getType() != null) {
+
+ // Instantiate the daemon (the connection isn't made until an actual request is done)
+ DaemonSettings settings = allDaemonSettings.get(lastUsedDaemonSettings);
+ daemon = settings.getType().createAdapter(settings);
+ emptyText.setText(R.string.connecting);
+
+ // Show which server configuration is currently active
+ ignoreFirstListNavigation = true;
+ getSupportActivity().getSupportActionBar().setSelectedNavigationItem(lastUsedDaemonSettings);
+
+ // Show the control bar
+ startsettings.setVisibility(View.GONE);
+ controlbar.setVisibility(View.VISIBLE);
+ statusBox.setVisibility(View.GONE);
+ activeLabel = null;
+ inAlternativeMode = false; // TODO: Actually this should be retrieved from the server's session
+ getSupportActivity().invalidateOptionsMenu();
+
+ } else {
+
+ daemon = null;
+
+ // The 'set preferences first' screen is shown
+ emptyText.setText(R.string.no_settings);
+
+ // Show that no server configuration is currently active
+ ignoreFirstListNavigation = true;
+ getSupportActivity().getSupportActionBar().setListNavigationCallbacks(null, onServerChanged);
+ statusBox.setVisibility(View.GONE);
+ viewtype.setText("");
+
+ // Hide the control bar
+ startsettings.setVisibility(View.VISIBLE);
+ controlbar.setVisibility(View.GONE);
+ activeLabel = null;
+ getSupportActivity().invalidateOptionsMenu();
+
+ }
+
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ // Add the pause/resume/stop/start options
+ Torrent selected = (Torrent) getTorrentListAdapter().getItem((int) ((AdapterContextMenuInfo)menuInfo).id);
+ if (selected.canPause()) {
+ menu.add(0, MENU_PAUSE_ID, 0, R.string.menu_pause);
+ } else if (selected.canResume()) {
+ menu.add(0, MENU_RESUME_ID, 0, R.string.menu_resume);
+ }
+ if (daemon != null && Daemon.supportsStoppingStarting(daemon.getType())) {
+ if (selected.canStop()) {
+ menu.add(0, MENU_STOP_ID, 0, R.string.menu_stop);
+ } else if (selected.canStart()) {
+ menu.add(0, MENU_START_ID, 0, R.string.menu_start);
+ }
+ }
+ if (daemon != null && Daemon.supportsForcedStarting(daemon.getType()) && selected.canStart()) {
+ menu.add(0, MENU_FORCESTART_ID, 0, R.string.menu_forcestart);
+ }
+
+ // Add the remove options
+ menu.add(0, MENU_REMOVE_ID, 0, R.string.menu_remove);
+ if (daemon != null && Daemon.supportsRemoveWithData(daemon.getType())) {
+ menu.add(0, MENU_REMOVE_DATA_ID, 0, R.string.menu_remove_data);
+ }
+
+ // Add the 'set label' option
+ if (daemon != null && Daemon.supportsSetLabel(daemon.getType())) {
+ menu.add(0, MENU_SETLABEL_ID, 0, R.string.menu_setlabel);
+ }
+
+ // Add the 'set download location' option
+ if (daemon != null && Daemon.supportsSetDownloadLocation(daemon.getType())) {
+ menu.add(0, MENU_SETDOWNLOADLOCATION_ID, 0, R.string.menu_setdownloadlocation);
+ }
+
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+
+ // Add title bar buttons
+ MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
+ miRefresh.setIcon(R.drawable.icon_refresh_title);
+ miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ if (inProgress) {
+ // Show progress spinner instead of the option item
+ View view = getActivity().getLayoutInflater().inflate(R.layout.part_actionbar_progressitem, null);
+ miRefresh.setActionView(view);
+ }
+ MenuItem miSearch = menu.add(0, MENU_SEARCH_ID, 0, R.string.search);
+ miSearch.setIcon(R.drawable.icon_search_title);
+ miSearch.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ MenuItem miAltMode = menu.add(0, MENU_ALTMODE_ID, 0, R.string.menu_altmode);
+ miAltMode.setIcon(R.drawable.icon_turtle_title);
+ miAltMode.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ miAltMode.setVisible(daemon != null && Daemon.supportsSetAlternativeMode(daemon.getType()));
+
+ // Add the menu options row 1
+ MenuItem miAdd = menu.add(0, MENU_ADD_ID, 0, R.string.menu_add);
+ if (useTabletInterface) {
+ miAdd.setIcon(R.drawable.icon_add);
+ } else {
+ miAdd.setIcon(android.R.drawable.ic_menu_add);
+ }
+ miAdd.setShortcut('1', 'a');
+ miAdd.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ MenuItem miBarcode = menu.add(0, MENU_BARCODE_ID, 0, R.string.menu_scanbarcode);
+ miBarcode.setIcon(R.drawable.icon_barcode);
+ miBarcode.setShortcut('2', 'f');
+ miBarcode.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ MenuItem miRss = menu.add(0, MENU_RSS_ID, 0, R.string.menu_rss);
+ miRss.setIcon(R.drawable.icon_rss);
+ miRss.setShortcut('3', 'r');
+ miRss.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+
+ // Add the menu options row 2
+ SubMenu miForAll = menu.addSubMenu(MENU_FORALL_GROUP_ID, MENU_FORALL_ID, 0, R.string.menu_forall);
+ miForAll.setIcon(android.R.drawable.ic_menu_set_as);
+ miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_PAUSE_ID, 0, R.string.menu_forall_pause).setShortcut('4', 'p');
+ miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_RESUME_ID, 0, R.string.menu_forall_resume).setShortcut('5', 'u');
+ miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_STOP_ID, 0, R.string.menu_forall_stop).setShortcut('7', 't');
+ miForAll.add(MENU_FORALL_GROUP_ID, MENU_FORALL_START_ID, 0, R.string.menu_forall_start).setShortcut('8', 's');
+ SubMenu miSort = menu.addSubMenu(MENU_SORT_GROUP_ID, MENU_SORT_ID, 0, R.string.menu_filter);
+ miSort.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
+ //miSort.setHeaderTitle(R.string.menu_sort_reverse);
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_ALPHA_ID, 0, R.string.menu_sort_alpha).setAlphabeticShortcut('1').setChecked(true);
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_STATUS_ID, 0, R.string.menu_sort_status).setAlphabeticShortcut('2');
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_ADDED_ID, 0, R.string.menu_sort_added).setAlphabeticShortcut('3');
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_DONE_ID, 0, R.string.menu_sort_done).setAlphabeticShortcut('4');
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_UPSPEED_ID, 0, R.string.menu_sort_upspeed).setAlphabeticShortcut('5');
+ miSort.add(MENU_SORT_GROUP_ID, MENU_SORT_RATIO_ID, 0, R.string.menu_sort_ratio).setAlphabeticShortcut('6');
+ miSort.setGroupCheckable(MENU_SORT_GROUP_ID, true, true);
+ miSort.add(MENU_SORT_GTZERO_ID, MENU_SORT_GTZERO_ID, 0, R.string.menu_sort_onlytransferring).setCheckable(true);
+
+ // Add the extras menu options
+ MenuItem miSpeeds = menu.add(0, MENU_RATES_ID, 0, R.string.menu_speeds);
+ miSpeeds.setNumericShortcut('6');
+ miSpeeds.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ MenuItem miSwitch = menu.add(0, MENU_SWITCH_ID, 0, R.string.menu_servers);
+ miSwitch.setShortcut('9', 'h');
+ miSwitch.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ menu.add(0, MENU_ERRORREPORT_ID, 0, R.string.menu_errorreport);
+ menu.add(0, MENU_CHANGELOG_ID, 0, R.string.menu_changelog);
+ MenuItem miSettings = menu.add(0, MENU_SETTINGS_ID, 0, R.string.menu_settings);
+ //miSettings.setIcon(android.R.drawable.ic_menu_preferences);
+ miSettings.setNumericShortcut('0');
+ miSettings.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ boolean ok = daemon != null;
+ menu.findItem(MENU_ADD_ID).setEnabled(ok);
+ menu.findItem(MENU_BARCODE_ID).setEnabled(ok);
+ menu.findItem(MENU_RSS_ID).setEnabled(ok);
+ menu.findItem(MENU_FORALL_ID).setEnabled(ok);
+ menu.findItem(MENU_SORT_ID).setEnabled(ok);
+ if (ok) {
+ menu.findItem(MENU_ALTMODE_ID).setVisible(Daemon.supportsSetAlternativeMode(daemon.getType()));
+ /*menu.findItem(MENU_SORT_ADDED_ID).setVisible(Daemon.supportsDateAdded(daemon.getType()));
+ menu.findItem(MENU_FORALL_STOP_ID).setVisible(Daemon.supportsStoppingStarting(daemon.getType()));
+ menu.findItem(MENU_FORALL_START_ID).setVisible(Daemon.supportsStoppingStarting(daemon.getType()));
+
+ // Show the currently selected sort by option
+ SubMenu sortmenu = menu.findItem(MENU_SORT_ID).getSubMenu();
+ for (int i = 0; i < sortmenu.size(); i++) {
+ if (sortmenu.getItem(i).getItemId() == MENU_SORT_ALPHA_ID && sortSetting == TorrentsSortBy.Alphanumeric) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_STATUS_ID && sortSetting == TorrentsSortBy.Status) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_ADDED_ID && sortSetting == TorrentsSortBy.DateAdded) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_DONE_ID && sortSetting == TorrentsSortBy.DateDone) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_UPSPEED_ID && sortSetting == TorrentsSortBy.UploadSpeed) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ } else if (sortmenu.getItem(i).getItemId() == MENU_SORT_RATIO_ID && sortSetting == TorrentsSortBy.Ratio) {
+ sortmenu.getItem(i).setChecked(true);
+ break;
+ }
+ }
+
+ // Show the checkbox status according to the current settings
+ menu.findItem(MENU_SORT_GTZERO_ID).setChecked(onlyShowTransferring);*/
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return true;
+ }
+
+ // Get torrent item
+ Torrent selection = (Torrent) getTorrentListAdapter().getItem((int)info.id);
+
+ switch (item.getItemId()) {
+ case MENU_PAUSE_ID:
+
+ // Set an intermediate status first (for a response feel)
+ selection.mimicPause();
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(PauseTask.create(daemon, selection));
+ return true;
+
+ case MENU_RESUME_ID:
+
+ // Set an intermediate status first (for a response feel)
+ selection.mimicResume();
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(ResumeTask.create(daemon, selection));
+ queue.enqueue(RetrieveTask.create(daemon));
+ return true;
+
+ case MENU_STOP_ID:
+
+ // Set an intermediate status first (for a response feel)
+ selection.mimicStop();
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(StopTask.create(daemon, selection));
+ return true;
+
+ case MENU_START_ID:
+
+ // Set an intermediate status first (for a response feel)
+ selection.mimicStart();
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(StartTask.create(daemon, selection, false));
+ queue.enqueue(RetrieveTask.create(daemon));
+ return true;
+
+ case MENU_FORCESTART_ID:
+
+ // Set an intermediate status first (for a response feel)
+ selection.mimicStart();
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(StartTask.create(daemon, selection, true));
+ queue.enqueue(RetrieveTask.create(daemon));
+ return true;
+
+ case MENU_REMOVE_ID:
+
+ if (interfaceSettings.getAskBeforeRemove()) {
+ // We store the torrent that we selected so the dialog can use this to make its calls
+ selectedTorrent = selection;
+ selectedRemoveData = false;
+ showDialog(DIALOG_ASKREMOVE);
+ } else {
+ removeTorrentOnServer(selection, false);
+ }
+ return true;
+
+ case MENU_REMOVE_DATA_ID:
+
+ if (interfaceSettings.getAskBeforeRemove()) {
+ // We store the torrent that we selected so the dialog can use this to make its calls
+ selectedTorrent = selection;
+ selectedRemoveData = true;
+ showDialog(DIALOG_ASKREMOVE);
+ } else {
+ removeTorrentOnServer(selection, true);
+ }
+ return true;
+
+ case MENU_SETLABEL_ID:
+
+ // Store the torrent that we selected and open the set label dialog
+ selectedTorrent = selection;
+ showDialog(DIALOG_SETLABEL);
+ return true;
+
+ case MENU_SETDOWNLOADLOCATION_ID:
+
+ // Store the torrent that we selected and open the set download location dialog
+ selectedTorrent = selection;
+ showDialog(DIALOG_SETDOWNLOADLOCATION);
+ return true;
+
+ }
+ return super.onContextItemSelected(item);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) {
+
+ // Check connection first (when not opening the settings)
+ if (item.getItemId() != MENU_SETTINGS_ID &&
+ item.getItemId() != MENU_CHANGELOG_ID && daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return true;
+ }
+
+ switch (item.getItemId()) {
+ /*case android.R.id.home:
+
+ // Home button click in the action bar
+ Intent i = new Intent(getActivity(), Torrents.class);
+ i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(i);
+ break;*/
+
+ case MENU_REFRESH_ID:
+
+ refreshActivity();
+ break;
+
+ case MENU_SEARCH_ID:
+ getSupportActivity().onSearchRequested();
+ break;
+
+ case MENU_ALTMODE_ID:
+
+ switchAlternativeMode();
+ break;
+
+ case MENU_FORALL_PAUSE_ID:
+
+ if (allTorrents != null && allTorrents.size() > 0) {
+
+ // Set an intermediate status first on all items (for a response feel)
+ for (Torrent torrent : allTorrents) {
+ torrent.mimicPause();
+ }
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(PauseAllTask.create(daemon));
+
+ }
+ break;
+
+ case MENU_FORALL_RESUME_ID:
+
+ if (allTorrents != null && allTorrents.size() > 0) {
+
+ // Set an intermediate status first on all items (for a response feel)
+ for (Torrent torrent : allTorrents) {
+ torrent.mimicResume();
+ }
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(ResumeAllTask.create(daemon));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+ break;
+
+ case MENU_FORALL_STOP_ID:
+
+ if (allTorrents != null && allTorrents.size() > 0 && Daemon.supportsStoppingStarting(daemon.getType())) {
+
+ // Set an intermediate status first on all items (for a response feel)
+ for (Torrent torrent : allTorrents) {
+ torrent.mimicStop();
+ }
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(StopAllTask.create(daemon));
+
+ }
+ break;
+
+ case MENU_FORALL_START_ID:
+
+ if (allTorrents != null && allTorrents.size() > 0 && Daemon.supportsStoppingStarting(daemon.getType())) {
+
+ // Set an intermediate status first on all items (for a response feel)
+ for (Torrent torrent : allTorrents) {
+ torrent.mimicStart();
+ }
+ // Update adapter
+ getTorrentListAdapter().notifyDataSetChanged();
+
+ queue.enqueue(StartAllTask.create(daemon, false));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+ break;
+
+ case MENU_ADD_ID:
+
+ // Show a torrent URL input screen;
+ startActivity(new Intent(getActivity(), Add.class));
+ break;
+
+ case MENU_BARCODE_ID:
+
+ startBarcodeScanner();
+ break;
+
+ case MENU_RSS_ID:
+
+ // Show the RSS feeds screen
+ startActivity(new Intent(getActivity(), RssFeeds.class));
+ break;
+
+ case MENU_SWITCH_ID:
+
+ // Present a dialog with all available servers
+ showDialog(DIALOG_SERVERS);
+ break;
+
+ case MENU_SETTINGS_ID:
+
+ // Open settings menu
+ startActivityForResult(new Intent(getActivity(), PreferencesMain.class), ACTIVITY_PREFERENCES);
+ break;
+
+ case MENU_RATES_ID:
+
+ // Present a dialog that allows the setting of maxium transfer rates
+ showDialog(DIALOG_RATES);
+ break;
+
+ case MENU_CHANGELOG_ID:
+
+ // Present a dialog that shows version information and recent changes
+ showDialog(DIALOG_CHANGELOG);
+ break;
+
+ case MENU_ERRORREPORT_ID:
+
+ ErrorLogSender.collectAndSendLog(getActivity(), daemon, allDaemonSettings.get(lastUsedDaemonSettings));
+ break;
+
+ case MENU_SORT_ALPHA_ID:
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.Alphanumeric);
+ break;
+
+ case MENU_SORT_STATUS_ID:
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.Status);
+ break;
+
+ case MENU_SORT_DONE_ID:
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.DateDone);
+ break;
+
+ case MENU_SORT_UPSPEED_ID:
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.UploadSpeed);
+ break;
+
+ case MENU_SORT_RATIO_ID:
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.Ratio);
+ break;
+
+ case MENU_SORT_ADDED_ID:
+
+ if (Daemon.supportsDateAdded(daemon.getType())) {
+
+ // Resort
+ item.setChecked(true);
+ newTorrentListSorting(TorrentsSortBy.DateAdded);
+
+ }
+ break;
+
+ case MENU_SORT_GTZERO_ID:
+
+ // Set boolean to filter on only transferring (> 0 KB/s) torrents
+ item.setChecked(!item.isChecked());
+ onlyShowTransferring = item.isChecked();
+
+ updateTorrentsView(true);
+
+ break;
+
+ }
+ return true;
+ }
+
+ private OnItemClickListener onTorrentClicked = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View v, int position, long id) {
+ if (getTorrentListAdapter() != null) {
+
+ Torrent tor = getTorrentListAdapter().getItem(position);
+
+ // Show the details in the right of the screen (tablet interface) or separately
+ if (useTabletInterface) {
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.details, new DetailsFragment(lastUsedDaemonSettings, tor, buildLabelTexts(false)));
+ ft.commit();
+ } else {
+ Intent i = new Intent(getActivity(), Details.class);
+ i.putExtra(Details.STATE_DAEMON, lastUsedDaemonSettings);
+ i.putExtra(Details.STATE_LABELS, buildLabelTexts(false));
+ i.putExtra(Details.STATE_TORRENT, tor);
+ startActivityForResult(i, ACTIVITY_DETAILS);
+ }
+
+ }
+ }
+ };
+
+ private void startBarcodeScanner() {
+
+ // Test to see if the ZXing barcode scanner is available that can handle the SCAN intent
+ Intent scan = new Intent(Transdroid.SCAN_INTENT);
+ scan.addCategory(Intent.CATEGORY_DEFAULT);
+ if (ActivityUtil.isIntentAvailable(getActivity(), scan)) {
+ // Ask the barcode scanner to allow the user to scan some code
+ startActivityForResult(scan, ACTIVITY_BARCODE);
+ } else {
+ // Show a message if the user should install the barcode scanner for this feature
+ showDialog(DIALOG_INSTALLBARCODESCANNER);
+ }
+
+ }
+
+ protected Dialog onCreateDialog(int id) {
+
+ switch (id) {
+ case DIALOG_SERVERS:
+
+ // Build a dialog with a radio box per daemon configuration
+ AlertDialog.Builder serverDialog = new AlertDialog.Builder(getActivity());
+ serverDialog.setTitle(R.string.menu_servers);
+ serverDialog.setSingleChoiceItems(
+ buildServerTextsForDialog(), // The strings of the available server configurations
+ (lastUsedDaemonSettings < allDaemonSettings.size()? lastUsedDaemonSettings: 0), // The current selection except when this suddenly doesn't exist any more
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ // When the server is clicked (and it is different from the current active configuration),
+ // reload the daemon and update the torrent list
+ public void onClick(DialogInterface dialog, int which) {
+ if (which != lastUsedDaemonSettings) {
+ switchDaemonConfig(which);
+ }
+ dismissDialog(DIALOG_SERVERS);
+ }
+ });
+ return serverDialog.create();
+
+ case DIALOG_REFRESH_INTERVAL:
+
+ // Build a dialog with a radio boxes of different refresh intervals to choose from
+ AlertDialog.Builder refintDialog = new AlertDialog.Builder(getActivity());
+ refintDialog.setTitle(R.string.pref_uirefresh);
+ refintDialog.setSingleChoiceItems(
+ R.array.pref_uirefresh_types,
+ getCurrentRefreshIntervalID(),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Store new refresh interval
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ Preferences.storeNewRefreshInterval(prefs,
+ getResources().getStringArray(R.array.pref_uirefresh_values)[which]);
+ interfaceSettings = Preferences.readInterfaceSettings(prefs);
+ // Apply new refresh interval
+ handler.removeCallbacks(refreshRunable); // Stops refresh timer
+ setupRefreshTimer();
+ dismissDialog(DIALOG_REFRESH_INTERVAL);
+ }
+ });
+ return refintDialog.create();
+
+ case DIALOG_SETLABEL:
+
+ // Build a dialog that asks for a new or selected an existing label to assign to the selected torrent
+ String[] setLabelTexts = buildLabelTexts(false);
+ SetLabelDialog setLabelDialog = new SetLabelDialog(getActivity(), new ResultListener() {
+ @Override
+ public void onLabelResult(String newLabel) {
+ if (newLabel.equals(getString(R.string.labels_unlabeled).toString())) {
+ // Setting a torrent to 'unlabeled' is actually setting the label to an empty string
+ newLabel = "";
+ }
+ setNewLabel(newLabel);
+ }
+ }, setLabelTexts, selectedTorrent.getLabelName());
+ setLabelDialog.setTitle(R.string.labels_newlabel);
+
+ return setLabelDialog;
+
+ case DIALOG_SETDOWNLOADLOCATION:
+
+ // Build a dialog that asks for a new download location for the torrent
+ final View setLocationLayout = getActivity().getLayoutInflater().inflate(R.layout.dialog_set_download_location, null);
+ final EditText newLocation = (EditText) setLocationLayout.findViewById(R.id.download_location);
+ AlertDialog.Builder setLocationDialog = new AlertDialog.Builder(getActivity());
+ setLocationDialog.setTitle(R.string.menu_setdownloadlocation);
+ setLocationDialog.setView(setLocationLayout);
+ setLocationDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+
+ setDownloadLocation(newLocation.getText().toString());
+ }
+ });
+ setLocationDialog.setNegativeButton(android.R.string.cancel, null);
+ return setLocationDialog.create();
+
+ case DIALOG_RATES:
+
+ // Build a dialog that allows for the input of maximum upload and download transfer rates
+ final View ratesDialogView = getActivity().getLayoutInflater().inflate(R.layout.dialog_transfer_rates, null);
+ final EditText rateDownload = (EditText) ratesDialogView.findViewById(R.id.rate_download);
+ final EditText rateUpload = (EditText) ratesDialogView.findViewById(R.id.rate_upload);
+ AlertDialog.Builder ratesDialog = new AlertDialog.Builder(getActivity());
+ ratesDialog.setTitle(R.string.menu_speeds);
+ ratesDialog.setView(ratesDialogView);
+ ratesDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ setTransferRates(
+ (rateUpload.getText().toString().equals("")? null: Integer.parseInt(rateUpload.getText().toString())),
+ (rateDownload.getText().toString().equals("")? null: Integer.parseInt(rateDownload.getText().toString())));
+ }
+ });
+ ratesDialog.setNeutralButton(R.string.rate_reset, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Reset the text boxes first
+ rateUpload.setText("");
+ rateDownload.setText("");
+ setTransferRates(null, null);
+ }
+ });
+ ratesDialog.setNegativeButton(android.R.string.cancel, null);
+
+ return ratesDialog.create();
+
+ case DIALOG_CHANGELOG:
+
+ // Build a dialog listing the recent changes in Transdroid
+ AlertDialog.Builder changesDialog = new AlertDialog.Builder(getActivity());
+ changesDialog.setTitle(R.string.menu_changelog);
+ View changes = getActivity().getLayoutInflater().inflate(R.layout.dialog_about, null);
+ ((TextView)changes.findViewById(R.id.transdroid)).setText("Transdroid " + ActivityUtil.getVersionNumber(getActivity()));
+ changesDialog.setView(changes);
+ return changesDialog.create();
+
+ case DIALOG_ASKREMOVE:
+
+ // Build a dialog that asks to confirm the deletions of a torrent
+ AlertDialog.Builder askRemoveDialog = new AlertDialog.Builder(getActivity());
+ askRemoveDialog.setTitle(R.string.askremove_title);
+ askRemoveDialog.setMessage(R.string.askremove);
+ askRemoveDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ removeTorrentOnServer(selectedTorrent, selectedRemoveData);
+ dismissDialog(DIALOG_ASKREMOVE);
+ }
+ });
+ askRemoveDialog.setNegativeButton(android.R.string.no, null);
+ return askRemoveDialog.create();
+
+ case DIALOG_ADDFAILED:
+
+ // Build a dialog that asks to retry or store this torrent and add it later
+ AlertDialog.Builder addFailedDialog = new AlertDialog.Builder(getActivity());
+ addFailedDialog.setTitle(R.string.addfailed_title);
+ if (alarmServiceSettings.isAlarmEnabled()) {
+ addFailedDialog.setMessage(getString(R.string.addfailed_service2, failedTorrentTitle));
+ addFailedDialog.setNeutralButton(R.string.addfailed_addlater, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ Preferences.addToTorrentAddQueue(PreferenceManager.getDefaultSharedPreferences(getActivity()),
+ daemon.getSettings().getIdString(), failedTorrentUri);
+ dismissDialog(DIALOG_ADDFAILED);
+ }
+ });
+ } else {
+ addFailedDialog.setMessage(getString(R.string.addfailed_noservice2, failedTorrentTitle));
+ }
+ addFailedDialog.setPositiveButton(R.string.addfailed_retry, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ if (Preferences.isQueuedTorrentToAddALocalFile(failedTorrentUri)) {
+ addTorrentByFile(failedTorrentUri);
+ } else if (Preferences.isQueuedTorrentToAddAMagnetUrl(failedTorrentUri)) {
+ addTorrentByMagnetUrl(failedTorrentUri);
+ } else {
+ addTorrentByUrl(failedTorrentUri, failedTorrentTitle);
+ }
+ dismissDialog(DIALOG_ADDFAILED);
+ }
+ });
+ addFailedDialog.setNegativeButton(android.R.string.no, null);
+ return addFailedDialog.create();
+
+ case DIALOG_INSTALLBARCODESCANNER:
+ return ActivityUtil.buildInstallDialog(getActivity(), R.string.scanner_not_found, Transdroid.SCANNER_MARKET_URI);
+
+ }
+ return null;
+
+ }
+
+ /*@Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ super.onPrepareDialog(id, dialog);
+
+ switch (id) {
+ case DIALOG_SERVERS:
+
+ // Re-populate the dialog adapter with possibly new/edited server configurations
+ AlertDialog serverDialog = (AlertDialog) dialog;
+ ListView serverRadios = serverDialog.getListView();
+ ArrayAdapter serverList = new ArrayAdapter(this, android.R.layout.select_dialog_singlechoice, android.R.id.text1, buildServerTextsForDialog());
+ serverRadios.setAdapter(serverList);
+
+ // Also pre-select the active daemon
+ int serverSelected = (lastUsedDaemonSettings < allDaemonSettings.size()? lastUsedDaemonSettings: 0); // Prevent going out of bounds
+ serverRadios.clearChoices();
+ serverRadios.setItemChecked(serverSelected, true);
+ serverRadios.setSelection(serverSelected);
+ break;
+
+ case DIALOG_REFRESH_INTERVAL:
+
+ // Pre-select the current refresh interval
+ AlertDialog refintDialog = (AlertDialog) dialog;
+ ListView refintRadios = refintDialog.getListView();
+ refintRadios.clearChoices();
+ refintRadios.setItemChecked(getCurrentRefreshIntervalID(), true);
+ refintRadios.setSelection(getCurrentRefreshIntervalID());
+ break;
+
+ case DIALOG_SETLABEL:
+
+ // Re-populate the dialog adapter with the available labels
+ SetLabelDialog setLabelDialog = (SetLabelDialog) dialog;
+ String[] setLabelTexts = buildLabelTexts(false);
+ setLabelDialog.resetDialog(this, setLabelTexts, selectedTorrent.getLabelName());
+ break;
+
+ case DIALOG_SETDOWNLOADLOCATION:
+
+ // Show the existing download location
+ final EditText newLocation = (EditText) dialog.findViewById(R.id.download_location);
+ newLocation.setText(selectedTorrent.getLocationDir());
+ break;
+
+ case DIALOG_ADDFAILED:
+
+ AlertDialog addFailedDialog = (AlertDialog) dialog;
+ if (alarmServiceSettings.isAlarmEnabled()) {
+ addFailedDialog.setMessage(getString(R.string.addfailed_service2, failedTorrentTitle));
+ addFailedDialog.setButton2(getText(R.string.addfailed_addlater), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface arg0, int arg1) {
+ Preferences.addToTorrentAddQueue(PreferenceManager.getDefaultSharedPreferences(TorrentsFragment.this),
+ daemon.getSettings().getIdString(), failedTorrentUri);
+ removeDialog(DIALOG_ADDFAILED);
+ }
+ });
+ } else {
+ addFailedDialog.setMessage(getString(R.string.addfailed_noservice2, failedTorrentTitle));
+ addFailedDialog.setButton2(null, (DialogInterface.OnClickListener)null);
+ }
+ break;
+ }
+ }*/
+
+ private SpinnerAdapter buildServerListAdapter() {
+ ArrayAdapter ad = new ArrayAdapter(getActivity(), R.layout.abs__simple_spinner_item, buildServerTextsForDialog());
+ ad.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ return ad;
+ }
+
+ private String[] buildServerTextsForDialog() {
+
+ // Build a textual list of servers available
+ ArrayList servers = new ArrayList();
+ for (DaemonSettings daemon : allDaemonSettings) {
+ servers.add(daemon.getName());
+ }
+ return servers.toArray(new String[servers.size()]);
+
+ }
+
+ private int getCurrentRefreshIntervalID() {
+ String[] values = getResources().getStringArray(R.array.pref_uirefresh_values);
+ int current = interfaceSettings.getRefreshTimerInterval();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].equals(Integer.toString(current))) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ private String[] buildLabelTexts(boolean addShowAll) {
+
+ // Build a textual list of used torrent labels
+ ArrayList labelNames = new ArrayList();
+ if (availableLabels != null) {
+ // The 'show all' label first ...
+ String showAll = getText(R.string.labels_showall).toString();
+ if (addShowAll) {
+ labelNames.add(showAll);
+ }
+ // ... then all the normal labels (which will end up in alphabetical order)
+ for (String name : availableLabels) {
+ if (!name.equals(showAll)) {
+ labelNames.add(name);
+ }
+ }
+ }
+ return labelNames.toArray(new String[labelNames.size()]);
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case ACTIVITY_PREFERENCES:
+
+ // Preference screen was called: use new preferences to connect
+ readSettings();
+ setupDaemon();
+ updateTorrentList();
+ break;
+
+ case ACTIVITY_DETAILS:
+
+ // Details screen was shown; we may have an updated torrent (it can be started/removed/etc.)
+ updateTorrentList();
+ break;
+
+ case ACTIVITY_BARCODE:
+
+ if (resultCode == Activity.RESULT_OK) {
+
+ // Get scan results code
+ String contents = data.getStringExtra("SCAN_RESULT");
+ String formatName = data.getStringExtra("SCAN_RESULT_FORMAT");
+
+ if (formatName != null && formatName.equals(Transdroid.SCAN_FORMAT_QRCODE)) {
+ // Scanned barcode was a QR code: assume the contents contain a URL to a .torrent file
+ TLog.d(LOG_NAME, "Add torrent from QR code url '" + contents + "'");
+ addTorrentByUrl(contents, "Torrent QR code"); // No real torrent title known
+ } else {
+ // Get a meaningful search query based on a Google Search product lookup
+ TLog.d(LOG_NAME, "Starting barcode lookup for code '" + contents + "' " + (formatName == null? "(code type is unknown)": "(this should be a " + formatName + " code)"));
+ setProgressBar(true);
+ new GoogleWebSearchBarcodeResolver() {
+ @Override
+ protected void onBarcodeLookupComplete(String result) {
+
+ setProgressBar(false);
+
+ // No proper result?
+ if (result == null || result.equals("")) {
+ TLog.d(LOG_NAME, "Barcode not resolved (timout, connection error, no items, etc.)");
+ Toast.makeText(getActivity(), R.string.no_results, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Open TransdroidSearch directly, mimicking a search query
+ TLog.d(LOG_NAME, "Barcode resolved to '" + result + "'. Now starting search.");
+ Intent search = new Intent(getActivity(), Search.class);
+ search.setAction(Intent.ACTION_SEARCH);
+ search.putExtra(SearchManager.QUERY, result);
+ startActivity(search);
+
+ }
+ }.execute(contents);
+ }
+
+ }
+ break;
+ }
+ }
+
+ private void refreshActivity() {
+ updateTorrentList();
+ if (getSupportFragmentManager().findFragmentById(R.id.details) != null) {
+ // Marshal the refresh button click to the fragment
+ ((DetailsFragment)getSupportFragmentManager().findFragmentById(R.id.details)).refreshActivity();
+ }
+ }
+
+ private void updateTorrentList() {
+ if (daemon != null) {
+ queue.enqueue(RetrieveTask.create(daemon));
+ }
+ }
+
+ private void addTorrentByUrl(String url, String title) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ queue.enqueue(AddByUrlTask.create(daemon, url, title));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+
+ private void addTorrentByMagnetUrl(String url) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsAddByMagnetUrl(daemon.getType())) {
+ // Not supported by the torrent client
+ Toast.makeText(getActivity(), R.string.no_magnet_links, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ queue.enqueue(AddByMagnetUrlTask.create(daemon, url));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+
+ private void addTorrentByFile(String fileUri) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsAddByFile(daemon.getType())) {
+ // The daemon type does not support .torrent file uploads/metadata sending or this is not yet implemented
+ Toast.makeText(getActivity(), R.string.no_file_uploads, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ queue.enqueue(AddByFileTask.create(daemon, fileUri));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+
+ private void removeTorrentOnServer(Torrent torrent, boolean removeData) {
+
+ // Remove the list item first (for a responsive feel) from views and labels
+ getTorrentListAdapter().remove(torrent);
+ updateEmptyListDescription();
+
+ // Remove the torrent from the server
+ queue.enqueue(RemoveTask.create(daemon, torrent, removeData));
+
+ }
+
+ private void setTransferRates(Integer uploadRate, Integer downloadRate) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsSetTransferRates(daemon.getType())) {
+ // The daemon type does not support adjusting the maximum transfer rates
+ Toast.makeText(getActivity(), R.string.rate_no_support, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ queue.enqueue(SetTransferRatesTask.create(daemon, uploadRate, downloadRate));
+
+ }
+
+ private void setNewLabel(String newLabel) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsSetLabel(daemon.getType())) {
+ // The daemon type does not support setting the label of a torrent
+ Toast.makeText(getActivity(), R.string.labels_no_support, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // Mimic that we have already set the label (for a response feel)
+ selectedTorrent.mimicNewLabel(newLabel);
+
+ queue.enqueue(SetLabelTask.create(daemon, selectedTorrent, newLabel));
+ queue.enqueue(RetrieveTask.create(daemon));
+
+ }
+
+ private void setDownloadLocation(String newLocation) {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsSetDownloadLocation(daemon.getType())) {
+ return;
+ }
+
+ queue.enqueue(SetDownloadLocationTask.create(daemon, selectedTorrent, newLocation));
+
+ }
+
+ protected void switchAlternativeMode() {
+
+ if (daemon == null) {
+ // No connection possible yet: give message
+ Toast.makeText(getActivity(), R.string.no_settings_short, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ if (!Daemon.supportsSetAlternativeMode(daemon.getType())) {
+ return;
+ }
+
+ inAlternativeMode = !inAlternativeMode;
+ queue.enqueue(SetAlternativeModeTask.create(daemon, inAlternativeMode));
+
+ }
+
+ @Override
+ public void onQueuedTaskFinished(DaemonTask started) {
+
+ // Show the daemon status (speeds) again
+ updateStatusText(null);
+
+ }
+
+ @Override
+ public void onQueuedTaskStarted(DaemonTask started) {
+
+ // Started on a new task: turn on status indicator
+ setProgressBar(true);
+ // Show which task we are executing
+ updateStatusText(getStatusFromTask(started).toString());
+
+ }
+
+ @Override
+ public void onQueueEmpty() {
+
+ // No active task: turn off status indicator
+ setProgressBar(false);
+
+ }
+
+ private CharSequence getStatusFromTask(DaemonTask started) {
+ switch (started.getMethod()) {
+ case Retrieve:
+ return getText(R.string.task_refreshing);
+ case AddByUrl:
+ return getText(R.string.task_addbyurl);
+ case AddByMagnetUrl:
+ return getText(R.string.task_addbyurl);
+ case AddByFile:
+ return getText(R.string.task_addbyfile);
+ case Remove:
+ return getText(R.string.task_removing);
+ case Pause:
+ return getText(R.string.task_pausing);
+ case PauseAll:
+ return getText(R.string.task_pausingall);
+ case Resume:
+ return getText(R.string.task_resuming);
+ case ResumeAll:
+ return getText(R.string.task_resumingall);
+ case Stop:
+ return getText(R.string.task_stopping);
+ case StopAll:
+ return getText(R.string.task_stoppingall);
+ case Start:
+ return getText(R.string.task_starting);
+ case StartAll:
+ return getText(R.string.task_startingall);
+ case GetFileList:
+ return getText(R.string.task_getfiles);
+ case SetFilePriorities:
+ return getText(R.string.task_setfileprop);
+ case SetTransferRates:
+ return getText(R.string.task_settransrates);
+ case SetLabel:
+ return getText(R.string.task_setlabel);
+ case SetDownloadLocation:
+ return getText(R.string.task_setlocation);
+ case SetAlternativeMode:
+ return getText(R.string.task_setalternativemode);
+ }
+ return "";
+ }
+
+ @Override
+ public void onTaskFailure(DaemonTaskFailureResult result) {
+
+ if (result.getMethod() == DaemonMethod.Retrieve) {
+ // For retrieve tasks: Only bother if we still are still looking at the same daemon since the task was queued
+ if (result.getTask().getAdapterType() == daemon.getType()) {
+ // Show error message
+ Toast.makeText(getActivity(), LocalTorrent.getResourceForDaemonException(result.getException()), Toast.LENGTH_SHORT * 2).show();
+ }
+
+ } else if (result.getMethod() == DaemonMethod.AddByFile) {
+ // Failed adding a torrent? Ask to add this torrent later
+ failedTorrentUri = ((AddByFileTask)result.getTask()).getFile();
+ failedTorrentTitle = new File(failedTorrentUri).getName(); // Use filename as title
+ showDialog(DIALOG_ADDFAILED);
+
+ } else if (result.getMethod() == DaemonMethod.AddByUrl) {
+ // Failed adding a torrent? Ask to add this torrent later
+ failedTorrentUri = ((AddByUrlTask)result.getTask()).getUrl();
+ failedTorrentTitle = ((AddByUrlTask)result.getTask()).getTitle(); // Get title directly from task
+ showDialog(DIALOG_ADDFAILED);
+
+ } else if (result.getMethod() == DaemonMethod.AddByMagnetUrl) {
+ // Failed adding a torrent? Ask to add this torrent later
+ failedTorrentUri = ((AddByMagnetUrlTask)result.getTask()).getUrl();
+ failedTorrentTitle = "Torrent"; // No way to know the title here
+ showDialog(DIALOG_ADDFAILED);
+
+ } else {
+ // Show error message
+ Toast.makeText(getActivity(), LocalTorrent.getResourceForDaemonException(result.getException()), Toast.LENGTH_SHORT * 2).show();
+ }
+
+ }
+
+ @Override
+ public void onTaskSuccess(DaemonTaskSuccessResult result) {
+
+ switch (result.getMethod()) {
+ case AddByFile:
+ case AddByUrl:
+
+ // Show 'added' message
+ Toast.makeText(getActivity(), R.string.torrent_added, Toast.LENGTH_SHORT).show();
+ break;
+
+ case Retrieve:
+
+ // Only bother if we still are still looking at the same daemon since the task was queued
+ if (result.getTask().getAdapterType() == daemon.getType()) {
+
+ // Sort the new list of torrents
+ allTorrents = ((RetrieveTaskSuccessResult) result).getTorrents();
+ Collections.sort(allTorrents, new TorrentsComparator(daemon, sortSetting, sortReversed));
+
+ // Show refreshed totals for this daemon
+ updateStatusText(null);
+ updateTorrentsView(false);
+
+ // Show 'refreshed' message unless we enabled the hide refresh message setting
+ if (!interfaceSettings.shouldHideRefreshMessage()) {
+ Toast.makeText(getActivity(), R.string.list_refreshed, Toast.LENGTH_SHORT).show();
+ }
+
+ }
+ break;
+
+ case Remove:
+
+ // Show 'removed' message
+ boolean includingData = ((RemoveTask)result.getTask()).includingData();
+ Toast.makeText(getActivity(), "'" + result.getTargetTorrent().getName() + "' " + getText(includingData? R.string.torrent_removed_with_data: R.string.torrent_removed), Toast.LENGTH_SHORT).show();
+ break;
+
+ case Resume:
+
+ // Show 'resumed' message
+ Toast.makeText(getActivity(), "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_resumed), Toast.LENGTH_SHORT).show();
+ break;
+
+ case ResumeAll:
+
+ // Show 'resumed all' message
+ Toast.makeText(getActivity(), getText(R.string.torrent_resumed_all), Toast.LENGTH_SHORT).show();
+ break;
+
+ case Pause:
+
+ // Show 'paused' message
+ Toast.makeText(getActivity(), "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_paused), Toast.LENGTH_SHORT).show();
+ break;
+
+ case PauseAll:
+
+ // Show 'paused all' message
+ Toast.makeText(getActivity(), getText(R.string.torrent_paused_all), Toast.LENGTH_SHORT).show();
+ break;
+
+ case Start:
+
+ // Show 'started' message
+ Toast.makeText(getActivity(), "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_started), Toast.LENGTH_SHORT).show();
+ break;
+
+ case StartAll:
+
+ // Show 'started all' message
+ Toast.makeText(getActivity(), getText(R.string.torrent_started_all), Toast.LENGTH_SHORT).show();
+ break;
+
+ case Stop:
+
+ // Show 'stopped' message
+ Toast.makeText(getActivity(), "'" + result.getTargetTorrent().getName() + "' " + getText(R.string.torrent_stopped), Toast.LENGTH_SHORT).show();
+ break;
+
+ case StopAll:
+
+ // Show 'stopped all' message
+ Toast.makeText(getActivity(), getText(R.string.torrent_stopped_all), Toast.LENGTH_SHORT).show();
+ break;
+
+ case SetTransferRates:
+
+ // Show 'rates updated' message
+ Toast.makeText(getActivity(), R.string.rate_updated, Toast.LENGTH_SHORT).show();
+ break;
+
+ case SetDownloadLocation:
+ Toast.makeText(getActivity(), getString(R.string.torrent_locationset, ((SetDownloadLocationTask)result.getTask()).getNewLocation()), Toast.LENGTH_SHORT).show();
+ break;
+
+ }
+
+ }
+
+ /**
+ * Shows the proper text when the torrent list is empty
+ */
+ private void updateEmptyListDescription() {
+
+ // Show empty text when no torrents exist any more
+ if (getTorrentListAdapter() != null && getTorrentListAdapter().getAllItems().size() == 0) {
+ if (activeMainView == MainViewType.OnlyDownloading) {
+ emptyText.setText(R.string.no_downloading_torrents);
+ } else if (activeMainView == MainViewType.OnlyUploading) {
+ emptyText.setText(R.string.no_uploading_torrents);
+ } else if (activeMainView == MainViewType.OnlyInactive) {
+ emptyText.setText(R.string.no_inactive_torrents);
+ } else {
+ emptyText.setText(R.string.no_torrents);
+ }
+ }
+
+ }
+
+ private void updateStatusText(String taskmessageText) {
+
+ if (taskmessageText != null || allTorrents == null) {
+ taskmessage.setText(taskmessageText);
+ taskmessage.setVisibility(View.VISIBLE);
+ statusBox.setVisibility(View.GONE);
+ emptyText.setVisibility(View.VISIBLE);
+ getListView().setVisibility(View.GONE);
+ /*if (getSupportFragmentManager().findFragmentById(R.id.details) != null) {
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.remove(getSupportFragmentManager().findFragmentById(R.id.details));
+ ft.commit();
+ }*/
+ return;
+ }
+
+ // Keep totals
+ int downloading = 0;
+ int downloadingD = 0;
+ int downloadingU = 0;
+ int eta = -1;
+ int seeding = 0;
+ int seedingU = 0;
+ int other = 0;
+ for (Torrent tor : allTorrents) {
+ if (tor.getStatusCode() == TorrentStatus.Downloading && (!onlyShowTransferring || tor.getRateDownload() > 0)) {
+ downloading++;
+ downloadingD += tor.getRateDownload();
+ downloadingU += tor.getRateUpload();
+ eta = Math.max(eta, tor.getEta());
+ } else if (tor.getStatusCode() == TorrentStatus.Seeding && (!onlyShowTransferring || tor.getRateUpload() > 0)) {
+ seeding++;
+ seedingU += tor.getRateUpload();
+ } else {
+ other++;
+ }
+ }
+
+ // Set text views
+ taskmessage.setVisibility(View.GONE);
+ statusBox.setVisibility(View.VISIBLE);
+ statusDown.setText(downloading + "\u2193");
+ statusUp.setText(seeding + "\u2191");
+ statusDownRate.setText(FileSizeConverter.getSize(downloadingD) + getString(R.string.status_persecond));
+ statusUpRate.setText(FileSizeConverter.getSize(downloadingU + seedingU) + getString(R.string.status_persecond));
+ emptyText.setVisibility(View.GONE);
+ getListView().setVisibility(View.VISIBLE);
+
+ }
+
+ private void newTorrentListSorting(TorrentsSortBy newSortBy) {
+
+ this.sortReversed = (sortSetting == newSortBy? !sortReversed: false); // If the same is selected again, reverse the sort order
+ this.sortSetting = newSortBy;
+
+ if (!(getTorrentListAdapter() == null || getTorrentListAdapter().getCount() == 0)) {
+
+ // Sort the shown list of torrents using the new sortBy criteria
+ Collections.sort(allTorrents, new TorrentsComparator(daemon, sortSetting, sortReversed));
+ updateTorrentsView(true);
+
+ }
+
+ // Remember the new option by saving it to the user preferences (for a new Transdroid startup)
+ Editor editor = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit();
+ editor.putInt(Preferences.KEY_PREF_LASTSORTBY, sortSetting.getCode());
+ editor.putBoolean(Preferences.KEY_PREF_LASTSORTORD, sortReversed);
+ editor.putBoolean(Preferences.KEY_PREF_LASTSORTGTZERO, onlyShowTransferring);
+ editor.commit();
+
+ }
+
+ private OnNavigationListener onServerChanged = new OnNavigationListener() {
+ @Override
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+ if (!ignoreFirstListNavigation ) {
+ switchDaemonConfig((int) itemId);
+ }
+ ignoreFirstListNavigation = false;
+ return true;
+ }
+ };
+
+ /**
+ * Clear the screen and set up the new daemon (just as if we were clicking on a daemon in the pop-up menu)
+ * @param which To which daemon settings configuration to switch to (which must exist)
+ */
+ private void switchDaemonConfig(int which) {
+
+ if (getActivity() == null) {
+ return;
+ }
+
+ // Store this new 'last used server'
+ Preferences.storeLastUsedDaemonSettings(getActivity().getApplicationContext(), which);
+ lastUsedDaemonSettings = which;
+
+ // Clear any old 'refresh' tasks from the queue
+ queue.clear(DaemonMethod.Retrieve);
+
+ // Hide the old torrents list and show that we are connecting again
+ if (allTorrents != null) {
+ allTorrents.clear();
+ }
+ if (getTorrentListAdapter() != null) {
+ getTorrentListAdapter().clear();
+ }
+ emptyText.setText(R.string.connecting);
+
+ // Clear the old details fragment
+ if (useTabletInterface) {
+ Fragment f = getSupportFragmentManager().findFragmentById(R.id.details);
+ if (f != null) {
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.remove(f);
+ ft.commit();
+ }
+ }
+
+ // Reload server and update torrent list
+ setupDaemon();
+ updateTorrentList();
+
+ }
+
+ private void loadLabels() {
+
+ availableLabels = new ArrayList();
+
+ if (Daemon.supportsLabels(getActiveDaemonType())) {
+
+ // Add a label that includes all torrents called 'show all'
+ String showAll = getText(R.string.labels_showall).toString();
+ availableLabels.add(showAll);
+
+ // Gather the used labels from the torrents
+ for (Torrent tor : allTorrents) {
+
+ // Force a label name (use 'unlabeled' if none is provided)
+ String name = tor.getLabelName();
+ if (name == null || name.equals("")) {
+ name = getText(R.string.labels_unlabeled).toString();
+ }
+ tor.mimicNewLabel(name);
+
+ // Start a new label if this name wasn't encountered yet
+ if (!availableLabels.contains(name)) {
+ availableLabels.add(name);
+ }
+
+ }
+ Collections.sort(availableLabels);
+
+ }
+
+ viewtypeselectorpopup.updateLabels(availableLabels);
+
+ }
+
+ private void updateTorrentsView(boolean forceScrollToTop) {
+ if (daemon != null && allTorrents != null) {
+
+ // Load the labels
+ String useLabel = null;
+ String showAllLabelsText = getText(R.string.labels_showall).toString();
+ loadLabels();
+ if (Daemon.supportsLabels(getActiveDaemonType())) {
+ useLabel = showAllLabelsText;
+ if (activeLabel != null && availableLabels.contains(activeLabel)) {
+ useLabel = activeLabel;
+ }
+ }
+
+ // Build a list of torrents that should be shown
+ List showTorrents = new ArrayList();
+ for (Torrent torrent : allTorrents) {
+ if (matchesLabel(torrent, useLabel, showAllLabelsText) && matchesStatus(torrent, activeMainView)) {
+ showTorrents.add(torrent);
+ }
+ }
+
+ if (getTorrentListAdapter() == null) {
+ setListAdapter(new TorrentListAdapter(this, showTorrents));
+ } else {
+ getTorrentListAdapter().replace(showTorrents);
+ }
+
+ // Scroll to the top of the list as well?
+ if (forceScrollToTop) {
+ getListView().setSelection(0);
+ }
+
+ updateEmptyListDescription();
+
+ // Update the torrents view type text
+ int mainViewTextID = activeMainView == MainViewType.OnlyDownloading? R.string.view_showdl:
+ (activeMainView == MainViewType.OnlyUploading? R.string.view_showul:
+ (activeMainView == MainViewType.OnlyInactive? R.string.view_showinactive: R.string.view_showall));
+ int mainViewDrawableID = activeMainView == MainViewType.OnlyDownloading? R.drawable.icon_showdl:
+ (activeMainView == MainViewType.OnlyUploading? R.drawable.icon_showup:
+ (activeMainView == MainViewType.OnlyInactive? R.drawable.icon_showinactive: R.drawable.icon_showall));
+ viewtype.setText(getText(mainViewTextID).toString() + (Daemon.supportsLabels(getActiveDaemonType())? "\n" + useLabel: ""));
+ viewtypeselector.setImageResource(mainViewDrawableID);
+
+ }
+ }
+
+ private boolean matchesLabel(Torrent torrent, String matchLabel, String showAllLabelsText) {
+ if (Daemon.supportsLabels(getActiveDaemonType())) {
+ return matchLabel == null || matchLabel.equals(showAllLabelsText) || torrent.getLabelName().equals(matchLabel);
+ }
+ return true;
+ }
+
+ private boolean matchesStatus(Torrent torrent, MainViewType matchViewType) {
+ boolean isActivelyDownloading = torrent.getStatusCode() == TorrentStatus.Downloading && (!onlyShowTransferring || torrent.getRateDownload() > 0);
+ boolean isActivelySeeding = torrent.getStatusCode() == TorrentStatus.Seeding && (!onlyShowTransferring || torrent.getRateUpload() > 0);
+ return (matchViewType == MainViewType.ShowAll ||
+ (matchViewType == MainViewType.OnlyDownloading && isActivelyDownloading) ||
+ (matchViewType == MainViewType.OnlyUploading && isActivelySeeding)||
+ (matchViewType == MainViewType.OnlyInactive && !isActivelyDownloading && !isActivelySeeding));
+ }
+
+ private void setProgressBar(boolean b) {
+ inProgress = b;
+ getSupportActivity().invalidateOptionsMenu();
+ }
+
+ protected View findViewById(int id) {
+ return getView().findViewById(id);
+ }
+
+ protected ListView getListView() {
+ return (ListView) findViewById(R.id.torrents);
+ }
+
+ private TorrentListAdapter getTorrentListAdapter() {
+ return (TorrentListAdapter) getListView().getAdapter();
+ }
+
+ private void setListAdapter(TorrentListAdapter torrentListAdapter) {
+ getListView().setAdapter(torrentListAdapter);
+ if (torrentListAdapter == null || torrentListAdapter.getCount() <= 0) {
+ emptyText.setVisibility(View.VISIBLE);
+ getListView().setVisibility(View.GONE);
+ } else {
+ emptyText.setVisibility(View.GONE);
+ getListView().setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void showDialog(int id) {
+ new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG + id);
+ }
+
+ protected void dismissDialog(int id) {
+ // Remove the dialog wrapper fragment for the dialog's ID
+ getSupportActivity().getSupportFragmentManager().beginTransaction().remove(
+ getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit();
+ }
+
+ /**
+ * Returns the type of the currently active (shown) daemon
+ * @return The enum type of the active daemon
+ */
+ public Daemon getActiveDaemonType() {
+ return daemon.getType();
+ }
+
+ /*@Override
+ public boolean onTouchEvent(MotionEvent me) {
+ return gestureDetector.onTouchEvent(me);
+ }*/
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return gestureDetector.onTouchEvent(event);
+ }
+
+ /**
+ * Internal class that handles gestures from the Transdroid main screen (a 'swipe' or 'fling').
+ *
+ * More at http://stackoverflow.com/questions/937313/android-basic-gesture-detection
+ */
+ class MainScreenGestureListener extends SimpleOnGestureListener {
+
+ private static final int SWIPE_MIN_DISTANCE = 120;
+ private static final int SWIPE_MAX_OFF_PATH = 250;
+ private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
+ @Override
+ public boolean onDoubleTap (MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+
+ if (e1 != null && e2 != null) {
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+ return false;
+ }
+
+ if (daemon != null && interfaceSettings != null) {
+ if (Daemon.supportsLabels(daemon.getType()) && interfaceSettings.shouldSwipeLabels()) {
+
+ // Determine to which label to switch
+ String[] allLabels = buildLabelTexts(true);
+ int newLabel = 0;
+ if (activeLabel != null) {
+ for (int i = 0; i < allLabels.length; i++) {
+ if (activeLabel.equals(allLabels[i])) {
+ newLabel = i;
+ break;
+ }
+ }
+ }
+ if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newLabel++;
+ if (newLabel >= allLabels.length) {
+ newLabel = 0;
+ }
+ } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newLabel--;
+ if (newLabel < 0) {
+ newLabel = allLabels.length - 1;
+ }
+ }
+
+ // Make the switch, if possible and needed
+ if (newLabel >=0 && newLabel < allLabels.length && (activeLabel == null || activeLabel != allLabels[newLabel])) {
+ activeLabel = allLabels[newLabel];
+ updateTorrentsView(true);
+ }
+
+ } else {
+
+ // Determine to which daemon we are now switching
+ int newDaemon = lastUsedDaemonSettings;
+ // right to left swipe
+ if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newDaemon = lastUsedDaemonSettings + 1;
+ if (newDaemon >= allDaemonSettings.size()) {
+ newDaemon = 0;
+ }
+ } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newDaemon = lastUsedDaemonSettings - 1;
+ if (newDaemon < 0) {
+ newDaemon = allDaemonSettings.size() - 1;
+ }
+ }
+
+ // Make the switch, if needed
+ if (lastUsedDaemonSettings != newDaemon) {
+ switchDaemonConfig(newDaemon);
+ }
+
+ }
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/Transdroid.java b/android/src/org/transdroid/gui/Transdroid.java
new file mode 100644
index 00000000..f1240478
--- /dev/null
+++ b/android/src/org/transdroid/gui/Transdroid.java
@@ -0,0 +1,67 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.net.Uri;
+
+/**
+ * The application's constants.
+ *
+ * @author erickok
+ *
+ */
+public class Transdroid {
+
+ public final static String SCAN_INTENT = "com.google.zxing.client.android.SCAN";
+ public static final Uri SCANNER_MARKET_URI = Uri.parse("market://search?q=pname:com.google.zxing.client.android");
+ public static final String SCAN_FORMAT_QRCODE = "QR_CODE";
+
+ public static final String BITTORRENT_MIME = "application/x-bittorrent";
+ public static final String INTENT_OPENDAEMON = "org.transdroid.OPEN_DAEMON";
+ public static final String INTENT_ADD_MULTIPLE = "org.transdroid.ADD_MULTIPLE";
+ public static final String INTENT_TORRENT_URLS = "TORRENT_URLS";
+ public static final String INTENT_TORRENT_TITLES = "TORRENT_TITLES";
+ public static final String INTENT_TORRENT_TITLE = "TORRENT_TITLE";
+
+ public static final String REMOTEINTENT = "org.openintents.remote.intent.action.VIEW";
+ public static final String REMOTEINTENT_HOST = "org.openintents.remote.intent.extra.HOST";
+ public final static Uri VLCREMOTE_MARKET_URI = Uri.parse("market://search?q=pname:org.peterbaldwin.client.android.vlcremote");
+ public final static Uri ANDFTP_MARKET_URI = Uri.parse("market://search?q=pname:lysesoft.andftp");
+ public final static String ANDFTP_INTENT_TYPE = "vnd.android.cursor.dir/lysesoft.andftp.uri";
+ public final static String ANDFTP_INTENT_USER = "ftp_username";
+ public final static String ANDFTP_INTENT_PASS = "ftp_password";
+ public final static String ANDFTP_INTENT_PASV = "ftp_pasv";
+ public final static String ANDFTP_INTENT_CMD = "command_type";
+ public final static String ANDFTP_INTENT_FILE = "remote_file1";
+ public final static String ANDFTP_INTENT_LOCAL = "local_folder";
+
+ /**
+ * Returns whether the device is a tablet (or better: whether it can fit a tablet layout)
+ * @param r The application resources
+ * @return True if the device is a tablet, false otherwise
+ */
+ public static boolean isTablet(Resources r) {
+ //boolean hasLargeScreen = ((r.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE);
+ boolean hasXLargeScreen = ((r.getConfiguration().screenLayout &
+ Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);
+ return hasXLargeScreen;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssFeedListAdapter.java b/android/src/org/transdroid/gui/rss/RssFeedListAdapter.java
new file mode 100644
index 00000000..5dae6e18
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssFeedListAdapter.java
@@ -0,0 +1,146 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.ifies.android.sax.Item;
+import org.ifies.android.sax.RssParser;
+import org.transdroid.R;
+import org.transdroid.gui.util.ArrayAdapter;
+import org.transdroid.rss.RssFeedSettings;
+import org.transdroid.util.TLog;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+/**
+ * An adapter that can be mapped to a list of rss feeds.
+ * @author erickok
+ *
+ */
+public class RssFeedListAdapter extends ArrayAdapter {
+
+ private static final String LOG_NAME = "RSS feeds";
+
+ private List unreadMessages;
+
+ public RssFeedListAdapter(Context context, List feeds) {
+ super(context, feeds);
+
+ // Maintain a list where, for each of the feeds, the number of unread messages is kept
+ // Initially this will show '?' (loading) and an asynchronous process will fill these
+ this.unreadMessages = new ArrayList();
+ for (int i = 0; i < feeds.size(); i++) {
+ unreadMessages.add("?");
+ retrieveUnreadPostCount(i);
+ }
+ }
+
+ public View getView(int position, View convertView, ViewGroup paret) {
+ if (convertView == null) {
+ // Create a new view
+ return new RssFeedListView(getContext(), getItem(position), unreadMessages.get(position));
+ } else {
+ // Reuse view
+ RssFeedListView setView = (RssFeedListView) convertView;
+ setView.setData(getItem(position), unreadMessages.get(position));
+ return setView;
+ }
+ }
+
+ private void retrieveUnreadPostCount(final int position) {
+
+ final RssFeedSettings settings = getItem(position);
+ TLog.d(LOG_NAME, "Retreiving unread item count for RSS feed " + settings.getName());
+
+ final Handler retrieveHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+
+ // Error?
+ if (msg.what == -1) {
+ // .obj contains the exception object
+ Toast.makeText(getContext(), settings.getName() + ": " + ((Exception)msg.obj).getMessage(), Toast.LENGTH_LONG).show();
+ unreadMessages.set(position, "?");
+ RssFeedListAdapter.this.notifyDataSetChanged();
+ return;
+ }
+
+ // Number of unread messages is on the message .obj and the settings object key as integer in .what
+ if (Integer.parseInt(settings.getKey()) == msg.what) {
+ unreadMessages.set(position, ((Integer)msg.obj).toString());
+ RssFeedListAdapter.this.notifyDataSetChanged();
+ }
+
+ }
+ };
+
+ // Asynchronous getting of the number of unread messages
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+
+ // Load RSS items
+ RssParser parser = new RssParser(settings.getUrl());
+ parser.parse();
+ if (parser.getChannel() == null) {
+ throw new Exception(getContext().getResources().getString(R.string.error_norssfeed));
+ }
+
+ // Count items until that last known read item is found again
+ // Note that the item URL is used as unique identifier
+ int unread = 0;
+ List items = parser.getChannel().getItems();
+ Collections.sort(items, Collections.reverseOrder());
+ for (Item item : items) {
+ if (settings.getLastNew() == null || item == null || item.getTheLink() == null || item.getTheLink().equals(settings.getLastNew())) {
+ break;
+ }
+ unread++;
+ }
+
+ // Return the found number of unread messages
+ TLog.d(LOG_NAME, "RSS feed " + settings.getName() + " has " + unread + " new messages.");
+ Message msg = Message.obtain();
+ msg.what = Integer.parseInt(settings.getKey());
+ msg.obj = unread;
+ retrieveHandler.sendMessage(msg);
+
+ } catch (Exception e) {
+
+ // Return the error to the callback
+ TLog.d(LOG_NAME, e.toString());
+ Message msg = Message.obtain();
+ msg.what = -1;
+ msg.obj = e;
+ retrieveHandler.sendMessage(msg);
+ }
+
+ }
+ }.start();
+
+ }
+}
diff --git a/android/src/org/transdroid/gui/rss/RssFeedListView.java b/android/src/org/transdroid/gui/rss/RssFeedListView.java
new file mode 100644
index 00000000..0ed4f7e5
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssFeedListView.java
@@ -0,0 +1,72 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import org.transdroid.R;
+import org.transdroid.rss.RssFeedSettings;
+
+import android.content.Context;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+/**
+ * A view that shows an rss feed and its number of unread items as a list view.
+ *
+ * The number of unread items is received asynchronously.
+ *
+ * @author erickok
+ *
+ */
+public class RssFeedListView extends LinearLayout {
+
+ //private static final String LOG_NAME = "Transdroid RSS feeds";
+
+ /**
+ * Constructs a view that can display an rss feed name and number of new items since last time (to use in a list)
+ * @param context The activity context
+ * @param feedSettings The rss feed to show the data for
+ * @param unreadMessages The string showing the number of unread messages (or ? when it is still loading)
+ */
+ public RssFeedListView(Context context, RssFeedSettings feedSettings, String unreadMessages) {
+ super(context);
+ addView(inflate(context, R.layout.list_item_rssfeed, null));
+
+ setData(feedSettings, unreadMessages);
+ }
+
+ /**
+ * Sets the actual texts and images to the visible widgets (fields)
+ */
+ public void setData(RssFeedSettings feedSettings, String unreadMessages) {
+ TextView name = (TextView)findViewById(R.id.feed_name);
+ TextView count = (TextView)findViewById(R.id.feed_unreadcount);
+ ProgressBar loading = (ProgressBar)findViewById(R.id.feed_loading);
+
+ name.setText(feedSettings.getName());
+ if (unreadMessages.equals("?")) {
+ loading.setVisibility(VISIBLE);
+ count.setVisibility(GONE);
+ } else {
+ loading.setVisibility(GONE);
+ count.setText(unreadMessages);
+ count.setVisibility(VISIBLE);
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssFeeds.java b/android/src/org/transdroid/gui/rss/RssFeeds.java
new file mode 100644
index 00000000..0bce4852
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssFeeds.java
@@ -0,0 +1,44 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import org.transdroid.R;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+public class RssFeeds extends FragmentActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_rssfeeds);
+
+ getSupportActionBar().setDisplayShowTitleEnabled(true);
+
+ if (savedInstanceState == null) {
+ // Start the fragment
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.feeds, new RssFeedsFragment());
+ ft.commit();
+ }
+
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssFeedsFragment.java b/android/src/org/transdroid/gui/rss/RssFeedsFragment.java
new file mode 100644
index 00000000..57d9ddd1
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssFeedsFragment.java
@@ -0,0 +1,174 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.rss;
+
+import java.util.List;
+
+import org.transdroid.R;
+import org.transdroid.gui.Transdroid;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.preferences.PreferencesRss;
+import org.transdroid.rss.RssFeedSettings;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.Menu;
+import android.support.v4.view.MenuItem;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class RssFeedsFragment extends Fragment {
+
+ // private static final String LOG_NAME = "Transdroid RSS feeds";
+
+ private static final int ACTIVITY_PREFERENCES = 0;
+ private static final int MENU_REFRESH_ID = 1;
+ private static final int MENU_SETTINGS_ID = 2;
+
+ protected boolean useTabletInterface;
+
+ public RssFeedsFragment() {
+ setHasOptionsMenu(true);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_rssfeeds, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ useTabletInterface = Transdroid.isTablet(getResources());
+ registerForContextMenu(getView().findViewById(android.R.id.list));
+ getSupportActivity().getSupportActionBar().setTitle(R.string.rss);
+ getListView().setOnItemClickListener(onFeedClicked);
+
+ getSupportActivity().setTitle(R.string.rss);
+
+ loadFeeds();
+
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ // Add title bar buttons
+ MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
+ miRefresh.setIcon(R.drawable.icon_refresh_title);
+ miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ // Add the settings button
+ MenuItem miSettings = menu.add(0, MENU_SETTINGS_ID, 0,
+ R.string.menu_settings);
+ miSettings.setIcon(android.R.drawable.ic_menu_preferences);
+ }
+
+ private void loadFeeds() {
+
+ // Read the feed settings from the user preferences
+ // Note that the 'number of new items' is retrieved asynchronously from
+ // within the RssFeedListAdapter
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ List feeds = Preferences.readAllRssFeedSettings(prefs);
+ setListAdapter(new RssFeedListAdapter(getActivity(), feeds));
+
+ }
+
+ private OnItemClickListener onFeedClicked = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+
+ // Show the feed items in the right of the screen (tablet interface) or separately
+ if (useTabletInterface) {
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.listing, new RssListingFragment(getListAdapter().getItem(position)));
+ ft.commit();
+ } else {
+ // Open the listing for the clicked RSS feed
+ String postfix = getListAdapter().getItem(position).getKey();
+ Intent i = new Intent(getActivity(), RssListing.class);
+ i.putExtra(RssListing.RSSFEED_LISTING_KEY, postfix);
+ startActivity(i);
+ }
+
+ }
+ };
+
+ @Override
+ public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_REFRESH_ID:
+ loadFeeds();
+ break;
+ case MENU_SETTINGS_ID:
+ startActivityForResult(new Intent(getActivity(),
+ PreferencesRss.class), ACTIVITY_PREFERENCES);
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case ACTIVITY_PREFERENCES:
+
+ // Preference screen was called: use new preferences to show new
+ // feeds
+ loadFeeds();
+ break;
+ }
+ }
+
+ protected ListView getListView() {
+ return (ListView) getView().findViewById(android.R.id.list);
+ }
+
+ protected RssFeedListAdapter getListAdapter() {
+ return (RssFeedListAdapter) getListView().getAdapter();
+ }
+
+ private View getEmptyText() {
+ return getView().findViewById(android.R.id.empty);
+ }
+
+ private void setListAdapter(RssFeedListAdapter rssFeedListAdapter) {
+ getListView().setAdapter(rssFeedListAdapter);
+ if (rssFeedListAdapter == null || rssFeedListAdapter.getCount() <= 0) {
+ getListView().setVisibility(View.GONE);
+ getEmptyText().setVisibility(View.VISIBLE);
+ } else {
+ getListView().setVisibility(View.VISIBLE);
+ getEmptyText().setVisibility(View.GONE);
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssItemListAdapter.java b/android/src/org/transdroid/gui/rss/RssItemListAdapter.java
new file mode 100644
index 00000000..e988802b
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssItemListAdapter.java
@@ -0,0 +1,62 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.ifies.android.sax.Item;
+import org.transdroid.gui.util.SelectableArrayAdapter;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * An adapter that can be mapped to a list of rss items.
+ * @author erickok
+ *
+ */
+public class RssItemListAdapter extends SelectableArrayAdapter {
+
+ private List isNew;
+ private boolean enableCheckboxes;
+
+ public RssItemListAdapter(Context context, OnSelectedChangedListener listener, List items, boolean enableCheckboxes, String lastNew) {
+ super(context, items, listener);
+ this.enableCheckboxes = enableCheckboxes;
+
+ // The 'last new' item url used to see which items are new since the last viewing of this feed
+ // For each item in the items list, there is one boolean in the isNew list indicating if it is new
+ boolean stillNew = true;
+ isNew = new ArrayList();
+ for (Item item : items) {
+ if (lastNew == null || item.getTheLink() == null || item.getTheLink().equals(lastNew)) {
+ stillNew = false;
+ }
+ isNew.add(new Boolean(stillNew));
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup paret, boolean selected) {
+ // TODO: Try to reuse the view to improve scrolling performance
+ return new RssItemListView(getContext(), this, getItem(position), isNew.get(position), enableCheckboxes, selected);
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssItemListView.java b/android/src/org/transdroid/gui/rss/RssItemListView.java
new file mode 100644
index 00000000..8a942fbb
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssItemListView.java
@@ -0,0 +1,97 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import java.util.Date;
+
+import org.ifies.android.sax.Item;
+import org.transdroid.R;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+
+/**
+ * A view that shows an RSS item (which is a link to some torrent) in a list view
+ *
+ * @author erickok
+ *
+ */
+public class RssItemListView extends LinearLayout {
+
+ private RssItemListAdapter adapter;
+ private Item item;
+
+ /**
+ * Constructs a view that can display RSS item data (to use in a list)
+ * @param context The activity context
+ * @param isNew Whether this message was new since the last viewin of the RSS feed
+ * @param torrent The RSS item to show the data for
+ */
+ public RssItemListView(Context context, RssItemListAdapter adapter, Item item, boolean isNew, boolean isCheckable, boolean initiallyChecked) {
+ super(context);
+ this.adapter = adapter;
+
+ addView(inflate(context, R.layout.list_item_rssitem, null));
+ setData(item, isNew,isCheckable, initiallyChecked);
+ }
+
+ /**
+ * Sets the actual texts and images to the visible widgets (fields)
+ */
+ public void setData(Item item, boolean isNew, boolean isCheckable, boolean initiallyChecked) {
+ this.item = item;
+
+ // Set the checkbox that allow picking of multiple results at once
+ final CheckBox check = (CheckBox)findViewById(R.id.rssitem_check);
+ if (isCheckable) {
+ check.setVisibility(VISIBLE);
+ check.setChecked(initiallyChecked);
+ check.setOnCheckedChangeListener(itemSelection);
+ } else {
+ check.setVisibility(GONE);
+ }
+
+ // Bind the data values to the text views
+ ImageView icon = ((ImageView)findViewById(R.id.rssitem_new));
+ TextView title = ((TextView)findViewById(R.id.rssitem_title));
+ TextView date = ((TextView)findViewById(R.id.rssitem_date));
+ icon.setImageResource(isNew? R.drawable.icon_new: R.drawable.icon_notnew);
+ title.setText(item.getTitle());
+ if (item.getPubdate() != null) {
+ date.setText(DateUtils.formatSameDayTime(item.getPubdate().getTime(), new Date().getTime(), java.text.DateFormat.MEDIUM, java.text.DateFormat.SHORT));
+ date.setVisibility(VISIBLE);
+ } else {
+ date.setText("");
+ date.setVisibility(GONE);
+ }
+ }
+
+ private OnCheckedChangeListener itemSelection = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ adapter.itemChecked(item, isChecked);
+ }
+ };
+
+}
diff --git a/android/src/org/transdroid/gui/rss/RssListing.java b/android/src/org/transdroid/gui/rss/RssListing.java
new file mode 100644
index 00000000..4da82117
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssListing.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.rss;
+
+import org.transdroid.R;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.rss.RssFeedSettings;
+
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v4.app.ActionBar;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+public class RssListing extends FragmentActivity {
+
+ public static final String RSSFEED_LISTING_KEY = "RSSFEED_LISTING_KEY";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_rsslisting);
+
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+
+ if (savedInstanceState == null) {
+ // Get the ID of the RSS feed to load
+ String postfix = getIntent().getStringExtra(RSSFEED_LISTING_KEY);
+ // Get settings form user preferences
+ RssFeedSettings feedSettings = Preferences.readRssFeedSettings(PreferenceManager.getDefaultSharedPreferences(this), postfix);
+
+ // Start the fragment for this torrent
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.items, new RssListingFragment(feedSettings));
+ ft.commit();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/org/transdroid/gui/rss/RssListingFragment.java b/android/src/org/transdroid/gui/rss/RssListingFragment.java
new file mode 100644
index 00000000..86a44adc
--- /dev/null
+++ b/android/src/org/transdroid/gui/rss/RssListingFragment.java
@@ -0,0 +1,624 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.rss;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.ifies.android.sax.Item;
+import org.ifies.android.sax.RssParser;
+import org.transdroid.R;
+import org.transdroid.gui.Torrents;
+import org.transdroid.gui.Transdroid;
+import org.transdroid.gui.search.Search;
+import org.transdroid.gui.util.DialogWrapper;
+import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.rss.RssFeedSettings;
+import org.transdroid.util.TLog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.SearchManager;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.PreferenceManager;
+import android.support.v4.app.ActionBar.OnNavigationListener;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.Menu;
+import android.support.v4.view.MenuItem;
+import android.text.Html;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class RssListingFragment extends Fragment implements OnTouchListener, OnSelectedChangedListener {
+
+ private static final String LOG_NAME = "RSS listing";
+
+ private static final int MENU_REFRESH_ID = 1;
+ private static final int ITEMMENU_ADD_ID = 10;
+ private static final int ITEMMENU_BROWSE_ID = 11;
+ private static final int ITEMMENU_DETAILS_ID = 12;
+ private static final int ITEMMENU_USEASSEARCH_ID = 13;
+
+ private static final int DIALOG_ITEMDETAILS = 20;
+
+ private TextView empty;
+ private LinearLayout addSelected;
+ private Button addSelectedButton;
+ private GestureDetector gestureDetector;
+
+ private boolean inProgress = false;
+ private List allFeeds = null;
+ protected List lastLoadedItems = null;
+ private RssFeedSettings feedSettings;
+ private boolean ignoreFirstListNavigation = true;
+ private String detailsDialogText;
+
+
+ public RssListingFragment(RssFeedSettings feedSettings) {
+ this.feedSettings = feedSettings;
+ setHasOptionsMenu(true);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_rsslisting, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ registerForContextMenu(getListView());
+ getListView().setOnItemClickListener(onItemClicked);
+ empty = (TextView) getView().findViewById(android.R.id.empty);
+ addSelected = (LinearLayout) getView().findViewById(R.id.add_selected);
+ addSelectedButton = (Button) getView().findViewById(R.id.add_selectedbutton);
+ addSelectedButton.setOnClickListener(addSelectedClicked);
+ // Swiping or flinging between server configurations
+ gestureDetector = new GestureDetector(new RssScreenGestureListener());
+ getSupportActivity().getSupportActionBar().setTitle(R.string.rss);
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ allFeeds = Preferences.readAllRssFeedSettings(prefs);
+
+ ignoreFirstListNavigation = true;
+ if (getActivity() instanceof RssListing) {
+ getSupportActivity().getSupportActionBar().setListNavigationCallbacks(buildFeedsAdapter(), onFeedSelected);
+ }
+ if (lastLoadedItems == null || feedSettings == null) {
+ // Start loading the items
+ loadItems();
+ } else {
+ // Set items from the retained instance state
+ if (getActivity() instanceof RssListing) {
+ getSupportActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings));
+ setListAdapter(new RssItemListAdapter(getActivity(), RssListingFragment.this, lastLoadedItems, true, feedSettings.getLastNew()));
+ }
+ }
+
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ menu.add(0, ITEMMENU_ADD_ID, 0, R.string.searchmenu_add);
+ menu.add(0, ITEMMENU_BROWSE_ID, 0, R.string.searchmenu_details);
+ menu.add(0, ITEMMENU_DETAILS_ID, 0, R.string.details_details);
+ menu.add(0, ITEMMENU_USEASSEARCH_ID, 0, R.string.searchmenu_useassearch);
+
+ }
+
+ private void loadItems() {
+
+ setListAdapter(null);
+ if (feedSettings == null) {
+ empty.setText(R.string.rss_no_items);
+ return;
+ }
+
+ // Show the 'loading' icon (rotating indeterminate progress bar)
+ setProgressBar(true);
+ empty.setText(R.string.rss_loading_feed);
+
+ // Show the (newly) selected feed
+ if (getActivity() instanceof RssListing && feedSettings.getName() != null && !feedSettings.getName().equals("")) {
+ ignoreFirstListNavigation = true;
+ getSupportActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings));
+ }
+
+ // Read the RSS items asynchronously
+ final Handler retrieveHandler = new Handler() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleMessage(Message msg) {
+
+ // Not loading any more, turn off status indicator
+ setProgressBar(false);
+
+ // Error?
+ if (msg.what == -1) {
+ String errorMessage = ((Exception)msg.obj).getMessage();
+ Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show();
+ empty.setText(errorMessage);
+ return;
+ }
+
+ // The list of items is contained in the message obj
+ List items = (List) msg.obj;
+ lastLoadedItems = items;
+ if (items == null || items.size() == 0) {
+
+ empty.setText(R.string.rss_no_items);
+
+ } else {
+
+ setListAdapter(new RssItemListAdapter(getActivity(), RssListingFragment.this, items, true, feedSettings.getLastNew()));
+
+ // Also store the 'last url' for the newest item that we now viewed
+ // (The most recent is always the first item, we assume)
+ Editor manager = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit();
+ manager.putString(Preferences.KEY_PREF_RSSLASTNEW + feedSettings.getKey(), items.get(0).getTheLink());
+ manager.commit();
+ feedSettings.setLastNew(items.get(0).getTheLink());
+
+ }
+
+ }
+ };
+
+ // Asynchronous getting of the RSS items
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+
+ // Load RSS items
+ RssParser parser = new RssParser(feedSettings.getUrl());
+ parser.parse();
+ if (parser.getChannel() == null) {
+ throw new Exception(getResources().getString(R.string.error_norssfeed));
+ }
+ List items = parser.getChannel().getItems();
+ Collections.sort(items, Collections.reverseOrder());
+
+ // Return the list of items
+ TLog.d(LOG_NAME, "RSS feed " + feedSettings.getName() + " has " + items.size() + " messages.");
+ Message msg = Message.obtain();
+ msg.what = 1;
+ msg.obj = items;
+ retrieveHandler.sendMessage(msg);
+
+ } catch (Exception e) {
+
+ // Return the error to the callback
+ TLog.d(LOG_NAME, e.toString());
+ Message msg = Message.obtain();
+ msg.what = -1;
+ msg.obj = e;
+ retrieveHandler.sendMessage(msg);
+ }
+
+ }
+ }.start();
+
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem item) {
+
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ Item result = (Item) getListAdapter().getItem((int) info.id);
+
+ switch (item.getItemId()) {
+ case ITEMMENU_ADD_ID:
+
+ // Directly add this torrent
+ addTorrent(result);
+ break;
+
+ case ITEMMENU_BROWSE_ID:
+
+ // Open the browser to show the website contained in the item's link tag
+ if (result.getLink() != null && !result.getLink().equals("")) {
+ Uri uri = Uri.parse(result.getLink());
+ startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ } else {
+ // No URL was specified in the RSS feed item link tag (or no link tag was present)
+ Toast.makeText(getActivity(), R.string.error_no_link, Toast.LENGTH_LONG).show();
+ }
+ break;
+
+ case ITEMMENU_DETAILS_ID:
+
+ // Show a dialog box with the RSS item description text
+ detailsDialogText = result.getDescription();
+ showDialog(DIALOG_ITEMDETAILS);
+ break;
+
+ case ITEMMENU_USEASSEARCH_ID:
+
+ // Use the title of this torrent as a new search query
+ Intent search = new Intent(getActivity(), Search.class);
+ search.setAction(Intent.ACTION_SEARCH);
+ search.putExtra(SearchManager.QUERY, result.getTitle());
+ startActivity(search);
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+
+ // Add title bar buttons
+ if (getActivity() instanceof RssListing) {
+ MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
+ miRefresh.setIcon(R.drawable.icon_refresh_title);
+ miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ if (inProgress ) {
+ // Show progress spinner instead of the option item
+ View view = getActivity().getLayoutInflater().inflate(R.layout.part_actionbar_progressitem, null);
+ miRefresh.setActionView(view);
+ }
+ }
+
+ }
+
+ private OnItemClickListener onItemClicked = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ Item item = (Item) getListAdapter().getItem(position);
+ // If something was already selected before
+ if (!getRssItemListAdapter().getSelected().isEmpty()) {
+ getRssItemListAdapter().itemChecked(item, !getRssItemListAdapter().isItemChecked(item));
+ getListView().invalidateViews();
+ } else {
+ // No selection: add directly
+ addTorrent(item);
+ }
+ }
+ };
+
+ @Override
+ public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_REFRESH_ID:
+ loadItems();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_ITEMDETAILS:
+
+ // Build a dialog with a description text
+ AlertDialog.Builder detailsDialog = new AlertDialog.Builder(getActivity());
+ detailsDialog.setTitle(R.string.details_details);
+ detailsDialog.setMessage(Html.fromHtml((detailsDialogText == null? "": detailsDialogText)));
+ detailsDialog.setNeutralButton(android.R.string.ok, null);
+ return detailsDialog.create();
+
+ /*case DIALOG_FEEDS:
+
+ // Build a dialog with a radio box per RSS feed
+ AlertDialog.Builder feedsDialog = new AlertDialog.Builder(this);
+ feedsDialog.setTitle(R.string.pref_rss_info);
+ feedsDialog.setSingleChoiceItems(
+ buildFeedTextsForDialog(), // The strings of the available RSS feeds
+ feedSettingsIndex(feedSettings),
+ new DialogInterface.OnClickListener() {
+ @Override
+ // When the feed is clicked (and it is different from the current shown feed),
+ // change the feed to show
+ public void onClick(DialogInterface dialog, int which) {
+ RssFeedSettings selected = allFeeds.get(which);
+ if (selected.getKey() != feedSettings.getKey()) {
+
+ feedSettings = selected;
+ loadItems();
+
+ }
+ removeDialog(DIALOG_FEEDS);
+ }
+ });
+ return feedsDialog.create();*/
+
+ }
+ return null;
+
+ }
+
+ /*@Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ switch (id) {
+ case DIALOG_ITEMDETAILS:
+
+ AlertDialog detailsDialog = (AlertDialog) dialog;
+ detailsDialog.setMessage(Html.fromHtml(detailsDialogText == null? "": detailsDialogText));
+ break;
+
+ }
+ super.onPrepareDialog(id, dialog);
+ }*/
+
+ private int feedSettingsIndex(RssFeedSettings afeed) {
+ int i = 0;
+ for (RssFeedSettings feed : allFeeds) {
+ if (feed.getKey().equals(afeed.getKey())) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ private SpinnerAdapter buildFeedsAdapter() {
+ ArrayAdapter ad = new ArrayAdapter(getActivity(), R.layout.abs__simple_spinner_item, buildFeedTextsForDialog());
+ ad.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ return ad;
+ }
+
+ private String[] buildFeedTextsForDialog() {
+
+ // Build a textual list of RSS feeds available
+ ArrayList feeds = new ArrayList();
+ for (RssFeedSettings feed : allFeeds) {
+ feeds.add(feed.getName());
+ }
+ return feeds.toArray(new String[feeds.size()]);
+
+ }
+
+ private OnNavigationListener onFeedSelected = new OnNavigationListener() {
+ @Override
+ public boolean onNavigationItemSelected(int which, long itemId) {
+ if (!ignoreFirstListNavigation) {
+ RssFeedSettings selected = allFeeds.get(which);
+ if (selected.getKey() != feedSettings.getKey()) {
+
+ feedSettings = selected;
+ loadItems();
+
+ }
+ }
+ ignoreFirstListNavigation = false;
+ return true;
+ }
+ };
+
+ private RssItemListAdapter getRssItemListAdapter() {
+ return (RssItemListAdapter) getListAdapter();
+ }
+
+ private void addTorrent(Item item) {
+
+ // The actual torrent URL is usually contained an 'enclosure' or the link tag
+ if (item.getTheLink() != null && !item.getTheLink().equals("")) {
+
+ Intent i;
+ if (feedSettings.needsAuthentication()) {
+ // Redirect links to the Android browser instead of directly adding it via URL
+ i = new Intent(Intent.ACTION_VIEW, Uri.parse(item.getTheLink()));
+ } else {
+ // Build new intent that Transdroid can pick up again
+ i = new Intent(getActivity(), Torrents.class);
+ i.setData(Uri.parse(item.getTheLink()));
+ }
+
+ // Create a result for the calling activity
+ //setResult(RESULT_OK);
+ startActivity(i);
+ getSupportFragmentManager().popBackStack();
+
+ } else {
+
+ // No URL was specified in the RSS feed item
+ Toast.makeText(getActivity(), R.string.error_no_url_enclosure, Toast.LENGTH_LONG).show();
+
+ }
+
+ }
+
+ private void addTorrents(List items) {
+
+ // The actual torrent URL is usually contained an 'enclosure' or the link tag
+ // We will test the first selected item, since it is very likely that if this has a link, the others will as well
+ if (items != null && items.size() > 0) {
+ if (items.get(0).getTheLink() != null && !items.get(0).getTheLink().equals("")) {
+
+ // Build new intent that Transdroid can pick up again
+ // This sets the data to "||..."
+ Intent i = new Intent(getActivity(), Torrents.class);
+ String[] urls = new String[items.size()];
+ for (int j = 0; j < items.size(); j++) {
+ urls[j] = items.get(j).getTheLink();
+ }
+ i.setAction(Transdroid.INTENT_ADD_MULTIPLE);
+ i.putExtra(Transdroid.INTENT_TORRENT_URLS, urls);
+
+ // Create a result for the calling activity
+ //setResult(RESULT_OK);
+ startActivity(i);
+ getSupportFragmentManager().popBackStack();
+
+ } else {
+
+ // No URL was specified in the RSS feed item
+ Toast.makeText(getActivity(), R.string.error_no_url_enclosure, Toast.LENGTH_LONG).show();
+
+ }
+ }
+
+ }
+
+ private void setProgressBar(boolean b) {
+ inProgress = b;
+ getSupportActivity().invalidateOptionsMenu();
+ }
+
+ /*@Override
+ public boolean onTouchEvent(MotionEvent me) {
+ return gestureDetector.onTouchEvent(me);
+ }*/
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return gestureDetector.onTouchEvent(event);
+ }
+
+ /**
+ * Internal class that handles gestures from the search screen (a 'swipe' or 'fling').
+ *
+ * More at http://stackoverflow.com/questions/937313/android-basic-gesture-detection
+ */
+ class RssScreenGestureListener extends SimpleOnGestureListener {
+
+ private static final int SWIPE_MIN_DISTANCE = 120;
+ private static final int SWIPE_MAX_OFF_PATH = 250;
+ private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
+ @Override
+ public boolean onDoubleTap (MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+
+ if (e1 != null && e2 != null) {
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+ return false;
+ }
+
+ // Determine to which feed we are now switching
+ int newFeed = feedSettingsIndex(feedSettings);
+ // right to left swipe
+ if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newFeed += 1;
+ if (newFeed >= allFeeds.size()) {
+ newFeed = 0;
+ }
+ } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newFeed -= 1;
+ if (newFeed < 0) {
+ newFeed = allFeeds.size() - 1;
+ }
+ }
+
+ // Make the switch, if needed
+ RssFeedSettings newFeedSettings = allFeeds.get(newFeed);
+ if (!newFeedSettings.getKey().equals(feedSettings.getKey())) {
+ feedSettings = newFeedSettings;
+ loadItems();
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Called by the SelectableArrayAdapter when the set of selected items changed
+ */
+ public void onSelectedResultsChanged() {
+ RssItemListAdapter adapter = (RssItemListAdapter) getListAdapter();
+ if (adapter.getSelected().size() == 0) {
+ // Hide the 'add selected' button
+ addSelected.setVisibility(View.GONE);
+ } else {
+ addSelected.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private OnClickListener addSelectedClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Send the urls of all selected search result back to Transdroid
+ RssItemListAdapter adapter = (RssItemListAdapter) getListAdapter();
+ addTorrents(adapter.getSelected());
+ }
+ };
+
+ public void showDialog(int id) {
+ new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG + id);
+ }
+
+ protected void dismissDialog(int id) {
+ // Remove the dialog wrapper fragment for the dialog's ID
+ getSupportActivity().getSupportFragmentManager().beginTransaction().remove(
+ getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit();
+ }
+
+ protected ListView getListView() {
+ return (ListView) getView().findViewById(android.R.id.list);
+ }
+
+ protected RssItemListAdapter getListAdapter() {
+ return (RssItemListAdapter) getListView().getAdapter();
+ }
+
+ private View getEmptyText() {
+ return getView().findViewById(android.R.id.empty);
+ }
+
+ private void setListAdapter(RssItemListAdapter adapter) {
+ getListView().setAdapter(adapter);
+ if (adapter == null || adapter.getCount() <= 0) {
+ getListView().setVisibility(View.GONE);
+ getEmptyText().setVisibility(View.VISIBLE);
+ } else {
+ getListView().setVisibility(View.VISIBLE);
+ getEmptyText().setVisibility(View.GONE);
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/search/GlobalTorrentSearch.java b/android/src/org/transdroid/gui/search/GlobalTorrentSearch.java
new file mode 100644
index 00000000..47175928
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/GlobalTorrentSearch.java
@@ -0,0 +1,28 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+/**
+ * The default search activity, but extended to provide a
+ * separate class for the Quick Search Box expose.
+ *
+ * @author erickok
+ */
+public class GlobalTorrentSearch extends Search {
+
+}
diff --git a/android/src/org/transdroid/gui/search/GlobalTorrentSearchProvider.java b/android/src/org/transdroid/gui/search/GlobalTorrentSearchProvider.java
new file mode 100644
index 00000000..de64c111
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/GlobalTorrentSearchProvider.java
@@ -0,0 +1,102 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.search;
+
+import org.transdroid.R;
+import org.transdroid.preferences.Preferences;
+
+import android.app.SearchManager;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+import android.provider.BaseColumns;
+
+/**
+ * Will provide a search 'suggestion' to the global Quick Search Box to search
+ * for torrents in every available (in-app or web) search site
+ *
+ * @author erickok
+ *
+ */
+public class GlobalTorrentSearchProvider extends ContentProvider {
+
+ public static final String AUTHORITY = "org.transdroid.GlobalTorrentSearchProvider";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return SearchManager.SUGGEST_MIME_TYPE;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+
+ // Return a suggestion for every available site
+ return new SitesCursor(getContext(), selectionArgs[0]);
+ }
+
+ private class SitesCursor extends MatrixCursor {
+
+ public SitesCursor(Context context, String query) {
+ super(new String[] {
+ BaseColumns._ID,
+ SearchManager.SUGGEST_COLUMN_TEXT_1,
+ SearchManager.SUGGEST_COLUMN_TEXT_2,
+ SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
+ SearchManager.SUGGEST_COLUMN_QUERY,
+ SearchManager.SUGGEST_COLUMN_SHORTCUT_ID});
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ // Add a single item for the default search site
+ SiteSettings site = Preferences.readDefaultSearchSiteSettings(prefs);
+ RowBuilder row = newRow();
+ row.add(0); // ID
+ row.add(query); // First text line
+ row.add(context.getString(R.string.search_resultsfrom) + " " + site.getName()); // Second text line
+ row.add(site.getKey()); // Extra string (daemon key to search against)
+ row.add(query); // Extra string (query)
+ row.add(0);
+ }
+
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+
+}
diff --git a/android/src/org/transdroid/gui/search/Search.java b/android/src/org/transdroid/gui/search/Search.java
new file mode 100644
index 00000000..2157e4c8
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/Search.java
@@ -0,0 +1,752 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.transdroid.R;
+import org.transdroid.daemon.util.HttpHelper;
+import org.transdroid.gui.Torrents;
+import org.transdroid.gui.Transdroid;
+import org.transdroid.gui.util.ActivityUtil;
+import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener;
+import org.transdroid.preferences.Preferences;
+import org.transdroid.util.TLog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.SearchManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.provider.SearchRecentSuggestions;
+import android.support.v4.app.ActionBar;
+import android.support.v4.app.ActionBar.OnNavigationListener;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.view.Menu;
+import android.support.v4.view.MenuItem;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * Provides an activity that allows a search to be performed on a search engine and
+ * lists the results. Individual results can be browsed to using the web browser or the URL
+ * is forwarded to the Torrents activity. For web searches, the browser is started at
+ * the appropriate search URL. In-app searches are performed with the Transdroid Torrent
+ * Search project's public cursor adapters.
+ *
+ * @author erickok
+ *
+ */
+public class Search extends FragmentActivity implements OnTouchListener, OnSelectedChangedListener {
+
+ private static final String LOG_NAME = "Search";
+ private final static Uri TTS_MARKET_URI = Uri.parse("market://search?q=pname:org.transdroid.search");
+
+ private static final int MENU_REFRESH_ID = 1;
+ private static final int MENU_SEARCH_ID = 2;
+ private static final int MENU_SITES_ID = 3;
+ private static final int MENU_SAVESEARCH_ID = 4;
+
+ private static final int SEARCHMENU_ADD_ID = 10;
+ private static final int SEARCHMENU_DETAILS_ID = 11;
+ private static final int SEARCHMENU_OPENWITH_ID = 12;
+ private static final int SEARCHMENU_SHARELINK_ID = 13;
+
+ private static final int DIALOG_SITES = 1;
+ private static final int DIALOG_INSTALLSEARCH = 2;
+
+ private TextView empty;
+ private LinearLayout addSelected;
+ private Button addSelectedButton;
+ private SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
+ TorrentSearchHistoryProvider.AUTHORITY, TorrentSearchHistoryProvider.MODE);
+ private GestureDetector gestureDetector;
+
+ private List allSites;
+ private SiteSettings defaultSite;
+ private SearchSettings searchSettings;
+ private String query;
+
+ private boolean inProgress = false;
+ private boolean disableListNavigation = true;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_search);
+
+ registerForContextMenu(findViewById(R.id.results));
+ getListView().setTextFilterEnabled(true);
+ getListView().setOnItemClickListener(onSearchResultSelected);
+
+ getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+
+ empty = (TextView) findViewById(android.R.id.empty);
+ addSelected = (LinearLayout) findViewById(R.id.add_selected);
+ addSelectedButton = (Button) findViewById(R.id.add_selectedbutton);
+ addSelectedButton.setOnClickListener(addSelectedClicked);
+ // Swiping or flinging between server configurations
+ gestureDetector = new GestureDetector(new SearchScreenGestureListener());
+ getListView().setOnTouchListener(this);
+
+ handleIntent(getIntent());
+
+ }
+
+ private SpinnerAdapter buildProvidersAdapter() {
+ ArrayAdapter ad = new ArrayAdapter(this, R.layout.abs__simple_spinner_item, buildSiteTextsForDialog());
+ ad.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ return ad;
+ }
+
+ /** Called when a new intent is delivered */
+ @Override
+ public void onNewIntent(final Intent newIntent) {
+ super.onNewIntent(newIntent);
+
+ handleIntent(newIntent);
+ }
+
+ private void handleIntent(Intent startIntent) {
+
+ // Get the query string from the intent
+ String thequery = getQuery(startIntent);
+
+ // Is this actually a full HTTP URL?
+ if (thequery != null && (thequery.startsWith(HttpHelper.SCHEME_HTTP) ||
+ thequery.startsWith(HttpHelper.SCHEME_MAGNET) || thequery.startsWith(HttpHelper.SCHEME_FILE))) {
+
+ // Redirect this request to the main screen to add the URL directly
+ Intent i = new Intent(this, Torrents.class);
+ i.setData(Uri.parse(thequery));
+ startActivity(i);
+ finish();
+ return;
+
+ }
+
+ // Check if Transdroid Torrent Search is installed
+ if (!TorrentSearchTask.isTorrentSearchInstalled(this)) {
+ showDialog(DIALOG_INSTALLSEARCH);
+ empty.setText("");
+ return;
+ }
+
+ // Load preferences
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ defaultSite = Preferences.readDefaultSearchSiteSettings(prefs);
+ allSites = Preferences.readAllSiteSettings(prefs);
+ searchSettings = Preferences.readSearchSettings(prefs);
+
+ // Update selection spinner
+ disableListNavigation = true;
+ getSupportActionBar().setListNavigationCallbacks(buildProvidersAdapter(), onProviderSelected);
+
+ // Switch to a certain site?
+ if (startIntent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
+ String switchToKey = startIntent.getStringExtra(SearchManager.EXTRA_DATA_KEY);
+ // See if this site (key) exists
+ for (SiteSettings site : allSites) {
+ if (site.getKey().equals(switchToKey)) {
+ // If it is different than the last used (default) site, switch to it
+ if (!defaultSite.getKey().equals(switchToKey)) {
+ // Set the default site search to this new site
+ Preferences.storeLastUsedSearchSiteSettings(getApplicationContext(), switchToKey);
+ defaultSite = allSites.get(siteSettingsIndex(site));
+ }
+ break;
+ }
+ }
+
+ }
+
+ if (defaultSite == null) {
+ return;
+ }
+
+ // Start a web search?
+ if (defaultSite.isWebSearch()) {
+
+ if (thequery == null || thequery.equals("")) {
+ // No search term was provided: show a message and close this search activity
+ Toast.makeText(this, R.string.no_query, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ doWebSearch(defaultSite, thequery);
+ finish();
+ return;
+
+ }
+
+ // Select the now-selected site in the spinner
+ getSupportActionBar().setSelectedNavigationItem(siteSettingsIndex(defaultSite));
+ disableListNavigation = false;
+
+ // Normal in-app search
+ query = thequery;
+ handleQuery();
+
+ }
+
+ private void doWebSearch(SiteSettings thesite, String thequery) {
+
+ // Check for a valid url
+ Uri uri = Uri.parse(thesite.getSubstitutedUrl(thequery));
+ if (uri == null || uri.getScheme() == null || !(uri.getScheme().equals("http") || uri.getScheme().equals("https"))) {
+ // The url doesn't even have a http or https scheme, so the intent will fail
+ Toast.makeText(this, getResources().getText(R.string.error_invalid_search_url) + " " + uri.toString(), Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ // Do not load this activity, but immediately start a web search via a new Intent
+ startActivity(new Intent(Intent.ACTION_VIEW, uri));
+
+ }
+
+ /**
+ * Extracts the query string from the search Intent
+ * @return The string that was entered by the user
+ */
+ private String getQuery(Intent intent) {
+
+ // Extract string from Intent
+ String query = null;
+ if (intent.getAction().equals(Intent.ACTION_SEARCH)) {
+ query = intent.getStringExtra(SearchManager.QUERY);
+ } else if (intent.getAction().equals(Intent.ACTION_SEND)) {
+ query = SendIntentHelper.cleanUpText(intent);
+ }
+ if (query != null && query.length() > 0) {
+
+ // Remember this search query to later show as a suggestion
+ suggestions.saveRecentQuery(query, null);
+ return query;
+
+ }
+ return null;
+
+ }
+
+ /**
+ * Actually calls the search on the local preset query (if not empty)
+ */
+ private void handleQuery() {
+
+ if (query == null || query.equals("")) {
+ // No search (activity was started incorrectly or query was empty)
+ empty.setText(R.string.no_query);
+
+ // Provide search input
+ onSearchRequested();
+ return;
+ }
+
+ // Execute search
+ doSearch(query);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ menu.add(0, SEARCHMENU_ADD_ID, 0, R.string.searchmenu_add);
+ menu.add(0, SEARCHMENU_DETAILS_ID, 0, R.string.searchmenu_details);
+ menu.add(0, SEARCHMENU_OPENWITH_ID, 0, R.string.searchmenu_openwith);
+ menu.add(0, SEARCHMENU_SHARELINK_ID, 0, R.string.searchmenu_sharelink);
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ boolean result = super.onCreateOptionsMenu(menu);
+
+ // Add title bar buttons
+ MenuItem miRefresh = menu.add(0, MENU_REFRESH_ID, 0, R.string.refresh);
+ miRefresh.setIcon(R.drawable.icon_refresh_title);
+ miRefresh.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ if (inProgress) {
+ // Show progress spinner instead of the option item
+ View view = getLayoutInflater().inflate(R.layout.part_actionbar_progressitem, null);
+ miRefresh.setActionView(view);
+ }
+ MenuItem miSearch = menu.add(0, MENU_SEARCH_ID, 0, R.string.search);
+ miSearch.setIcon(R.drawable.icon_search_title);
+ miSearch.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS|MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ if (TorrentSearchTask.isTorrentSearchInstalled(this)) {
+ // Add the switch sites button
+ MenuItem miSwitch = menu.add(0, MENU_SITES_ID, 0, R.string.searchmenu_switchsite);
+ miSwitch.setIcon(android.R.drawable.ic_menu_myplaces);
+
+ // Add the save search button
+ MenuItem miSave = menu.add(0, MENU_SAVESEARCH_ID, 0, R.string.searchmenu_savesearch);
+ miSave.setIcon(android.R.drawable.ic_menu_save);
+ }
+
+ return result;
+ }
+
+ private OnItemClickListener onSearchResultSelected = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View v, int position, long id) {
+ // If something was already selected before
+ Cursor item = (Cursor) getListAdapter().getItem(position);
+ String url = item.getString(TorrentSearchTask.CURSOR_SEARCH_TORRENTURL);
+ if (!getSearchListAdapter().getSelectedUrls().isEmpty()) {
+
+ // Use an item click as selection check box click
+ getSearchListAdapter().itemChecked(url, !getSearchListAdapter().isItemChecked(url));
+ getListView().invalidateViews();
+
+ } else {
+
+ // Directly return the URL of the clicked torrent file
+ ReturnUrlResult(url, item.getString(TorrentSearchTask.CURSOR_SEARCH_NAME));
+
+ }
+ }
+ };
+
+ private SearchListAdapter getSearchListAdapter() {
+ return (SearchListAdapter) getListAdapter();
+ }
+
+ @Override
+ public boolean onContextItemSelected(android.view.MenuItem item) {
+
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ Cursor result = (Cursor) getListAdapter().getItem((int) info.id);
+
+ switch (item.getItemId()) {
+ case SEARCHMENU_ADD_ID:
+
+ // Return the url of the selected list item
+ ReturnUrlResult(result.getString(TorrentSearchTask.CURSOR_SEARCH_TORRENTURL),
+ result.getString(TorrentSearchTask.CURSOR_SEARCH_NAME));
+ break;
+
+ case SEARCHMENU_DETAILS_ID:
+
+ // Open the browser to show the website details page
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(result.getString(TorrentSearchTask.CURSOR_SEARCH_DETAILSURL))));
+ break;
+
+ case SEARCHMENU_OPENWITH_ID:
+
+ // Start a VIEW (open) Intent with the .torrent url that other apps can catch
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(result.getString(TorrentSearchTask.CURSOR_SEARCH_TORRENTURL))));
+ break;
+
+ case SEARCHMENU_SHARELINK_ID:
+
+ // Start a SEND (share) Intent with the .torrent url so the user can send the link to someone else
+ startActivity(Intent.createChooser(
+ new Intent(Intent.ACTION_SEND)
+ .setType("text/plain")
+ .putExtra(Intent.EXTRA_TEXT, result.getString(TorrentSearchTask.CURSOR_SEARCH_TORRENTURL))
+ .putExtra(Intent.EXTRA_SUBJECT, result.getString(TorrentSearchTask.CURSOR_SEARCH_NAME)),
+ getText(R.string.searchmenu_sharelink)));
+ break;
+
+ }
+ return true;
+ }
+
+ private OnNavigationListener onProviderSelected = new OnNavigationListener() {
+ @Override
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+ if (!disableListNavigation) {
+ switchProvider(itemPosition);
+ }
+ return false;
+ }
+ };
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ switch (item.getItemId()) {
+
+ case MENU_REFRESH_ID:
+
+ if (TorrentSearchTask.isTorrentSearchInstalled(this) && defaultSite != null) {
+ handleQuery();
+ }
+ break;
+
+ case MENU_SEARCH_ID:
+
+ onSearchRequested();
+ break;
+
+ case MENU_SITES_ID:
+
+ // Present a dialog with all available in-app sites
+ showDialog(DIALOG_SITES);
+ break;
+
+ case MENU_SAVESEARCH_ID:
+
+ // Save the current query as an RSS feed
+ saveSearch();
+ break;
+
+ }
+ return super.onMenuItemSelected(featureId, item);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+
+ switch (id) {
+ case DIALOG_SITES:
+
+ // Build a dialog with a radio box per in-app search site
+ AlertDialog.Builder serverDialog = new AlertDialog.Builder(this);
+ serverDialog.setTitle(R.string.searchmenu_switchsite);
+ serverDialog.setSingleChoiceItems(
+ buildSiteTextsForDialog(), // The strings of the available in-app search sites
+ siteSettingsIndex(defaultSite),
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ // When the server is clicked (and it is different from the current active configuration),
+ // reload the daemon and update the torrent list
+ public void onClick(DialogInterface dialog, int which) {
+ switchProvider(which);
+ removeDialog(DIALOG_SITES);
+ }
+ });
+ return serverDialog.create();
+
+ case DIALOG_INSTALLSEARCH:
+
+ return ActivityUtil.buildInstallDialog(this, R.string.tts_not_found, TTS_MARKET_URI, true);
+
+ }
+ return super.onCreateDialog(id);
+
+ }
+
+ private void switchProvider(int which) {
+ SiteSettings selected = allSites.get(which);
+ if (selected.getKey() != defaultSite.getKey()) {
+
+ if (selected.isWebSearch()) {
+ // Start a web search, but do not change the defaultSite
+ doWebSearch(selected, query);
+ } else {
+ // Set the default site search to this new site
+ Preferences.storeLastUsedSearchSiteSettings(getApplicationContext(), selected.getKey());
+ defaultSite = selected;
+ // Search again with the same query
+ handleQuery();
+ }
+
+ }
+ }
+ private int siteSettingsIndex(SiteSettings asite) {
+ if (asite == null ) {
+ return 0;
+ }
+ int i = 0;
+ for (SiteSettings site : allSites) {
+ if (site.getKey().equals(asite.getKey())) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ private String[] buildSiteTextsForDialog() {
+
+ // Build a textual list of in-app search sites available
+ ArrayList sites = new ArrayList();
+ for (SiteSettings site : allSites) {
+ //if (!site.isWebSearch()) {
+ sites.add(site.getName());
+ //}
+ }
+ return sites.toArray(new String[sites.size()]);
+
+ }
+
+ private void ReturnUrlResult(String uri, String title) {
+
+ if (uri == null) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ try {
+ Uri.parse(uri);
+ } catch (Exception e) {
+ Toast.makeText(this, R.string.error_no_url_enclosure, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // Build new intent that Transdroid can pick up again
+ Intent i = new Intent(this, Torrents.class);
+ i.setData(Uri.parse(uri));
+ i.putExtra(Transdroid.INTENT_TORRENT_TITLE, title);
+
+ // Create a result for the calling activity
+ setResult(RESULT_OK);
+ startActivity(i);
+ finish();
+ }
+
+ private void ReturnUrlResult(Set results) {
+
+ // Build new intent with multiple result url's that Transdroid can pick up again
+ Intent i = new Intent(this, Torrents.class);
+ i.setAction(Transdroid.INTENT_ADD_MULTIPLE);
+ i.putExtra(Transdroid.INTENT_TORRENT_URLS, results.toArray(new String[] {}));
+
+ // Create a result for the calling activity
+ setResult(RESULT_OK);
+ startActivity(i);
+ finish();
+ }
+
+ private void doSearch(String query) {
+
+ // Show the 'loading' icon (rotating indeterminate progress bar)
+ setProgressBar(true);
+ // Show the searching text again (if search was started from within this screen itself, the results screen was populated)
+ empty.setText(R.string.searching);
+ if (getListAdapter() != null) {
+ setListAdapter(null);
+ }
+
+ // Start a new search
+ TLog.d(LOG_NAME, "Starting a " + defaultSite.getKey() + " search with query: " + query);
+ setTitle(getText(R.string.search_resultsfrom) + " " + defaultSite.getName());
+ new TorrentSearchTask(this) {
+ @Override
+ protected void onResultsRetrieved(Cursor cursor) {
+ Search.this.onResultsRetrieved(cursor);
+ }
+ @Override
+ protected void onError() {
+ Search.this.onError(getString(R.string.error_httperror));
+ }
+ }.execute(query, Preferences.getCursorKeyForPreferencesKey(defaultSite.getKey()), searchSettings.getSortBySeeders()? "BySeeders": "Combined");
+
+ }
+
+ private void setProgressBar(boolean b) {
+ inProgress = b;
+ invalidateOptionsMenu();
+ }
+
+ public void onResultsRetrieved(Cursor cursor) {
+
+ // Not loading any more, turn off status indicator
+ setProgressBar(false);
+
+ // Update the list
+ empty.setText(R.string.no_results);
+ setListAdapter(new SearchListAdapter(this, cursor, this));
+ getListView().requestFocus();
+ getListView().setOnTouchListener(this);
+
+ }
+
+ public void onError(String errorMessage) {
+
+ // Not loading any more, turn off status indicator
+ setProgressBar(false);
+
+ // Update the list
+ empty.setText(errorMessage);
+ setListAdapter(null);
+
+ }
+
+ private void saveSearch() {
+
+ // Find the url to match an RSS feed to the last query
+ String url = TorrentSearchTask.buildRssFeedFromSearch(this, defaultSite.getKey(), query);
+ if (url != null) {
+
+ // Build new RSS feed settings object
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ int i = 0;
+ String nextUrl = Preferences.KEY_PREF_RSSURL + Integer.toString(i);
+ while (prefs.contains(nextUrl)) {
+ i++;
+ nextUrl = Preferences.KEY_PREF_RSSURL + Integer.toString(i);
+ }
+
+ // Store an RSS feed setting for this feed
+ Editor editor = prefs.edit();
+ editor.putString(Preferences.KEY_PREF_RSSNAME + Integer.toString(i), query);
+ editor.putString(nextUrl, url);
+ editor.commit();
+
+ Toast.makeText(this, R.string.search_savedrssfeed, Toast.LENGTH_SHORT).show();
+
+ } else {
+ Toast.makeText(this, R.string.search_savenotsupported, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ protected ListView getListView() {
+ return (ListView) findViewById(R.id.results);
+ }
+
+ private SearchListAdapter getListAdapter() {
+ return (SearchListAdapter) getListView().getAdapter();
+ }
+
+ private View getEmptyText() {
+ return findViewById(android.R.id.empty);
+ }
+
+ private void setListAdapter(SearchListAdapter adapter) {
+ getListView().setAdapter(adapter);
+ if (adapter == null || adapter.getCount() <= 0) {
+ getListView().setVisibility(View.GONE);
+ getEmptyText().setVisibility(View.VISIBLE);
+ } else {
+ getListView().setVisibility(View.VISIBLE);
+ getEmptyText().setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent me) {
+ return gestureDetector.onTouchEvent(me);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return gestureDetector.onTouchEvent(event);
+ }
+
+ /**
+ * Internal class that handles gestures from the search screen (a 'swipe' or 'fling').
+ *
+ * More at http://stackoverflow.com/questions/937313/android-basic-gesture-detection
+ */
+ class SearchScreenGestureListener extends SimpleOnGestureListener {
+
+ private static final int SWIPE_MIN_DISTANCE = 120;
+ private static final int SWIPE_MAX_OFF_PATH = 250;
+ private static final int SWIPE_THRESHOLD_VELOCITY = 200;
+
+ @Override
+ public boolean onDoubleTap (MotionEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+
+ if (e1 != null && e2 != null) {
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+ return false;
+ }
+
+ // Determine to which daemon we are now switching
+ int newSite = siteSettingsIndex(defaultSite);
+ // right to left swipe
+ if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newSite += 1;
+ if (newSite >= allSites.size() || allSites.get(newSite).isWebSearch()) {
+ newSite = 0;
+ }
+ } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ newSite -= 1;
+ if (newSite < 0) {
+ newSite = allSites.size() - 1;
+ while (allSites.get(newSite).isWebSearch()) {
+ // Skip the web search sites
+ newSite -= 1;
+ }
+ }
+ }
+
+
+ // Make the switch, if needed
+ SiteSettings newSiteSettings = allSites.get(newSite);
+ if (!newSiteSettings.getKey().equals(defaultSite.getKey())) {
+ // Set the default site search to this new site
+ Preferences.storeLastUsedSearchSiteSettings(getApplicationContext(), newSiteSettings.getKey());
+ defaultSite = newSiteSettings;
+ disableListNavigation = true;
+ getSupportActionBar().setSelectedNavigationItem(newSite);
+ disableListNavigation = false;
+ handleQuery();
+ }
+ }
+
+ return false;
+ }
+
+ }
+
+ /**
+ * Called by the SelectableArrayAdapter when the set of selected search results changed
+ */
+ public void onSelectedResultsChanged() {
+ SearchListAdapter adapter = (SearchListAdapter) getListAdapter();
+ if (adapter.getSelectedUrls().size() == 0) {
+ // Hide the 'add selected' button
+ addSelected.setVisibility(View.GONE);
+ } else {
+ addSelected.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private OnClickListener addSelectedClicked = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Send the urls of all selected search result back to Transdroid
+ SearchListAdapter adapter = (SearchListAdapter) getListAdapter();
+ ReturnUrlResult(adapter.getSelectedUrls());
+ }
+ };
+}
diff --git a/android/src/org/transdroid/gui/search/SearchListAdapter.java b/android/src/org/transdroid/gui/search/SearchListAdapter.java
new file mode 100644
index 00000000..10729464
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/SearchListAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.transdroid.R;
+import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+
+public class SearchListAdapter extends ResourceCursorAdapter {
+
+ private final LayoutInflater li;
+
+ private HashSet selectedUrls;
+ private OnSelectedChangedListener listener;
+
+ public SearchListAdapter(Context context, Cursor c, OnSelectedChangedListener listener) {
+ super(context, R.layout.list_item_search, c);
+ li = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ this.listener = listener;
+ this.selectedUrls = new HashSet();
+ }
+
+ @Override
+ public View newView(Context context, Cursor cur, ViewGroup parent) {
+ return li.inflate(R.layout.list_item_search, parent, false);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+
+ // Set the checkbox that allow picking of multiple results at once
+ final CheckBox check = (CheckBox)view.findViewById(R.id.result_check);
+ // Store this row's URL in the check box view's tag
+ String tag = cursor.getString(TorrentSearchTask.CURSOR_SEARCH_TORRENTURL);
+ check.setTag(tag);
+ check.setChecked(selectedUrls.contains(tag));
+ check.setOnCheckedChangeListener(itemSelectionHandler);
+
+ // Bind the data values to the text views
+ TextView date = (TextView)view.findViewById(R.id.result_date);
+ ((TextView)view.findViewById(R.id.result_title)).setText(cursor.getString(TorrentSearchTask.CURSOR_SEARCH_NAME));
+ ((TextView)view.findViewById(R.id.result_size)).setText(cursor.getString(TorrentSearchTask.CURSOR_SEARCH_SIZE));
+ ((TextView)view.findViewById(R.id.result_leechers)).setText("L: " + cursor.getInt(TorrentSearchTask.CURSOR_SEARCH_LEECHERS));
+ ((TextView)view.findViewById(R.id.result_seeds)).setText("S: " + cursor.getInt(TorrentSearchTask.CURSOR_SEARCH_SEEDERS));
+ long dateAdded = cursor.getLong(TorrentSearchTask.CURSOR_SEARCH_ADDED);
+ if (dateAdded > 0) {
+ date.setText(DateFormat.getDateInstance(DateFormat.SHORT).format(new Date(dateAdded)));
+ date.setVisibility(View.VISIBLE);
+ } else {
+ date.setText("");
+ date.setVisibility(View.GONE);
+ }
+
+ }
+
+ private final OnCheckedChangeListener itemSelectionHandler = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ itemChecked((String) buttonView.getTag(), isChecked);
+ }
+ };
+
+ /**
+ * Is called by views to indicate an item was either selected or deselected
+ * @param url The URL for which the selected state has changed
+ * @param isChecked If the item is now checked/selected
+ */
+ public void itemChecked(String url, boolean isChecked) {
+ if (!isChecked && selectedUrls.contains(url)) {
+ selectedUrls.remove(url);
+ }
+ if (isChecked && !selectedUrls.contains(url)) {
+ selectedUrls.add(url);
+ }
+ if (listener != null) {
+ listener.onSelectedResultsChanged();
+ }
+ }
+
+ /**
+ * Whether an search item is currently selected
+ * @param url The search item URL, which should be present in the underlying list
+ * @return True if the search item is currently selected, false otherwise
+ */
+ public boolean isItemChecked(String url) {
+ return selectedUrls.contains(url);
+ }
+
+ /**
+ * Returns the list of all checked/selected items
+ * @return The list of selected items
+ */
+ public Set getSelectedUrls() {
+ return this.selectedUrls;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/search/SearchSettings.java b/android/src/org/transdroid/gui/search/SearchSettings.java
new file mode 100644
index 00000000..bebe6892
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/SearchSettings.java
@@ -0,0 +1,57 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+/**
+ * A class that contains interface settings relating to searches
+ *
+ * @author eric
+ *
+ */
+public final class SearchSettings {
+
+ final private int numberOfResults;
+ final private boolean sortBySeeders;
+
+ /**
+ * Creates a search site settings instance, providing all result options details
+ * @param numberOfResults The number of results to get from the server for a single query
+ * @param sortBySeeders Whether to sort by number of leechers (otherwise a combined sort is used)
+ */
+ public SearchSettings(int numberOfResults, boolean sortBySeeders) {
+ this.numberOfResults = numberOfResults;
+ this.sortBySeeders = sortBySeeders;
+ }
+
+ /**
+ * Gives how many search results to show in one screen
+ * @return The number of results to show
+ */
+ public int getNumberOfResults() {
+ return numberOfResults;
+ }
+
+ /**
+ * Gives the sort method that should be used
+ * @return True if the results should be sorted by number of seeders/leechers, otherwise it should sort using the torrent site default
+ */
+ public boolean getSortBySeeders() {
+ return sortBySeeders;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/search/SendIntentHelper.java b/android/src/org/transdroid/gui/search/SendIntentHelper.java
new file mode 100644
index 00000000..6dee5aea
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/SendIntentHelper.java
@@ -0,0 +1,51 @@
+package org.transdroid.gui.search;
+
+import android.content.Intent;
+
+/**
+ * Used to clean up text as received from a generic ACTION_SEND intent. This
+ * class is highly custom-based for known applications, i.e. the EXTRA_TEXT
+ * send by some known applications.
+ *
+ * @author erickok
+ */
+public class SendIntentHelper {
+
+ private static final String SOUNDHOUND1 = "Just used #SoundHound to find ";
+ private static final String SOUNDHOUND1_END = " http://";
+ private static final String YOUTUBE_ID= "Watch \"";
+ private static final String YOUTUBE_START = "\"";
+ private static final String YOUTUBE_END = "\"";
+
+ public static String cleanUpText(Intent intent) {
+
+ if (intent == null || !intent.hasExtra(Intent.EXTRA_TEXT)) {
+ return null;
+ }
+ String text = intent.getStringExtra(Intent.EXTRA_TEXT);
+ try {
+
+ // Soundhound song/artist share
+ if (text.startsWith(SOUNDHOUND1)) {
+ return cutOut(text, SOUNDHOUND1, SOUNDHOUND1_END).replace(" by ", " ");
+ }
+ // YouTube app share (stores title in EXTRA_SUBJECT)
+ if (intent.hasExtra(Intent.EXTRA_SUBJECT)) {
+ String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
+ if (subject.startsWith(YOUTUBE_ID)) {
+ return cutOut(subject, YOUTUBE_START, YOUTUBE_END);
+ }
+ }
+
+ } catch (Exception e) {
+ // Ignore any errors in parsing; just return the raw text
+ }
+ return text;
+ }
+
+ private static String cutOut(String text, String start, String end) {
+ int startAt = text.indexOf(start) + start.length();
+ return text.substring(startAt, text.indexOf(end, startAt));
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/search/SiteSettings.java b/android/src/org/transdroid/gui/search/SiteSettings.java
new file mode 100644
index 00000000..55ee18ca
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/SiteSettings.java
@@ -0,0 +1,112 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+import java.net.URLEncoder;
+
+import org.transdroid.R;
+
+/**
+ * Represents a torrent site configuration; either in-app or web search
+ *
+ * @author erickok
+ *
+ */
+public final class SiteSettings {
+
+ final private boolean isWebSearch;
+ final private String key;
+ final private String name;
+ final private String url;
+
+ /**
+ * Instantiates an in-app search site
+ * @param adapterKey The unique key identifying the search adapter
+ * @param name The visible name of the site
+ */
+ public SiteSettings(String adapterKey, String name) {
+ this.isWebSearch = false;
+ this.key = adapterKey;
+ this.name = name;
+ this.url = null;
+ }
+
+ /**
+ * Instantiates a web search site
+ * @param uniqueKey The (numeric) identifier for this web search settings (used as postfix on stored preferences)
+ * @param name The visible name of the site
+ * @param encodedUrl The raw URL to send the web search to, where %s will be replaced by the search keywords; for example http://www.google.nl/search?q=%s+ext%3Atorrent
+ */
+ public SiteSettings(String uniqueKey, String name, String encodedUrl) {
+ this.isWebSearch = true;
+ this.key = uniqueKey;
+ this.name = name;
+ this.url = encodedUrl;
+ }
+
+ /**
+ * @return If this site performs a web search; it is an in-app search otherwise
+ */
+ public boolean isWebSearch() {
+ return isWebSearch;
+ }
+
+ /**
+ * @return For in-app search sites this is the factory key; otherwise it is the unique identifier used to store it in the user preferences
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * @return The visible name of the site
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the raw URL where web searches will be directed to; it has a %s where search keywords will be placed
+ * @return
+ */
+ public String getRawurl() {
+ return url;
+ }
+
+ /**
+ * Returns the URL for a search based on the user query. The query will be URL-encoded.
+ * @param query The raw user query text
+ * @return The url that can be send to the browser to show the web search results
+ */
+ public String getSubstitutedUrl(String query) {
+ return url.replace("%s", URLEncoder.encode(query));
+ }
+
+ /**
+ * Tells the user what type of search engine this is
+ * @return The resource id of the text explaining the search type
+ */
+ public int getSearchTypeTextResource() {
+ if (isWebSearch()) {
+ return R.string.websearch;
+ } else {
+ return R.string.inappsite;
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/search/TorrentSearchHistoryProvider.java b/android/src/org/transdroid/gui/search/TorrentSearchHistoryProvider.java
new file mode 100644
index 00000000..3cb289e6
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/TorrentSearchHistoryProvider.java
@@ -0,0 +1,46 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.search;
+
+import android.content.Context;
+import android.content.SearchRecentSuggestionsProvider;
+import android.provider.SearchRecentSuggestions;
+
+/**
+ * Provides a wrapper for the SearchRecentSuggestionsProvider to show the last
+ * torrent searches to the user
+ *
+ * @author erickok
+ *
+ */
+public class TorrentSearchHistoryProvider extends SearchRecentSuggestionsProvider {
+
+ final static String AUTHORITY = "org.transdroid.TorrentSearchHistoryProvider";
+ final static int MODE = DATABASE_MODE_QUERIES;
+
+ public TorrentSearchHistoryProvider() {
+ super();
+ setupSuggestions(AUTHORITY, MODE);
+ }
+
+ public static void clearHistory(Context context) {
+ SearchRecentSuggestions suggestions = new SearchRecentSuggestions(context,
+ TorrentSearchHistoryProvider.AUTHORITY, TorrentSearchHistoryProvider.MODE);
+ suggestions.clearHistory();
+ }
+}
diff --git a/android/src/org/transdroid/gui/search/TorrentSearchTask.java b/android/src/org/transdroid/gui/search/TorrentSearchTask.java
new file mode 100644
index 00000000..6cb36595
--- /dev/null
+++ b/android/src/org/transdroid/gui/search/TorrentSearchTask.java
@@ -0,0 +1,150 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.search;
+
+import org.transdroid.preferences.Preferences;
+
+import android.app.Activity;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+/**
+ * Task that helps in retrieving torrent search results from the Transdroid Torrent Search content providers.
+ * Use getSupportedSites() to see which torrent search sites are available to query against.
+ *
+ * @author erickok
+ *
+ */
+public abstract class TorrentSearchTask extends AsyncTask {
+
+ // public static final String[] SEARCH_FIELDS = new String[] { "_ID", "NAME", "TORRENTURL", "DETAILSURL",
+ // "SIZE", "ADDED", "SEEDERS", "LEECHERS" };
+ // public static final String[] SITE_FIELDS = new String[] { "_ID", "CODE", "NAME", "RSSURL" };
+
+ static final int CURSOR_SEARCH_ID = 0;
+ static final int CURSOR_SEARCH_NAME = 1;
+ static final int CURSOR_SEARCH_TORRENTURL = 2;
+ static final int CURSOR_SEARCH_DETAILSURL = 3;
+ static final int CURSOR_SEARCH_SIZE = 4;
+ static final int CURSOR_SEARCH_ADDED = 5;
+ static final int CURSOR_SEARCH_SEEDERS = 6;
+ static final int CURSOR_SEARCH_LEECHERS = 7;
+
+ static final int CURSOR_SITE_ID = 0;
+ static final int CURSOR_SITE_CODE = 1;
+ static final int CURSOR_SITE_NAME = 2;
+ static final int CURSOR_SITE_RSSURL = 3;
+
+ /**
+ * Returns the list of supported torrent search sites
+ * @param activity The displaying activity against which the query for Transdroid Torrent Search can be executed
+ * @return A cursor with search sites (with fields SITE_FIELDS)
+ */
+ public static Cursor getSupportedSites(Activity activity) {
+ // Create the URI of the TorrentSitesProvider
+ String uriString = "content://org.transdroid.search.torrentsitesprovider/sites";
+ Uri uri = Uri.parse(uriString);
+ // Then query all torrent sites (no selection nor projection nor sort):
+ return activity.managedQuery(uri, null, null, null, null);
+ }
+
+ /**
+ * Build an RSS feed URL for some site and some user query
+ * @param activity The calling activity (used to connect to Transdroid Torrent Search)
+ * @param preferencesKey The Transdroid-preferences key, e.g. 'site_mininova'
+ * @param query The user query that was searched for
+ * @return The RSS feed URL, or null if the site isn't supporting RSS feeds (or no site with preferencesKey exists)
+ */
+ public static String buildRssFeedFromSearch(Activity activity, String preferencesKey, String query) {
+ String key = Preferences.getCursorKeyForPreferencesKey(preferencesKey);
+ Cursor cursor = getSupportedSites(activity);
+ if (cursor.moveToFirst()) {
+ do {
+ if (cursor.getString(CURSOR_SITE_CODE).equals(key)) {
+ if (cursor.getString(CURSOR_SITE_RSSURL) == null || cursor.getString(CURSOR_SITE_RSSURL).equals("")) {
+ // Not supported by this site
+ return null;
+ }
+ return cursor.getString(CURSOR_SITE_RSSURL).replace("%s", query);
+ }
+ } while (cursor.moveToNext());
+ }
+ // Site is not supported by Transdroid Torrent Search
+ return null;
+ }
+
+ /**
+ * Return whether Transdroid Torrent Search is installed and available to query against
+ * @return True if the available sites can be retrieved from the content provider, false otherwise
+ */
+ public static boolean isTorrentSearchInstalled(Activity activity) {
+ return getSupportedSites(activity) != null;
+ }
+
+ private Activity activity;
+
+ public TorrentSearchTask(Activity activity) {
+ this.activity = activity;
+ }
+
+ @Override
+ protected final Cursor doInBackground(String... params) {
+
+ // Search query, site and sort order specified?
+ if (params == null || params.length != 3) {
+ return null;
+ }
+
+ // Create the URI of the TorrentProvider
+ String uriString = "content://org.transdroid.search.torrentsearchprovider/search/" + params[0];
+ Uri uri = Uri.parse(uriString);
+
+ // Then query for this specific search, site and sort order
+ return activity.managedQuery(uri, null, "SITE = ?", new String[] { params[1] }, params[2]);
+ // Actual catching of run-time exceptions doesn't work cross-process
+ /*
+ * } catch (RuntimeException e) { // Hold on to the error message; onPostExecute will post it back to
+ * make sure it's posted on the UI thread errorMessage = e.toString(); return null; }
+ */
+
+ }
+
+ @Override
+ protected final void onPostExecute(Cursor cursor) {
+ if (cursor == null)
+ onError();
+ else
+ onResultsRetrieved(cursor);
+ }
+
+ /**
+ * Method that needs to be implemented to handle the search results
+ *
+ * @param errorMessage
+ * The (technical) error message text
+ */
+ protected abstract void onResultsRetrieved(Cursor cursor);
+
+ /**
+ * Method that needs to be implemented to catch error occurring during the retrieving or parsing of search
+ * results
+ */
+ protected abstract void onError();
+
+}
diff --git a/android/src/org/transdroid/gui/util/ActivityUtil.java b/android/src/org/transdroid/gui/util/ActivityUtil.java
new file mode 100644
index 00000000..ca30890e
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/ActivityUtil.java
@@ -0,0 +1,103 @@
+package org.transdroid.gui.util;
+
+import java.util.List;
+
+import org.transdroid.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+import android.widget.Toast;
+
+public class ActivityUtil {
+
+ private static final String LOG_NAME = "Activity util";
+
+ /**
+ * Get current version number
+ * @return A string with the application version number
+ */
+ public static String getVersionNumber(Context context) {
+ String version = "?";
+ try {
+ PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ version = pi.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_NAME, "Package name not found to retrieve version number", e);
+ }
+ return version;
+ }
+
+ /**
+ * Indicates whether the specified action can be used as an intent. This
+ * method queries the package manager for installed packages that can
+ * respond to an intent with the specified action. If no suitable package is
+ * found, this method returns false.
+ * @param context The application's environment.
+ * @param intent The Intent to check for availability.
+ * @return True if an Intent with the specified action can be sent and responded to, false otherwise.
+ */
+ public static boolean isIntentAvailable(Context context, Intent intent) {
+ final PackageManager packageManager = context.getPackageManager();
+ List list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ return list.size() > 0;
+ }
+
+ /**
+ * Builds a (reusable) dialog that asks to install some application from the Android market
+ * @param messageResourceID The message to show to the user
+ * @param marketUri The application's URI on the Android Market
+ * @return The dialog to show
+ */
+ public static Dialog buildInstallDialog(final Activity activity, int messageResourceID, final Uri marketUri) {
+ return buildInstallDialog(activity, messageResourceID, marketUri, false);
+ }
+
+ /**
+ * Builds a (reusable) dialog that asks to install some application from the Android market
+ * @param messageResourceID The message to show to the user
+ * @param marketUri The application's URI on the Android Market
+ * @param alternativeNegativeButtonHandler The click handler for the negative dialog button
+ * @return The dialog to show
+ */
+ public static Dialog buildInstallDialog(final Activity activity, int messageResourceID, final Uri marketUri,
+ final boolean closeAfterInstallFailure) {
+ AlertDialog.Builder fbuilder = new AlertDialog.Builder(activity);
+ fbuilder.setMessage(messageResourceID);
+ fbuilder.setCancelable(true);
+ fbuilder.setPositiveButton(R.string.oifm_install, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent install = new Intent(Intent.ACTION_VIEW, marketUri);
+ if (ActivityUtil.isIntentAvailable(activity, install)) {
+ activity.startActivity(install);
+ } else {
+ Toast.makeText(activity, R.string.oifm_nomarket, Toast.LENGTH_LONG).show();
+ if (closeAfterInstallFailure) {
+ activity.finish();
+ }
+ }
+ dialog.dismiss();
+ }
+ });
+ fbuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ if (closeAfterInstallFailure) {
+ activity.finish();
+ }
+ }
+ });
+ return fbuilder.create();
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/util/ArrayAdapter.java b/android/src/org/transdroid/gui/util/ArrayAdapter.java
new file mode 100644
index 00000000..80f1ea2b
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/ArrayAdapter.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This ArrayList class is copied from android.widget.ArrayList and
+ * adjusted in three ways: 1) loading from resources is no longer supported,
+ * 2) a public method is added to allow replacing of the while list, and
+ * 3) it is made abstract, requiring to override getView (no more setting
+ * of the resource id to show)
+ */
+
+package org.transdroid.gui.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+
+/**
+ * A ListAdapter that manages a ListView backed by an array of arbitrary
+ * objects. getView needs to be overridden to determine the view to show
+ * for an object in the list.
+ */
+public abstract class ArrayAdapter extends BaseAdapter implements Filterable {
+ /**
+ * Contains the list of objects that represent the data of this ArrayAdapter.
+ * The content of this list is referred to as "the array" in the documentation.
+ */
+ private List mObjects;
+
+ /**
+ * Lock used to modify the content of {@link #mObjects}. Any write operation
+ * performed on the array should be synchronized on this lock. This lock is also
+ * used by the filter (see {@link #getFilter()} to make a synchronized copy of
+ * the original array of data.
+ */
+ private final Object mLock = new Object();
+
+ /**
+ * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
+ * {@link #mObjects} is modified.
+ */
+ private boolean mNotifyOnChange = true;
+
+ private Context mContext;
+
+ private ArrayList mOriginalValues;
+ private ArrayFilter mFilter;
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ */
+ public ArrayAdapter(Context context) {
+ init(context, new ArrayList());
+ }
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ * @param objects The objects to represent in the ListView.
+ */
+ public ArrayAdapter(Context context, T[] objects) {
+ init(context, Arrays.asList(objects));
+ }
+
+ /**
+ * Constructor
+ *
+ * @param context The current context.
+ * @param objects The objects to represent in the ListView.
+ */
+ public ArrayAdapter(Context context, List objects) {
+ init(context, objects);
+ }
+
+ /**
+ * Adds the specified object at the end of the array.
+ *
+ * @param object The object to add at the end of the array.
+ */
+ public void add(T object) {
+ if (mOriginalValues != null) {
+ synchronized (mLock) {
+ mOriginalValues.add(object);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+ } else {
+ mObjects.add(object);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * Inserts the specified object at the specified index in the array.
+ *
+ * @param object The object to insert into the array.
+ * @param index The index at which the object must be inserted.
+ */
+ public void insert(T object, int index) {
+ if (mOriginalValues != null) {
+ synchronized (mLock) {
+ mOriginalValues.add(index, object);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+ } else {
+ mObjects.add(index, object);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * Removes the specified object from the array.
+ *
+ * @param object The object to remove.
+ */
+ public void remove(T object) {
+ if (mOriginalValues != null) {
+ synchronized (mLock) {
+ mOriginalValues.remove(object);
+ }
+ } else {
+ mObjects.remove(object);
+ }
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+
+ /**
+ * Remove all elements from the list.
+ */
+ public void clear() {
+ if (mOriginalValues != null) {
+ synchronized (mLock) {
+ mOriginalValues.clear();
+ }
+ } else {
+ mObjects.clear();
+ }
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+
+ /**
+ * Sorts the content of this adapter using the specified comparator.
+ *
+ * @param comparator The comparator used to sort the objects contained
+ * in this adapter.
+ */
+ public void sort(Comparator super T> comparator) {
+ Collections.sort(mObjects, comparator);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+
+ /**
+ * Replaces the underlying list some other list and notifies a listening view.
+ *
+ * @param objects The new list of data objects,
+ */
+ public void replace(List objects) {
+ init(getContext(), objects);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ mNotifyOnChange = true;
+ }
+
+ /**
+ * Control whether methods that change the list ({@link #add},
+ * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
+ * {@link #notifyDataSetChanged}. If set to false, caller must
+ * manually call notifyDataSetChanged() to have the changes
+ * reflected in the attached view.
+ *
+ * The default is true, and calling notifyDataSetChanged()
+ * resets the flag to true.
+ *
+ * @param notifyOnChange if true, modifications to the list will
+ * automatically call {@link
+ * #notifyDataSetChanged}
+ */
+ public void setNotifyOnChange(boolean notifyOnChange) {
+ mNotifyOnChange = notifyOnChange;
+ }
+
+ private void init(Context context, List objects) {
+ mContext = context;
+ mObjects = objects;
+ }
+
+ /**
+ * Returns the context associated with this array adapter. The context is used
+ * to create views from the resource passed to the constructor.
+ *
+ * @return The Context associated with this adapter.
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCount() {
+ return mObjects.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public T getItem(int position) {
+ return mObjects.get(position);
+ }
+
+ /**
+ * Returns all objects in this adapter.
+ *
+ * @return The contained list of objects.
+ */
+ public List getAllItems() {
+ return mObjects;
+ }
+
+ /**
+ * Returns the position of the specified item in the array.
+ *
+ * @param item The item to retrieve the position of.
+ *
+ * @return The position of the specified item.
+ */
+ public int getPosition(T item) {
+ return mObjects.indexOf(item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getItemId(int position) {
+ return position;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract View getView(int position, View convertView, ViewGroup parent);
+
+ /**
+ * {@inheritDoc}
+ */
+ public Filter getFilter() {
+ if (mFilter == null) {
+ mFilter = new ArrayFilter();
+ }
+ return mFilter;
+ }
+
+ /**
+ *
An array filter constrains the content of the array adapter with
+ * a prefix. Each item that does not start with the supplied prefix
+ * is removed from the list.
+ */
+ private class ArrayFilter extends Filter {
+ @Override
+ protected FilterResults performFiltering(CharSequence prefix) {
+ FilterResults results = new FilterResults();
+
+ if (mOriginalValues == null) {
+ synchronized (mLock) {
+ mOriginalValues = new ArrayList(mObjects);
+ }
+ }
+
+ if (prefix == null || prefix.length() == 0) {
+ synchronized (mLock) {
+ ArrayList list = new ArrayList(mOriginalValues);
+ results.values = list;
+ results.count = list.size();
+ }
+ } else {
+ String prefixString = prefix.toString().toLowerCase();
+
+ final ArrayList values = mOriginalValues;
+ final int count = values.size();
+
+ final ArrayList newValues = new ArrayList(count);
+
+ for (int i = 0; i < count; i++) {
+ final T value = values.get(i);
+ final String valueText = value.toString().toLowerCase();
+
+ // First match against the whole, non-splitted value
+ if (valueText.startsWith(prefixString)) {
+ newValues.add(value);
+ } else {
+ final String[] words = valueText.split(" ");
+ final int wordCount = words.length;
+
+ for (int k = 0; k < wordCount; k++) {
+ if (words[k].startsWith(prefixString)) {
+ newValues.add(value);
+ break;
+ }
+ }
+ }
+ }
+
+ results.values = newValues;
+ results.count = newValues.size();
+ }
+
+ return results;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ //noinspection unchecked
+ mObjects = (List) results.values;
+ if (results.count > 0) {
+ notifyDataSetChanged();
+ } else {
+ notifyDataSetInvalidated();
+ }
+ }
+ }
+}
diff --git a/android/src/org/transdroid/gui/util/DialogWrapper.java b/android/src/org/transdroid/gui/util/DialogWrapper.java
new file mode 100644
index 00000000..af5c23ef
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/DialogWrapper.java
@@ -0,0 +1,25 @@
+package org.transdroid.gui.util;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+/**
+ * A wrapper used to create dialog fragments out of old-style activity dialogs
+ */
+public class DialogWrapper extends DialogFragment {
+
+ public static final String TAG = "DialogWrapper";
+
+ private final Dialog dialog;
+
+ public DialogWrapper(Dialog dialog) {
+ this.dialog = dialog;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return dialog;
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/org/transdroid/gui/util/ErrorLogSender.java b/android/src/org/transdroid/gui/util/ErrorLogSender.java
new file mode 100644
index 00000000..90c3bd08
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/ErrorLogSender.java
@@ -0,0 +1,98 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+ package org.transdroid.gui.util;
+
+import org.transdroid.R;
+import org.transdroid.daemon.DaemonSettings;
+import org.transdroid.daemon.IDaemonAdapter;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.widget.Toast;
+
+public class ErrorLogSender {
+
+ public static final String LOG_COLLECTOR_PACKAGE_NAME = "com.xtralogic.android.logcollector";//$NON-NLS-1$
+ public static final String ACTION_SEND_LOG = "com.xtralogic.logcollector.intent.action.SEND_LOG";//$NON-NLS-1$
+ public static final String EXTRA_SEND_INTENT_ACTION = "com.xtralogic.logcollector.intent.extra.SEND_INTENT_ACTION";//$NON-NLS-1$
+ public static final String EXTRA_DATA = "com.xtralogic.logcollector.intent.extra.DATA";//$NON-NLS-1$
+ public static final String EXTRA_ADDITIONAL_INFO = "com.xtralogic.logcollector.intent.extra.ADDITIONAL_INFO";//$NON-NLS-1$
+ public static final String EXTRA_SHOW_UI = "com.xtralogic.logcollector.intent.extra.SHOW_UI";//$NON-NLS-1$
+ public static final String EXTRA_FILTER_SPECS = "com.xtralogic.logcollector.intent.extra.FILTER_SPECS";//$NON-NLS-1$
+ public static final String EXTRA_FORMAT = "com.xtralogic.logcollector.intent.extra.FORMAT";//$NON-NLS-1$
+ public static final String EXTRA_BUFFER = "com.xtralogic.logcollector.intent.extra.BUFFER";//$NON-NLS-1$
+
+ public static void collectAndSendLog(final Context context, final IDaemonAdapter daemon, final DaemonSettings daemonSettings){
+ final Intent intent = new Intent(ACTION_SEND_LOG);
+ final boolean isInstalled = ActivityUtil.isIntentAvailable(context, intent);
+
+ if (!isInstalled){
+ new AlertDialog.Builder(context)
+ .setTitle("Transdroid")
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setMessage(R.string.lc_install)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface dialog, int whichButton){
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:" + LOG_COLLECTOR_PACKAGE_NAME));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (ActivityUtil.isIntentAvailable(context, marketIntent)) {
+ context.startActivity(marketIntent);
+ } else {
+ Toast.makeText(context, R.string.oifm_nomarket, Toast.LENGTH_LONG).show();
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+ else
+ {
+ new AlertDialog.Builder(context)
+ .setTitle("Transdroid")
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setMessage(R.string.lc_run)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface dialog, int whichButton){
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_SEND_INTENT_ACTION, Intent.ACTION_SENDTO);
+ intent.putExtra(EXTRA_DATA, Uri.parse("mailto:transdroid.org@gmail.com"));
+ intent.putExtra(EXTRA_ADDITIONAL_INFO, "My problem:\n\n\nTransdroid version " + ActivityUtil.getVersionNumber(context) + "\n" + daemon.getType().toString() + " settings: " + daemonSettings.getHumanReadableIdentifier() + "\n");
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Application failure report");
+
+ intent.putExtra(EXTRA_FORMAT, "time");
+
+ //The log can be filtered to contain data relevant only to your app
+ String[] filterSpecs = new String[4];
+ filterSpecs[0] = "AndroidRuntime:E";
+ filterSpecs[1] = "Transdroid:*";
+ filterSpecs[2] = "ActivityManager:*";
+ filterSpecs[3] = "*:S";
+ intent.putExtra(EXTRA_FILTER_SPECS, filterSpecs);
+
+ context.startActivity(intent);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/util/InterfaceSettings.java b/android/src/org/transdroid/gui/util/InterfaceSettings.java
new file mode 100644
index 00000000..a3db5e36
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/InterfaceSettings.java
@@ -0,0 +1,57 @@
+/*
+ * This file is part of Transdroid
+ *
+ * Transdroid 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Transdroid 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 Transdroid. If not, see .
+ *
+ */
+package org.transdroid.gui.util;
+
+/**
+ * A class that contains all the user interface settings.
+ *
+ * @author erickok
+ *
+ */
+public class InterfaceSettings {
+
+ private boolean swipeLabels;
+ private int refreshTimerInterval;
+ private boolean hideRefreshMessage;
+ private boolean askBeforeRemove;
+
+ public InterfaceSettings(boolean swipeLabels, int refreshTimerInterval, boolean showOnlyDownloading,
+ boolean hideRefreshMessage, boolean askBeforeRemove, boolean enableAds) {
+ this.swipeLabels = swipeLabels;
+ this.refreshTimerInterval = refreshTimerInterval;
+ this.hideRefreshMessage = hideRefreshMessage;
+ this.askBeforeRemove = askBeforeRemove;
+ }
+
+ public int getRefreshTimerInterval() {
+ return refreshTimerInterval;
+ }
+
+ public boolean shouldHideRefreshMessage() {
+ return hideRefreshMessage;
+ }
+
+ public boolean getAskBeforeRemove() {
+ return askBeforeRemove;
+ }
+
+ public boolean shouldSwipeLabels() {
+ return swipeLabels;
+ }
+
+}
diff --git a/android/src/org/transdroid/gui/util/SelectableArrayAdapter.java b/android/src/org/transdroid/gui/util/SelectableArrayAdapter.java
new file mode 100644
index 00000000..89ff4ab5
--- /dev/null
+++ b/android/src/org/transdroid/gui/util/SelectableArrayAdapter.java
@@ -0,0 +1,106 @@
+package org.transdroid.gui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class SelectableArrayAdapter extends ArrayAdapter {
+
+ private List selected;
+ private OnSelectedChangedListener listener;
+
+ public SelectableArrayAdapter(Context context, List objects, OnSelectedChangedListener listener) {
+ this(context, objects);
+ this.listener = listener;
+ }
+
+ public SelectableArrayAdapter(Context context, List objects) {
+ super(context, objects);
+ this.selected = new ArrayList();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return getView(position, convertView, parent, selected.contains(getItem(position)));
+ }
+
+ public abstract View getView(int position, View convertView, ViewGroup paret, boolean selected);
+
+ /**
+ * Is called by views to indicate an item was either selected or deselected
+ * @param item The item for which the selected state has changed
+ * @param isChecked If the item is now checked/selected
+ */
+ public void itemChecked(T item, boolean isChecked) {
+ if (!isChecked && selected.contains(item)) {
+ selected.remove(item);
+ }
+ if (isChecked && !selected.contains(item)) {
+ selected.add(item);
+ }
+ if (listener != null) {
+ listener.onSelectedResultsChanged();
+ }
+ }
+
+ /**
+ * Whether an item is currently selected
+ * @param item The item, which should be present in the underlying list
+ * @return True if the item is currently selected, false otherwise
+ */
+ public boolean isItemChecked(T item) {
+ return selected.contains(item);
+ }
+
+ @Override
+ public void replace(List objects) {
+ // Reset the 'selected' list as well
+ this.selected.clear();
+ super.replace(objects);
+ if (listener != null) {
+ listener.onSelectedResultsChanged();
+ }
+ }
+
+ /**
+ * Returns the list of all checked/selected items
+ * @return The list of selected items
+ */
+ public List getSelected() {
+ return this.selected;
+ }
+
+ /**
+ * Clears the entire item selection, leaving it empty
+ */
+ public void clearSelection() {
+ this.selected.clear();
+ if (listener != null) {
+ listener.onSelectedResultsChanged();
+ }
+ }
+
+ public void invertSelection() {
+ for (T item : getAllItems()) {
+ if (selected.contains(item)) {
+ selected.remove(item);
+ } else {
+ selected.add(item);
+ }
+ }
+ if (listener != null) {
+ listener.onSelectedResultsChanged();
+ }
+ }
+
+ /**
+ * Listener to changes in the state of selected items in an ArrayAdapter
+ */
+ public interface OnSelectedChangedListener {
+ public void onSelectedResultsChanged();
+ }
+
+}
diff --git a/android/src/org/transdroid/overview.html b/android/src/org/transdroid/overview.html
new file mode 100644
index 00000000..43d3d0c0
--- /dev/null
+++ b/android/src/org/transdroid/overview.html
@@ -0,0 +1,28 @@
+
+
+
+ Transdroid developer documentation
+
+
+
+
Transdroid is an Android remote client for your bittorrent application running
+ on a server or home computer. Many torrent clients are supported. It can show the active torrents, pause, resume
+ or remove them and new torrents can be added via URL, RSS feed or (integrated) site search. The application is
+ open-source and free.
+
+
This project is divided into several packages:
+
+
org.transdroid.gui
Everything interface related, such as the main activity.
+
org.transdroid.daemon
Adapters and helpers to connect to various torrent daemons.