Showing preview only (246K chars total). Download the full file or copy to clipboard to get everything.
Repository: mzule/AndroidWeekly
Branch: master
Commit: f4446585472d
Files: 106
Total size: 214.3 KB
Directory structure:
gitextract_qzfdnfdl/
├── .gitignore
├── LICENSE
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── mzule/
│ │ └── androidweekly/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── mzule/
│ │ │ └── androidweekly/
│ │ │ ├── App.java
│ │ │ ├── api/
│ │ │ │ ├── ApiCallback.java
│ │ │ │ ├── ArticleApi.java
│ │ │ │ ├── DictionaryApi.java
│ │ │ │ └── parser/
│ │ │ │ ├── ArticleParser.java
│ │ │ │ ├── ArticleParsers.java
│ │ │ │ ├── DocumentProvider.java
│ │ │ │ ├── FresherArticlesParser.java
│ │ │ │ └── OlderArticlesParser.java
│ │ │ ├── dao/
│ │ │ │ ├── ArticleDao.java
│ │ │ │ ├── FavoriteDao.java
│ │ │ │ ├── IssueListKeeper.java
│ │ │ │ ├── SearchHistoryKeeper.java
│ │ │ │ └── TextZoomKeeper.java
│ │ │ ├── entity/
│ │ │ │ ├── Article.java
│ │ │ │ ├── Dict.java
│ │ │ │ ├── Favorite.java
│ │ │ │ ├── Issue.java
│ │ │ │ └── TranslateResult.java
│ │ │ ├── ui/
│ │ │ │ ├── activity/
│ │ │ │ │ ├── AboutActivity.java
│ │ │ │ │ ├── ArticleActivity.java
│ │ │ │ │ ├── BaseActivity.java
│ │ │ │ │ ├── FavoriteActivity.java
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ ├── SearchActivity.java
│ │ │ │ │ └── SearchResultActivity.java
│ │ │ │ ├── adapter/
│ │ │ │ │ ├── ArticleAdapter.java
│ │ │ │ │ ├── SearchHistoryAdapter.java
│ │ │ │ │ └── SlideAdapter.java
│ │ │ │ ├── view/
│ │ │ │ │ ├── IconButton.java
│ │ │ │ │ ├── NaviBar.java
│ │ │ │ │ ├── PinnedSectionListView.java
│ │ │ │ │ ├── PopupView.java
│ │ │ │ │ ├── ProgressView.java
│ │ │ │ │ ├── TintStatusBar.java
│ │ │ │ │ ├── TranslateView.java
│ │ │ │ │ └── base/
│ │ │ │ │ ├── BaseLinearLayout.java
│ │ │ │ │ └── BaseRelativeLayout.java
│ │ │ │ └── viewtype/
│ │ │ │ ├── ArticleViewType.java
│ │ │ │ ├── BaseViewType.java
│ │ │ │ ├── SearchHistoryViewType.java
│ │ │ │ ├── SectionViewType.java
│ │ │ │ └── SlideIssueViewType.java
│ │ │ └── util/
│ │ │ ├── DateUtil.java
│ │ │ ├── DensityUtil.java
│ │ │ ├── DictParser.java
│ │ │ ├── IOUtil.java
│ │ │ ├── JsonUtil.java
│ │ │ ├── Keyboard.java
│ │ │ ├── MD5.java
│ │ │ ├── StemUtil.java
│ │ │ ├── ThreadUtil.java
│ │ │ └── Tinter.java
│ │ └── res/
│ │ ├── anim/
│ │ │ ├── slide_in_left.xml
│ │ │ ├── slide_in_right.xml
│ │ │ ├── slide_out_left.xml
│ │ │ └── slide_out_right.xml
│ │ ├── color/
│ │ │ ├── text_color_slide_date.xml
│ │ │ └── text_color_slide_issue.xml
│ │ ├── drawable/
│ │ │ ├── bg_button.xml
│ │ │ ├── bg_button_n.xml
│ │ │ ├── bg_button_s.xml
│ │ │ ├── bg_dialog.xml
│ │ │ └── ic_slide_menu.xml
│ │ ├── layout/
│ │ │ ├── activity_about.xml
│ │ │ ├── activity_article.xml
│ │ │ ├── activity_favorite.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_search.xml
│ │ │ ├── activity_search_result.xml
│ │ │ ├── item_article.xml
│ │ │ ├── item_search_history.xml
│ │ │ ├── item_section.xml
│ │ │ ├── item_slide_issue.xml
│ │ │ ├── view_navi_bar.xml
│ │ │ └── view_translate.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── ids.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── com/
│ └── github/
│ └── mzule/
│ └── androidweekly/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── snowball/
├── .gitignore
├── build.gradle
└── src/
└── main/
└── java/
└── org/
└── tartarus/
└── snowball/
├── Among.java
├── SnowballProgram.java
├── SnowballStemmer.java
├── TestApp.java
└── ext/
└── EnglishStem.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
.idea
.DS_Store
/build
/captures
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.
================================================
FILE: README.md
================================================
# AndroidWeekly
一个第三方 androidweekly.net 的客户端,主要用 jsoup 抓取了 androidweekly.net 的数据进行展示,很适合在空暇时间阅读浏览。
## 目前实现的功能
1. 文章列表
2. 文章页面
3. 收藏文章
4. 调整文章字体大小
5. 文章页面内建词典
6. 文章分享
7. 已读文章全文搜索
8. 收藏导入导出
欢迎提 pull request 或 issue 添加新功能,修 bug.
## 下载
[https://github.com/mzule/AndroidWeekly/releases](https://github.com/mzule/AndroidWeekly/releases)
## 运行效果






## 感谢
本项目用了部分开源项目,在此感谢。
* [ButterKnife](https://github.com/JakeWharton/butterknife)
* [EasyAdapter](https://github.com/mzule/EasyAdapter)
* [glide](https://github.com/bumptech/glide)
* [gson](https://github.com/google/gson)
* [jsoup](http://jsoup.org/)
* [LayoutAnnotation](https://github.com/mzule/LayoutAnnotation)
* [material-icon-lib](https://github.com/code-mc/material-icon-lib)
* [materialish-progress](https://github.com/pnikosis/materialish-progress)
* [Snowball](http://snowballstem.org/)
## 许可
Apache License 2.0
*不可发布到应用市场*
## 联系我
任何相关问题都可以通过以下方式联系我。
1. 提 issue
1. 新浪微博 [http://weibo.com/mzule](http://weibo.com/mzule)
1. 个人博客 [http://caodongping.me](http://caodongping.me)
1. 邮件 "mzule".concat("4j").concat("@").concat("gmail.com")
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'android-apt'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.github.mzule.androidweekly"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.github.mzule.easyadapter:easyadapter:1.1.1'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'org.jsoup:jsoup:1.8.3'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.google.code.gson:gson:2.5'
compile 'net.steamcrafted:materialiconlib:1.0.9'
compile 'com.pnikosis:materialish-progress:1.7'
compile project(':snowball')
compile 'com.github.mzule.layoutannotation:library:1.0.4'
apt 'com.github.mzule.layoutannotation:compiler:1.0.3'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/baidu/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/androidTest/java/com/github/mzule/androidweekly/ApplicationTest.java
================================================
package com.github.mzule.androidweekly;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.mzule.androidweekly">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.activity.ArticleActivity" />
<activity android:name=".ui.activity.FavoriteActivity" />
<activity android:name=".ui.activity.AboutActivity" />
<activity
android:name=".ui.activity.SearchActivity"
android:windowSoftInputMode="stateAlwaysVisible" />
<activity android:name=".ui.activity.SearchResultActivity" />
</application>
</manifest>
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/App.java
================================================
package com.github.mzule.androidweekly;
import android.app.Application;
/**
* Created by CaoDongping on 3/24/16.
*/
public class App extends Application {
private static App instance;
public static App getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/ApiCallback.java
================================================
package com.github.mzule.androidweekly.api;
/**
* Created by CaoDongping on 3/24/16.
*/
public interface ApiCallback<T> {
void onSuccess(T data, boolean fromCache);
void onFailure(Exception e);
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/ArticleApi.java
================================================
package com.github.mzule.androidweekly.api;
import android.os.Handler;
import android.text.TextUtils;
import com.github.mzule.androidweekly.api.parser.ArticleParsers;
import com.github.mzule.androidweekly.dao.ArticleDao;
import com.github.mzule.androidweekly.dao.IssueListKeeper;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.entity.Issue;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Created by mzule on 3/16/16.
*/
public class ArticleApi {
//TODO new thread to threadhandler
private Handler handler = new Handler();
private ArticleDao articleDao;
public ArticleApi() {
articleDao = new ArticleDao();
}
public void getPage(final String issue, final ApiCallback<List<Object>> callback) {
new Thread() {
@Override
public void run() {
try {
if (!readCache()) {
postSuccess(doGetPage(issue), callback);
}
} catch (final Exception e) {
postError(e, callback);
}
}
private boolean readCache() {
if (!TextUtils.isEmpty(issue)) {
List<Article> articles = articleDao.read(issue);
if (!articles.isEmpty()) {
postSuccess(new Response<>(make(articles), true), callback);
return true;
}
}
return false;
}
private List<Object> make(List<Article> articles) {
List<Object> ret = new ArrayList<>();
for (Article article : articles) {
if (!ret.contains(article.getSection())) {
ret.add(article.getSection());
}
ret.add(article);
}
return ret;
}
}.start();
}
public void getArchive(final ApiCallback<List<Issue>> callback) {
new Thread() {
@Override
public void run() {
try {
List<Issue> issues = IssueListKeeper.read();
if (issues != null && !issues.isEmpty()) {
postSuccess(new Response<>(issues, true), callback);
}
postSuccess(doGetArchive(), callback);
} catch (Exception e) {
postError(e, callback);
}
}
}.start();
}
private Response<List<Issue>> doGetArchive() throws Exception {
Document doc = Jsoup.parse(new URL("http://androidweekly.net/archive"), 30000);
Elements lis = doc.getElementsByClass("archive-list").get(0).getElementsByTag("li");
List<Issue> issues = new ArrayList<>();
for (Element li : lis) {
String date = li.getElementsByTag("span").get(0).text();
String name = li.getElementsByTag("h3").text().split("\\|")[0];
String url = li.getElementsByTag("a").attr("href");
issues.add(new Issue(name, url, date));
}
IssueListKeeper.save(issues);
return new Response<>(issues, false);
}
private Response<List<Object>> doGetPage(String issue) throws Exception {
List<Object> result = ArticleParsers.get(issue).parse(issue);
for (Object obj : result) {
if (obj instanceof Article) {
articleDao.save((Article) obj);
}
}
return new Response<>(result, false);
}
private <T> void postSuccess(final Response<T> result, final ApiCallback<T> callback) {
handler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(result.data, result.fromCache);
}
});
}
private <T> void postError(final Exception e, final ApiCallback<T> callback) {
e.printStackTrace();
handler.post(new Runnable() {
@Override
public void run() {
callback.onFailure(e);
}
});
}
static class Response<T> {
public T data;
public boolean fromCache;
public Response(T data, boolean fromCache) {
this.data = data;
this.fromCache = fromCache;
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/DictionaryApi.java
================================================
package com.github.mzule.androidweekly.api;
import android.os.Handler;
import com.github.mzule.androidweekly.entity.Dict;
import com.github.mzule.androidweekly.util.DictParser;
import java.net.URLEncoder;
/**
* Created by CaoDongping on 3/31/16.
*/
public class DictionaryApi {
private Handler handler = new Handler();
public void look(String q, final ApiCallback<Dict> callback) {
final String url = "http://dict-co.iciba.com/api/dictionary.php?w=" + URLEncoder.encode(q) + "&key=A3950A86AC38B86FCDEE6EAC68931C25&type=xml";
new Thread(new Runnable() {
@Override
public void run() {
try {
final Dict result = new DictParser(url).parse();
handler.post(new Runnable() {
@Override
public void run() {
callback.onSuccess(result, false);
}
});
} catch (final Exception e) {
e.printStackTrace();
handler.post(new Runnable() {
@Override
public void run() {
callback.onFailure(e);
}
});
}
}
}).start();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParser.java
================================================
package com.github.mzule.androidweekly.api.parser;
import java.io.IOException;
import java.util.List;
/**
* Created by CaoDongping on 4/15/16.
*/
public interface ArticleParser {
List<Object> parse(String issue) throws IOException;
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParsers.java
================================================
package com.github.mzule.androidweekly.api.parser;
import android.support.annotation.WorkerThread;
/**
* Created by CaoDongping on 4/15/16.
*/
public class ArticleParsers {
@WorkerThread
public static ArticleParser get(String issue) {
if (issue == null || Integer.parseInt(issue.split("-")[1]) > 102) {
return new FresherArticlesParser();
} else {
return new OlderArticlesParser();
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/DocumentProvider.java
================================================
package com.github.mzule.androidweekly.api.parser;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.net.URL;
/**
* Created by CaoDongping on 4/15/16.
*/
public class DocumentProvider {
public static Document get(String issue) throws IOException {
String url = "http://androidweekly.net/";
if (issue != null) {
url += issue;
}
return Jsoup.parse(new URL(url), 30000);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/FresherArticlesParser.java
================================================
package com.github.mzule.androidweekly.api.parser;
import com.github.mzule.androidweekly.entity.Article;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 4/15/16.
*/
public class FresherArticlesParser implements ArticleParser {
@Override
public List<Object> parse(String issue) throws IOException {
Document doc = DocumentProvider.get(issue);
List<Object> articles = new ArrayList<>();
Elements tables = doc.getElementsByTag("table");
String currentSection = null;
for (Element e : tables) {
Elements h2 = e.getElementsByTag("h2");
Elements h5 = e.getElementsByTag("h5");// 兼容issue-226 SPONSORED 在 h5 标签里面
if (!h2.isEmpty() || !h5.isEmpty()) {
currentSection = h2.size() > 0 ? h2.get(0).text() : h5.get(0).text();
if (!articles.contains(currentSection)) {
articles.add(currentSection);
}
} else {
Elements tds = e.getElementsByTag("td");
Element td = tds.get(tds.size() - 2);
String imageUrl = null;
if (tds.size() == 4) {
imageUrl = tds.get(0).getElementsByTag("img").get(0).attr("src");
}
String title = td.getElementsByClass("article-headline").get(0).text();
String brief = td.getElementsByTag("p").get(0).text();
String link = td.getElementsByClass("article-headline").get(0).attr("href");
String domain = td.getElementsByTag("span").get(0).text().replace("(", "").replace(")", "");
if (issue == null) {
String number = doc.getElementsByClass("issue-header").get(0).getElementsByTag("span").get(0).text();
issue = "/issues/issue-" + number.replace("#", "");
}
Article article = new Article();
article.setTitle(title);
article.setBrief(brief);
article.setLink(link);
article.setDomain(domain);
article.setIssue(issue);
article.setImageUrl(imageUrl);
article.setSection(currentSection);
articles.add(article);
}
}
return articles;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/OlderArticlesParser.java
================================================
package com.github.mzule.androidweekly.api.parser;
import com.github.mzule.androidweekly.entity.Article;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 4/15/16.
*/
public class OlderArticlesParser implements ArticleParser {
@Override
public List<Object> parse(String issue) throws IOException {
Document doc = DocumentProvider.get(issue);
List<Object> articles = new ArrayList<>();
Element root = doc.getElementsByClass("issue").get(0);
while (root.children().size() == 1) {
root = root.child(0);
}
String currentSection = null;
for (Element e : root.children()) {
if (e.tagName().equals("h2")) {
currentSection = e.text();
articles.add(currentSection);
continue;
}
if (e.tagName().equals("div")) {
Elements img = e.getElementsByTag("img");
if (!img.isEmpty()) {
Article article = new Article();
article.setImageUrl(img.get(0).attr("src"));
article.setTitle(e.getElementsByTag("a").get(1).text());
article.setLink(e.getElementsByTag("a").get(1).attr("href"));
article.setBrief(e.getElementsByTag("p").get(0).text());
Elements span = e.getElementsByTag("span");
if (!span.isEmpty()) {
article.setDomain(span.get(0).text().replace("(", "").replace(")", ""));
}
article.setIssue(issue);
article.setSection(currentSection);
articles.add(article);
}
} else {
Article article = new Article();
Elements title = e.getElementsByTag("a");
if (title.isEmpty()) {
continue;
}
article.setTitle(title.get(0).text());
Elements span = e.getElementsByTag("span");
if (!span.isEmpty()) {
article.setDomain(span.get(0).text().replace("(", "").replace(")", ""));
}
article.setLink(e.getElementsByTag("a").get(0).attr("href"));
article.setBrief(e.text());
article.setIssue(issue);
article.setSection(currentSection);
articles.add(article);
}
}
return articles;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/ArticleDao.java
================================================
package com.github.mzule.androidweekly.dao;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import com.github.mzule.androidweekly.App;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.util.StemUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 4/2/16.
*/
public class ArticleDao extends SQLiteOpenHelper {
private static final String NAME = "article";
private static final int VERSION = 1;
private static final int INDEX_TITLE = 1;
private static final int INDEX_BRIEF = 2;
private static final int INDEX_LINK = 3;
private static final int INDEX_IMAGE_URL = 4;
private static final int INDEX_DOMAIN = 5;
private static final int INDEX_ISSUE = 6;
private static final int INDEX_SECTION = 7;
public ArticleDao() {
super(App.getInstance(), NAME, null, VERSION);
}
public List<Article> read(String issue) {
List<Article> articles = new ArrayList<>();
Cursor cursor = getReadableDatabase().rawQuery("SELECT * FROM ARTICLE WHERE ISSUE=?", new String[]{issue});
while (cursor.moveToNext()) {
articles.add(read(cursor));
}
cursor.close();
return articles;
}
public List<Article> search(String q) {
q = StemUtil.stem(q);
List<Article> articles = new ArrayList<>();
Cursor cursor = getReadableDatabase().rawQuery("SELECT * FROM ARTICLE WHERE FTS MATCH ?", new String[]{q});
while (cursor.moveToNext()) {
articles.add(read(cursor));
}
cursor.close();
return articles;
}
@NonNull
private Article read(Cursor cursor) {
Article article = new Article();
article.setTitle(cursor.getString(INDEX_TITLE));
article.setBrief(cursor.getString(INDEX_BRIEF));
article.setLink(cursor.getString(INDEX_LINK));
article.setImageUrl(cursor.getString(INDEX_IMAGE_URL));
article.setDomain(cursor.getString(INDEX_DOMAIN));
article.setIssue(cursor.getString(INDEX_ISSUE));
article.setSection(cursor.getString(INDEX_SECTION));
return article;
}
public void save(Article article) {
if (!checkExist(article)) {
ContentValues cv = new ContentValues();
cv.put("TITLE", article.getTitle());
cv.put("BRIEF", article.getBrief());
cv.put("LINK", article.getLink());
cv.put("IMAGE_URL", article.getImageUrl());
cv.put("DOMAIN", article.getDomain());
cv.put("ISSUE", article.getIssue());
cv.put("SECTION", article.getSection());
cv.put("TYPE", 0);// TODO add type for article
cv.put("FTS", StemUtil.stem(article.getFTS()));
getWritableDatabase().insert("ARTICLE", null, cv);
}
}
private boolean checkExist(Article article) {
Cursor cursor = getReadableDatabase().rawQuery("SELECT COUNT(*) FROM ARTICLE WHERE LINK=?", new String[]{article.getLink()});
cursor.moveToNext();
int count = cursor.getInt(0);
cursor.close();
return count > 0;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE VIRTUAL TABLE ARTICLE USING fts3(" +
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
"TITLE VARCHAR(255), " +
"BRIEF TEXT, " +
"LINK VARCHAR(255), " +
"IMAGE_URL VARCHAR(255), " +
"DOMAIN VARCHAR(255), " +
"ISSUE VARCHAR(255), " +
"SECTION VARCHAR(255), " +
"TYPE INTEGER, " +
"FTS TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/FavoriteDao.java
================================================
package com.github.mzule.androidweekly.dao;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import com.github.mzule.androidweekly.App;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.entity.Favorite;
import com.github.mzule.androidweekly.util.IOUtil;
import com.github.mzule.androidweekly.util.JsonUtil;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 4/2/16.
*/
public class FavoriteDao extends SQLiteOpenHelper {
private static final String NAME = "favorite";
private static final int VERSION = 1;
private static final int INDEX_TITLE = 1;
private static final int INDEX_BRIEF = 2;
private static final int INDEX_LINK = 3;
private static final int INDEX_IMAGE_URL = 4;
private static final int INDEX_DOMAIN = 5;
private static final int INDEX_ISSUE = 6;
private static final int INDEX_SECTION = 7;
private static final int INDEX_TYPE = 8;
private static final int INDEX_TIME = 9;
public FavoriteDao() {
super(App.getInstance(), NAME, null, VERSION);
}
public List<Favorite> read() {
List<Favorite> favorites = new ArrayList<>();
Cursor cursor = getReadableDatabase().rawQuery("SELECT * FROM FAVORITE ORDER BY TIME DESC", null);
while (cursor.moveToNext()) {
Article article = new Article();
article.setTitle(cursor.getString(INDEX_TITLE));
article.setBrief(cursor.getString(INDEX_BRIEF));
article.setLink(cursor.getString(INDEX_LINK));
article.setImageUrl(cursor.getString(INDEX_IMAGE_URL));
article.setDomain(cursor.getString(INDEX_DOMAIN));
article.setIssue(cursor.getString(INDEX_ISSUE));
article.setSection(cursor.getString(INDEX_SECTION));
Favorite favorite = new Favorite(article);
favorite.setTime(cursor.getLong(INDEX_TIME));
favorites.add(favorite);
}
cursor.close();
return favorites;
}
public boolean contains(Article article) {
Cursor cursor = getReadableDatabase().rawQuery("SELECT COUNT(*) FROM FAVORITE WHERE LINK=?", new String[]{article.getLink()});
cursor.moveToNext();
int count = cursor.getInt(0);
cursor.close();
return count > 0;
}
public void save(Article article) {
if (!contains(article)) {
ContentValues cv = new ContentValues();
cv.put("TITLE", article.getTitle());
cv.put("BRIEF", article.getBrief());
cv.put("LINK", article.getLink());
cv.put("IMAGE_URL", article.getImageUrl());
cv.put("DOMAIN", article.getDomain());
cv.put("ISSUE", article.getIssue());
cv.put("SECTION", article.getSection());
cv.put("TYPE", 0);// TODO add type for article
cv.put("TIME", System.currentTimeMillis());
getWritableDatabase().insert("FAVORITE", null, cv);
}
}
public void save(Favorite favorite) {
Article article = favorite.getArticle();
if (!contains(article)) {
ContentValues cv = new ContentValues();
cv.put("TITLE", article.getTitle());
cv.put("BRIEF", article.getBrief());
cv.put("LINK", article.getLink());
cv.put("IMAGE_URL", article.getImageUrl());
cv.put("DOMAIN", article.getDomain());
cv.put("ISSUE", article.getIssue());
cv.put("SECTION", article.getSection());
cv.put("TYPE", 0);// TODO add type for article
cv.put("TIME", favorite.getTime());
getWritableDatabase().insert("FAVORITE", null, cv);
}
}
public void delete(Article article) {
getWritableDatabase().delete("FAVORITE", "LINK=?", new String[]{article.getLink()});
}
public void exportToFile() throws IOException {
List<Favorite> all = read();
String json = JsonUtil.toJson(all);
File file = new File(Environment.getExternalStorageDirectory(), "androidweeklyfavorite.json");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(file);
fileWriter.write(json);
fileWriter.flush();
} finally {
IOUtil.close(fileWriter);
}
}
public void importFromFile() throws IOException {
File file = new File(Environment.getExternalStorageDirectory(), "androidweeklyfavorite.json");
String json = IOUtil.read(file);
List<Favorite> favorites = JsonUtil.fromJson(json, new TypeToken<List<Favorite>>() {
}.getType());
if (favorites != null) {
for (Favorite favorite : favorites) {
save(favorite);
}
}
}
@Override
public void onCreate(SQLiteDatabase db) {
// 不创建一个与Article的外键引用是因为Article表是cache,可能会被清除。
db.execSQL("CREATE TABLE IF NOT EXISTS FAVORITE(" +
"ID INTEGER PRIMARY KEY AUTOINCREMENT, " +
"TITLE VARCHAR(255), " +
"BRIEF TEXT, " +
"LINK VARCHAR(255), " +
"IMAGE_URL VARCHAR(255), " +
"DOMAIN VARCHAR(255), " +
"ISSUE VARCHAR(255), " +
"SECTION VARCHAR(255), " +
"TYPE INTEGER, " +
"TIME INTEGER)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/IssueListKeeper.java
================================================
package com.github.mzule.androidweekly.dao;
import android.content.Context;
import android.content.SharedPreferences;
import com.github.mzule.androidweekly.App;
import com.github.mzule.androidweekly.entity.Issue;
import com.github.mzule.androidweekly.util.JsonUtil;
import com.google.gson.reflect.TypeToken;
import java.util.Collections;
import java.util.List;
/**
* Created by CaoDongping on 4/2/16.
*/
public class IssueListKeeper {
public static void save(List<Issue> issues) {
getSharedPreferences().edit().putString("issues", JsonUtil.toJson(issues)).apply();
}
public static List<Issue> read() {
String json = getSharedPreferences().getString("issues", null);
List<Issue> issues = JsonUtil.fromJson(json, new TypeToken<List<Issue>>() {
}.getType());
return issues == null ? Collections.<Issue>emptyList() : issues;
}
private static SharedPreferences getSharedPreferences() {
return App.getInstance().getSharedPreferences("IssueList", Context.MODE_PRIVATE);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/SearchHistoryKeeper.java
================================================
package com.github.mzule.androidweekly.dao;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import com.github.mzule.androidweekly.App;
import com.github.mzule.androidweekly.util.JsonUtil;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 4/5/16.
*/
public class SearchHistoryKeeper {
private static final int MAX_SIZE = 5;
public static void save(String q) {
List<String> exist = read();
if (exist.contains(q)) {
exist.remove(q);
}
exist.add(0, q);
if (exist.size() > MAX_SIZE) {
exist = exist.subList(0, MAX_SIZE);
}
getSharedPreferences().edit().putString("q", JsonUtil.toJson(exist)).apply();
}
public static List<String> read() {
String json = getSharedPreferences().getString("q", null);
if (TextUtils.isEmpty(json)) {
return new ArrayList<>();
} else {
return JsonUtil.fromJson(json, new TypeToken<List<String>>() {
}.getType());
}
}
private static SharedPreferences getSharedPreferences() {
return App.getInstance().getSharedPreferences("SearchHistory", Context.MODE_PRIVATE);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/TextZoomKeeper.java
================================================
package com.github.mzule.androidweekly.dao;
import android.content.Context;
import android.content.SharedPreferences;
import com.github.mzule.androidweekly.App;
/**
* Created by CaoDongping on 3/26/16.
*/
public class TextZoomKeeper {
public static void save(int zoom) {
getSharedPreferences().edit().putInt("zoom", zoom).apply();
}
public static int read(int def) {
return getSharedPreferences().getInt("zoom", def);
}
private static SharedPreferences getSharedPreferences() {
return App.getInstance().getSharedPreferences("TextZoom", Context.MODE_PRIVATE);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Article.java
================================================
package com.github.mzule.androidweekly.entity;
import java.io.Serializable;
import java.util.Arrays;
/**
* Created by CaoDongping on 3/24/16.
*/
public class Article implements Serializable {
private String title;
private String brief;
private String link;
private String imageUrl;
private String domain;
private String issue;
private String section;
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public String getIssue() {
return issue;
}
public void setIssue(String issue) {
this.issue = issue;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBrief() {
return brief;
}
public void setBrief(String brief) {
this.brief = brief;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getFTS() {
return title + "\n" + brief;
}
@Override
public String toString() {
return Arrays.toString(new String[]{title, "\n", brief, "\n", link, "\n", imageUrl, "\n", domain, "\n", "\n"});
}
@Override
public int hashCode() {
return link == null ? 0 : link.hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof Article) {
Article other = (Article) o;
return link == null ? other.link == null : link.equals(other.link);
}
return false;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Dict.java
================================================
package com.github.mzule.androidweekly.entity;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by CaoDongping on 3/31/16.
*/
public class Dict {
private String key;
private List<String> ps;
private List<String> pos;
private List<String> pron;
private List<String> acceptation;
private List<Sent> sent;
private String fy;
public Dict() {
ps = new ArrayList<>();
pos = new ArrayList<>();
pron = new ArrayList<>();
acceptation = new ArrayList<>();
sent = new ArrayList<>();
}
public String getContent() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < getPs().size(); i++) {
sb.append(getPs().get(i)).append("\n");
}
if (!TextUtils.isEmpty(getFy())) {
sb.append("\n");
sb.append(getFy()).append("\n");
}
for (int i = 0; i < getPos().size(); i++) {
sb.append("\n");
sb.append(getPos().get(i)).append("\n");
sb.append(getAcceptation().get(i)).append("\n");
}
for (int i = 0; i < getSent().size(); i++) {
sb.append("\n");
sb.append(getSent().get(i).getOrig()).append("\n");
sb.append(getSent().get(i).getTrans()).append("\n");
}
return sb.toString().trim();
}
public void addPos(String pos) {
this.pos.add(pos);
}
public void addAcceptation(String acceptation) {
this.acceptation.add(acceptation);
}
public List<String> getPos() {
return pos;
}
public void setPos(List<String> pos) {
this.pos = pos;
}
public List<String> getAcceptation() {
return acceptation;
}
public void setAcceptation(List<String> acceptation) {
this.acceptation = acceptation;
}
public void addPs(String ps) {
this.ps.add(ps);
}
public void addPron(String pron) {
this.pron.add(pron);
}
public void addSent(Sent sent) {
this.sent.add(sent);
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public List<String> getPs() {
return ps;
}
public void setPs(List<String> ps) {
this.ps = ps;
}
public List<String> getPron() {
return pron;
}
public void setPron(List<String> pron) {
this.pron = pron;
}
public List<Sent> getSent() {
return sent;
}
public void setSent(List<Sent> sent) {
this.sent = sent;
}
public String getFy() {
return fy;
}
public void setFy(String fy) {
this.fy = fy;
}
public static class Sent {
private String orig;
private String trans;
public String getOrig() {
return orig;
}
public void setOrig(String orig) {
this.orig = orig;
}
public String getTrans() {
return trans;
}
public void setTrans(String trans) {
this.trans = trans;
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Favorite.java
================================================
package com.github.mzule.androidweekly.entity;
import java.io.Serializable;
/**
* Created by CaoDongping on 3/28/16.
*/
public class Favorite implements Serializable {
private Article article;
private long time;
public Favorite(Article article) {
this.article = article;
this.time = System.currentTimeMillis();
}
public Article getArticle() {
return article;
}
public void setArticle(Article article) {
this.article = article;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
@Override
public boolean equals(Object o) {
return o instanceof Favorite && article.equals(((Favorite) o).article);
}
@Override
public int hashCode() {
return article.hashCode();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Issue.java
================================================
package com.github.mzule.androidweekly.entity;
import java.io.Serializable;
/**
* Created by CaoDongping on 3/25/16.
*/
public class Issue implements Serializable {
private String date;
private String name;
private String url;
private boolean active;
public Issue(String name) {
this.name = name;
}
public Issue(String name, boolean active) {
this.name = name;
this.active = active;
}
public Issue(String name, String url, String date) {
this.name = name;
this.url = url;
this.date = date;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/TranslateResult.java
================================================
package com.github.mzule.androidweekly.entity;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by CaoDongping on 3/30/16.
*/
public class TranslateResult {
private String from;
private String to;
@SerializedName("trans_result")
private List<Result> result;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
public String getDst() {
if (getResult() != null && !getResult().isEmpty()) {
return getResult().get(0).getDst();
}
return null;
}
public static class Result {
private String src;
private String dst;
public Result(String src, String dst) {
this.src = src;
this.dst = dst;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getDst() {
return dst;
}
public void setDst(String dst) {
this.dst = dst;
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/AboutActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
/**
* Created by CaoDongping on 4/12/16.
*/
@Layout(R.layout.activity_about)
public class AboutActivity extends BaseActivity {
@Bind(R.id.textView)
TextView textView;
public static Intent makeIntent(Context context) {
return new Intent(context, AboutActivity.class);
}
@Override
protected void afterBind() {
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(Html.fromHtml("Copyright: <br/><a href='http://androidweekly.net/'>http://androidweekly.net/</a><br/>" +
"Github Host: <br/><a href='https://github.com/mzule/AndroidWeekly'>https://github.com/mzule/AndroidWeekly</a><br/>" +
"Contributor:<br/> <a href='sinaweibo://userinfo?uid=mzule'>mzule</a> / <a href='sinaweibo://userinfo?uid=maoruibin'>maoruibin</a> "));
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/ArticleActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.dao.FavoriteDao;
import com.github.mzule.androidweekly.dao.TextZoomKeeper;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.ui.view.ProgressView;
import com.github.mzule.androidweekly.ui.view.TranslateView;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
import butterknife.OnClick;
/**
* Created by CaoDongping on 3/24/16.
*/
@Layout(R.layout.activity_article)
public class ArticleActivity extends BaseActivity {
@Bind(R.id.webView)
WebView webView;
@Bind(R.id.progressView)
ProgressView progressView;
@Bind(R.id.drawerLayout)
DrawerLayout drawerLayout;
@Bind(R.id.favoriteButton)
View favoriteButton;
private Article article;
private WebSettings settings;
private boolean changed;
private FavoriteDao favoriteDao;
public static Intent makeIntent(Context context, Article article) {
Intent intent = new Intent(context, ArticleActivity.class);
intent.putExtra("article", article);
return intent;
}
@OnClick(R.id.favoriteButton)
void favorite(View v) {
changed = true;
v.setSelected(!v.isSelected());
if (v.isSelected()) {
favoriteDao.save(article);
} else {
favoriteDao.delete(article);
}
drawerLayout.closeDrawers();
}
@OnClick(R.id.increaseButton)
void increate() {
settings.setTextZoom(settings.getTextZoom() + 5);
}
@OnClick(R.id.decreaseButton)
void decrease() {
settings.setTextZoom(settings.getTextZoom() - 5);
}
@OnClick(R.id.translateButton)
void translateAndPaste(View v) {
new TranslateView(this).attachTo(this, null);
drawerLayout.closeDrawers();
}
@OnClick(R.id.shareButton)
void share() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, article.getTitle() + " " + article.getLink());
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, "SHARE"));
drawerLayout.closeDrawers();
}
@OnClick(R.id.copyUrlButton)
void copyUrl() {
ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label",article.getLink());
clipboard.setPrimaryClip(clip);
drawerLayout.closeDrawers();
Toast.makeText(ArticleActivity.this, "已复制文章链接到粘贴板", Toast.LENGTH_SHORT).show();
}
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void afterBind() {
favoriteDao = new FavoriteDao();
article = (Article) getIntent().getSerializableExtra("article");
settings = webView.getSettings();
webView.loadUrl(article.getLink());
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
progressView.stop();
}
});
settings.setTextZoom(TextZoomKeeper.read(settings.getTextZoom()));
settings.setJavaScriptEnabled(true);
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
settings.setDomStorageEnabled(true);
favoriteButton.setSelected(favoriteDao.contains(article));
}
@Override
protected void onStop() {
super.onStop();
TextZoomKeeper.save(settings.getTextZoom());
}
@Override
public void finish() {
Intent intent = new Intent();
intent.putExtra("changed", changed);
setResult(RESULT_OK, intent);
super.finish();
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawers();
} else if (webView.canGoBack()) {
webView.goBack();
} else {
super.onBackPressed();
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/BaseActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.ui.view.PopupView;
import com.github.mzule.androidweekly.util.Tinter;
import com.github.mzule.layoutannotation.LayoutBinder;
import butterknife.ButterKnife;
/**
* Created by CaoDongping on 3/24/16.
*/
public abstract class BaseActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutBinder.bind(this);
ButterKnife.bind(this);
Tinter.enableIfSupport(this);
afterBind();
}
public void back(View v) {
onBackPressed();
}
@Override
public void onBackPressed() {
PopupView popupView = (PopupView) findViewById(R.id.popup_view_id);
if (popupView == null) {
super.onBackPressed();
} else {
popupView.finish();
}
}
protected abstract void afterBind();
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/FavoriteActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.content.Context;
import android.content.Intent;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.dao.FavoriteDao;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.entity.Favorite;
import com.github.mzule.androidweekly.ui.adapter.ArticleAdapter;
import com.github.mzule.androidweekly.util.DateUtil;
import com.github.mzule.layoutannotation.Layout;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.OnClick;
import butterknife.OnItemClick;
/**
* Created by CaoDongping on 3/28/16.
*/
@Layout(R.layout.activity_favorite)
public class FavoriteActivity extends BaseActivity {
private static final int REQUEST_CODE_OPEN_ARTICLE = 0x1;
@Bind(R.id.drawerLayout)
DrawerLayout drawerLayout;
@Bind(R.id.listView)
ListView listView;
private FavoriteDao favoriteDao;
private ArticleAdapter adapter;
public static Intent makeIntent(Context context) {
return new Intent(context, FavoriteActivity.class);
}
@OnItemClick(R.id.listView)
void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object item = parent.getAdapter().getItem(position);
if (item instanceof Article) {
startActivityForResult(ArticleActivity.makeIntent(this, (Article) item), REQUEST_CODE_OPEN_ARTICLE);
}
}
@OnClick(R.id.exportButton)
void exportToFile() {
try {
favoriteDao.exportToFile();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(this, "Export complete", Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
}
@OnClick(R.id.importButton)
void importFromFile() {
try {
favoriteDao.importFromFile();
} catch (IOException e) {
e.printStackTrace();
}
adapter.clear();
adapter.addAndNotify(extract(favoriteDao.read()));
Toast.makeText(this, "Import complete", Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
}
@Override
protected void afterBind() {
favoriteDao = new FavoriteDao();
adapter = new ArticleAdapter(this);
listView.setAdapter(adapter);
renderFavorites();
}
private void renderFavorites() {
List<Favorite> favorites = favoriteDao.read();
adapter.clear();
adapter.addAndNotify(extract(favorites));
}
private List<Object> extract(List<Favorite> favorites) {
List<Object> ret = new ArrayList<>();
for (Favorite favorite : favorites) {
String time = DateUtil.format(favorite.getTime());
if (!ret.contains(time)) {
ret.add(time);
}
ret.add(favorite.getArticle());
}
return ret;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_OPEN_ARTICLE) {
if (data.getBooleanExtra("changed", false)) {
renderFavorites();
}
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/MainActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.api.ApiCallback;
import com.github.mzule.androidweekly.api.ArticleApi;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.entity.Issue;
import com.github.mzule.androidweekly.ui.adapter.ArticleAdapter;
import com.github.mzule.androidweekly.ui.adapter.SlideAdapter;
import com.github.mzule.androidweekly.ui.view.ProgressView;
import com.github.mzule.layoutannotation.Layout;
import java.util.List;
import butterknife.Bind;
import butterknife.OnClick;
import butterknife.OnItemClick;
@Layout(R.layout.activity_main)
public class MainActivity extends BaseActivity {
@Bind(R.id.drawerLayout)
DrawerLayout drawerLayout;
@Bind(R.id.listView)
ListView listView;
@Bind(R.id.progressView)
ProgressView progressView;
@Bind(R.id.slideListView)
ListView slideListView;
private ArticleAdapter adapter;
private SlideAdapter slideAdapter;
private List<Issue> issues;
private ArticleApi articleApi;
@OnItemClick(R.id.slideListView)
void onSlideItemClick(AdapterView<?> parent, View view, int position, long id) {
Issue issue = (Issue) parent.getAdapter().getItem(position);
active(issue);
slideAdapter.notifyDataSetChanged();
sendArticleListRequest(issue.getUrl());
drawerLayout.closeDrawers();
progressView.start();
}
@OnItemClick(R.id.listView)
void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object item = parent.getAdapter().getItem(position);
if (item instanceof Article) {
startActivity(ArticleActivity.makeIntent(this, (Article) item));
}
}
@OnClick(R.id.slideMenuButton)
void onSlideMenuClick() {
drawerLayout.openDrawer(GravityCompat.START);
}
@OnClick(R.id.favoriteButton)
void onFavoriteClick() {
startActivity(FavoriteActivity.makeIntent(this));
drawerLayout.closeDrawers();
}
@OnClick(R.id.searchButton)
void onSearchClicK() {
startActivity(SearchActivity.makeIntent(this));
drawerLayout.closeDrawers();
}
@OnClick(R.id.aboutButton)
void onAboutClick() {
startActivity(AboutActivity.makeIntent(this));
drawerLayout.closeDrawers();
}
@Override
protected void afterBind() {
articleApi = new ArticleApi();
adapter = new ArticleAdapter(this);
listView.setAdapter(adapter);
slideAdapter = new SlideAdapter(this);
slideListView.setAdapter(slideAdapter);
sendArticleListRequest(null);
sendIssueListRequest();
}
private void active(Issue issue) {
for (Issue i : issues) {
i.setActive(i == issue);
}
}
private void sendArticleListRequest(String issue) {
articleApi.getPage(issue, new ApiCallback<List<Object>>() {
@Override
public void onSuccess(List<Object> data, boolean fromCache) {
adapter.clear();
adapter.addAndNotify(data);
listView.setSelection(0);
progressView.stop();
}
@Override
public void onFailure(Exception e) {
progressView.stop();
}
});
}
private void sendIssueListRequest() {
articleApi.getArchive(new ApiCallback<List<Issue>>() {
@Override
public void onSuccess(List<Issue> data, boolean fromCache) {
issues = data;
slideAdapter.clear();
slideAdapter.addAndNotify(issues);
active(issues.get(0));
}
@Override
public void onFailure(Exception e) {
}
});
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawers();
} else {
super.onBackPressed();
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.content.Context;
import android.content.Intent;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.dao.SearchHistoryKeeper;
import com.github.mzule.androidweekly.ui.adapter.SearchHistoryAdapter;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
import butterknife.OnItemClick;
/**
* Created by CaoDongping on 4/5/16.
*/
@Layout(R.layout.activity_search)
public class SearchActivity extends BaseActivity {
@Bind(R.id.queryInput)
EditText queryInput;
@Bind(R.id.listView)
ListView listView;
private SearchHistoryAdapter adapter;
public static Intent makeIntent(Context context) {
return new Intent(context, SearchActivity.class);
}
@OnItemClick(R.id.listView)
void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String q = (String) parent.getAdapter().getItem(position);
SearchHistoryKeeper.save(q);
startActivity(SearchResultActivity.makeIntent(this, q));
}
@Override
protected void afterBind() {
adapter = new SearchHistoryAdapter(this);
listView.setAdapter(adapter);
queryInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
String q = queryInput.getText().toString().trim();
startActivity(SearchResultActivity.makeIntent(SearchActivity.this, q));
SearchHistoryKeeper.save(q);
queryInput.setText("");
return true;
}
});
}
@Override
protected void onStart() {
super.onStart();
adapter.clear();
adapter.addAndNotify(SearchHistoryKeeper.read());
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchResultActivity.java
================================================
package com.github.mzule.androidweekly.ui.activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.dao.ArticleDao;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.ui.adapter.ArticleAdapter;
import com.github.mzule.androidweekly.ui.view.NaviBar;
import com.github.mzule.layoutannotation.Layout;
import java.util.List;
import butterknife.Bind;
import butterknife.OnItemClick;
/**
* Created by CaoDongping on 4/5/16.
*/
@Layout(R.layout.activity_search_result)
public class SearchResultActivity extends BaseActivity {
@Bind(R.id.naviBar)
NaviBar naviBar;
@Bind(R.id.listView)
ListView listView;
public static Intent makeIntent(Context context, String q) {
Intent intent = new Intent(context, SearchResultActivity.class);
intent.putExtra("q", q);
return intent;
}
@OnItemClick(R.id.listView)
void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object item = parent.getAdapter().getItem(position);
if (item instanceof Article) {
startActivity(ArticleActivity.makeIntent(this, (Article) item));
}
}
@Override
protected void afterBind() {
String q = getIntent().getStringExtra("q");
naviBar.setLeftText(q.toUpperCase());
ArticleDao articleDao = new ArticleDao();
List<Article> result = articleDao.search(q);
ArticleAdapter adapter = new ArticleAdapter(this);
listView.setAdapter(adapter);
adapter.addAndNotify(result);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/ArticleAdapter.java
================================================
package com.github.mzule.androidweekly.ui.adapter;
import android.content.Context;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.androidweekly.ui.view.PinnedSectionListView;
import com.github.mzule.androidweekly.ui.viewtype.ArticleViewType;
import com.github.mzule.androidweekly.ui.viewtype.SectionViewType;
import com.github.mzule.easyadapter.TypePerEntityAdapter;
/**
* Created by CaoDongping on 3/24/16.
*/
public class ArticleAdapter extends TypePerEntityAdapter<Object> implements PinnedSectionListView.PinnedSectionListAdapter {
public ArticleAdapter(Context context) {
super(context);
}
@Override
protected void mapEntityViewTypes() {
mapEntityViewType(String.class, SectionViewType.class);
mapEntityViewType(Article.class, ArticleViewType.class);
}
@Override
public boolean isItemViewTypePinned(int viewType) {
return getRawViewType(SectionViewType.class) == viewType;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SearchHistoryAdapter.java
================================================
package com.github.mzule.androidweekly.ui.adapter;
import android.content.Context;
import com.github.mzule.androidweekly.ui.viewtype.SearchHistoryViewType;
import com.github.mzule.easyadapter.SingleTypeAdapter;
import com.github.mzule.easyadapter.ViewType;
/**
* Created by CaoDongping on 4/5/16.
*/
public class SearchHistoryAdapter extends SingleTypeAdapter<String> {
public SearchHistoryAdapter(Context context) {
super(context);
}
@Override
protected Class<? extends ViewType> singleViewType() {
return SearchHistoryViewType.class;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SlideAdapter.java
================================================
package com.github.mzule.androidweekly.ui.adapter;
import android.content.Context;
import com.github.mzule.androidweekly.entity.Issue;
import com.github.mzule.androidweekly.ui.viewtype.SlideIssueViewType;
import com.github.mzule.easyadapter.SingleTypeAdapter;
import com.github.mzule.easyadapter.ViewType;
/**
* Created by CaoDongping on 3/25/16.
*/
public class SlideAdapter extends SingleTypeAdapter<Issue> {
public SlideAdapter(Context context) {
super(context);
}
@Override
protected Class<? extends ViewType> singleViewType() {
return SlideIssueViewType.class;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/IconButton.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.content.Context;
import android.util.AttributeSet;
import com.github.mzule.androidweekly.R;
import net.steamcrafted.materialiconlib.MaterialIconView;
/**
* Created by CaoDongping on 3/27/16.
*/
public class IconButton extends MaterialIconView {
public IconButton(Context context) {
super(context);
}
public IconButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IconButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
if (pressed) {
setColor(getResources().getColor(R.color.white));
setBackgroundColor(getResources().getColor(R.color.colorPrimary));
} else if (!isSelected()) {
setColor(getResources().getColor(R.color.colorPrimary));
setBackgroundColor(getResources().getColor(R.color.transparent));
}
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
if (selected) {
setColor(getResources().getColor(R.color.white));
setBackgroundResource(R.color.colorPrimary);
} else {
setColor(getResources().getColor(R.color.colorPrimary));
setBackgroundResource(R.color.transparent);
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/NaviBar.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.ui.view.base.BaseLinearLayout;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
import butterknife.OnClick;
/**
* Created by CaoDongping on 4/5/16.
*/
@Layout(R.layout.view_navi_bar)
public class NaviBar extends BaseLinearLayout {
@Bind(R.id.leftTextView)
TextView leftTextView;
@Bind(R.id.rightTextView)
TextView rightTextView;
public NaviBar(Context context) {
super(context);
}
public NaviBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NaviBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void init(Context context, AttributeSet attrs) {
super.init(context, attrs);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.NaviBar);
leftTextView.setText(a.getString(R.styleable.NaviBar_nb_left_text));
rightTextView.setText(a.getString(R.styleable.NaviBar_nb_right_text));
a.recycle();
}
}
@OnClick(R.id.backButton)
void back() {
if (getContext() instanceof Activity) {
((Activity) getContext()).finish();
}
}
public void setLeftText(String text) {
leftTextView.setText(text);
}
public void setRightText(String text) {
rightTextView.setText(text);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/PinnedSectionListView.java
================================================
/*
* Copyright (C) 2013 Sergej Shafarenka, halfbit.de
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file kt 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.github.mzule.androidweekly.ui.view;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AbsListView;
import android.widget.HeaderViewListAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SectionIndexer;
import com.github.mzule.androidweekly.BuildConfig;
/**
* ListView, which is capable to pin section views at its top while the rest is still scrolled.
*/
public class PinnedSectionListView extends ListView {
//-- inner classes
// fields used for handling touch events
private final Rect mTouchRect = new Rect();
private final PointF mTouchPoint = new PointF();
//-- class fields
/**
* Delegating listener, can be null.
*/
OnScrollListener mDelegateOnScrollListener;
/**
* Shadow for being recycled, can be null.
*/
PinnedSection mRecycleSection;
/**
* shadow instance with a pinned view, can be null.
*/
PinnedSection mPinnedSection;
/**
* Pinned view Y-translation. We use it to stick pinned view to the next section.
*/
int mTranslateY;
private int mTouchSlop;
private View mTouchTarget;
private MotionEvent mDownEvent;
// fields used for drawing shadow under a pinned section
private GradientDrawable mShadowDrawable;
private int mSectionsDistanceY;
/**
* Scroll listener which does the magic
*/
private final OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mDelegateOnScrollListener != null) { // delegate
mDelegateOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mDelegateOnScrollListener != null) { // delegate
mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
// get expected adapter or fail fast
ListAdapter adapter = getAdapter();
if (adapter == null || visibleItemCount == 0) return; // nothing to do
final boolean isFirstVisibleItemSection =
isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));
if (isFirstVisibleItemSection) {
View sectionView = getChildAt(0);
if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow
destroyPinnedShadow();
} else { // section doesn't stick to the top, make sure we have a pinned shadow
ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount);
}
} else { // section is not at the first visible position
int sectionPosition = findCurrentSectionPosition(firstVisibleItem);
if (sectionPosition > -1) { // we have section position
ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);
} else { // there is no section for the first visible item, destroy shadow
destroyPinnedShadow();
}
}
}
;
};
/**
* Default change observer.
*/
private final DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
recreatePinnedShadow();
}
;
@Override
public void onInvalidated() {
recreatePinnedShadow();
}
};
private int mShadowHeight;
public PinnedSectionListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
//-- constructors
public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {
if (adapter instanceof HeaderViewListAdapter) {
adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter();
}
return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType);
}
private void initView() {
setOnScrollListener(mOnScrollListener);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
initShadow(false);
}
public void setShadowVisible(boolean visible) {
initShadow(visible);
if (mPinnedSection != null) {
View v = mPinnedSection.view;
invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);
}
}
//-- public API methods
public void initShadow(boolean visible) {
if (visible) {
if (mShadowDrawable == null) {
mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,
new int[]{Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")});
mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);
}
} else {
if (mShadowDrawable != null) {
mShadowDrawable = null;
mShadowHeight = 0;
}
}
}
//-- pinned section drawing methods
/**
* Create shadow wrapper with a pinned view for a view at given position
*/
void createPinnedShadow(int position) {
// try to recycle shadow
PinnedSection pinnedShadow = mRecycleSection;
mRecycleSection = null;
// create new shadow, if needed
if (pinnedShadow == null) pinnedShadow = new PinnedSection();
// request new view using recycled view, if such
View pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this);
// read layout parameters
LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();
if (layoutParams == null) {
layoutParams = (LayoutParams) generateDefaultLayoutParams();
pinnedView.setLayoutParams(layoutParams);
}
int heightMode = MeasureSpec.getMode(layoutParams.height);
int heightSize = MeasureSpec.getSize(layoutParams.height);
if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;
int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();
if (heightSize > maxHeight) heightSize = maxHeight;
// measure & layout
int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);
int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
pinnedView.measure(ws, hs);
pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());
mTranslateY = 0;
// initialize pinned shadow
pinnedShadow.view = pinnedView;
pinnedShadow.position = position;
pinnedShadow.id = getAdapter().getItemId(position);
// store pinned shadow
mPinnedSection = pinnedShadow;
}
/**
* Destroy shadow wrapper for currently pinned view
*/
void destroyPinnedShadow() {
if (mPinnedSection != null) {
// keep shadow for being recycled later
mRecycleSection = mPinnedSection;
mPinnedSection = null;
}
}
/**
* Makes sure we have an actual pinned shadow for given position.
*/
void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {
if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item
destroyPinnedShadow();
return;
}
if (mPinnedSection != null
&& mPinnedSection.position != sectionPosition) { // invalidate shadow, if required
destroyPinnedShadow();
}
if (mPinnedSection == null) { // create shadow, if empty
createPinnedShadow(sectionPosition);
}
// align shadow according to next section position, if needed
int nextPosition = sectionPosition + 1;
if (nextPosition < getCount()) {
int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,
visibleItemCount - (nextPosition - firstVisibleItem));
if (nextSectionPosition > -1) {
View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);
final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();
mSectionsDistanceY = nextSectionView.getTop() - bottom;
if (mSectionsDistanceY < 0) {
// next section overlaps pinned shadow, move it up
mTranslateY = mSectionsDistanceY;
} else {
// next section does not overlap with pinned, stick to top
mTranslateY = 0;
}
} else {
// no other sections are visible, stick to top
mTranslateY = 0;
mSectionsDistanceY = Integer.MAX_VALUE;
}
}
}
int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {
ListAdapter adapter = getAdapter();
int adapterDataCount = adapter.getCount();
if (getLastVisiblePosition() >= adapterDataCount)
return -1; // dataset has changed, no candidate
if (firstVisibleItem + visibleItemCount >= adapterDataCount) {//added to prevent index Outofbound (in case)
visibleItemCount = adapterDataCount - firstVisibleItem;
}
for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {
int position = firstVisibleItem + childIndex;
int viewType = adapter.getItemViewType(position);
if (isItemViewTypePinned(adapter, viewType)) return position;
}
return -1;
}
int findCurrentSectionPosition(int fromPosition) {
ListAdapter adapter = getAdapter();
if (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate
if (adapter instanceof SectionIndexer) {
// try fast way by asking section indexer
SectionIndexer indexer = (SectionIndexer) adapter;
int sectionPosition = indexer.getSectionForPosition(fromPosition);
int itemPosition = indexer.getPositionForSection(sectionPosition);
int typeView = adapter.getItemViewType(itemPosition);
if (isItemViewTypePinned(adapter, typeView)) {
return itemPosition;
} // else, no luck
}
// try slow way by looking through to the next section item above
for (int position = fromPosition; position >= 0; position--) {
int viewType = adapter.getItemViewType(position);
if (isItemViewTypePinned(adapter, viewType)) return position;
}
return -1; // no candidate found
}
void recreatePinnedShadow() {
destroyPinnedShadow();
ListAdapter adapter = getAdapter();
if (adapter != null && adapter.getCount() > 0) {
int firstVisiblePosition = getFirstVisiblePosition();
int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);
if (sectionPosition == -1) return; // no views to pin, exit
ensureShadowForPosition(sectionPosition,
firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);
}
}
@Override
public void setOnScrollListener(OnScrollListener listener) {
if (listener == mOnScrollListener) {
super.setOnScrollListener(listener);
} else {
mDelegateOnScrollListener = listener;
}
}
@Override
public void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
post(new Runnable() {
@Override
public void run() { // restore pinned view after configuration change
recreatePinnedShadow();
}
});
}
@Override
public void setAdapter(ListAdapter adapter) {
// assert adapter in debug mode
if (BuildConfig.DEBUG && adapter != null) {
if (!(adapter instanceof PinnedSectionListAdapter))
throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?");
if (adapter.getViewTypeCount() < 2)
throw new IllegalArgumentException("Does your adapter handle at least two types" +
" of views in getViewTypeCount() method: items and sections?");
}
// unregister observer at old adapter and register on new one
ListAdapter oldAdapter = getAdapter();
if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);
if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);
// destroy pinned shadow, if new adapter is not same as old one
if (oldAdapter != adapter) destroyPinnedShadow();
super.setAdapter(adapter);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (mPinnedSection != null) {
int parentWidth = r - l - getPaddingLeft() - getPaddingRight();
int shadowWidth = mPinnedSection.view.getWidth();
if (parentWidth != shadowWidth) {
recreatePinnedShadow();
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mPinnedSection != null) {
// prepare variables
int pLeft = getListPaddingLeft();
int pTop = getListPaddingTop();
View view = mPinnedSection.view;
// draw child
canvas.save();
int clipHeight = view.getHeight() +
(mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));
canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);
canvas.translate(pLeft, pTop + mTranslateY);
drawChild(canvas, mPinnedSection.view, getDrawingTime());
if (mShadowDrawable != null && mSectionsDistanceY > 0) {
mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),
mPinnedSection.view.getBottom(),
mPinnedSection.view.getRight(),
mPinnedSection.view.getBottom() + mShadowHeight);
mShadowDrawable.draw(canvas);
}
canvas.restore();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final float x = ev.getX();
final float y = ev.getY();
final int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN
&& mTouchTarget == null
&& mPinnedSection != null
&& isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target
// user touched pinned view
mTouchTarget = mPinnedSection.view;
mTouchPoint.x = x;
mTouchPoint.y = y;
// copy down event for eventually be used later
mDownEvent = MotionEvent.obtain(ev);
}
if (mTouchTarget != null) {
if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view
mTouchTarget.dispatchTouchEvent(ev);
}
if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view
super.dispatchTouchEvent(ev);
performPinnedItemClick();
clearTouchTarget();
} else if (action == MotionEvent.ACTION_CANCEL) { // cancel
clearTouchTarget();
} else if (action == MotionEvent.ACTION_MOVE) {
if (Math.abs(y - mTouchPoint.y) > mTouchSlop) {
// cancel sequence on touch target
MotionEvent event = MotionEvent.obtain(ev);
event.setAction(MotionEvent.ACTION_CANCEL);
mTouchTarget.dispatchTouchEvent(event);
event.recycle();
// provide correct sequence to super class for further handling
super.dispatchTouchEvent(mDownEvent);
super.dispatchTouchEvent(ev);
clearTouchTarget();
}
}
return true;
}
// call super if this was not our pinned view
return super.dispatchTouchEvent(ev);
}
//-- touch handling methods
private boolean isPinnedViewTouched(View view, float x, float y) {
view.getHitRect(mTouchRect);
// by taping top or bottom padding, the list performs on click on a border item.
// we don't add top padding here to keep behavior consistent.
mTouchRect.top += mTranslateY;
mTouchRect.bottom += mTranslateY + getPaddingTop();
mTouchRect.left += getPaddingLeft();
mTouchRect.right -= getPaddingRight();
return mTouchRect.contains((int) x, (int) y);
}
private void clearTouchTarget() {
mTouchTarget = null;
if (mDownEvent != null) {
mDownEvent.recycle();
mDownEvent = null;
}
}
private boolean performPinnedItemClick() {
if (mPinnedSection == null) return false;
OnItemClickListener listener = getOnItemClickListener();
if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) {
View view = mPinnedSection.view;
playSoundEffect(SoundEffectConstants.CLICK);
if (view != null) {
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
}
listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id);
return true;
}
return false;
}
/**
* List adapter to be implemented for being used with PinnedSectionListView adapter.
*/
public static interface PinnedSectionListAdapter extends ListAdapter {
/**
* This method shall return 'true' if views of given type has to be pinned.
*/
boolean isItemViewTypePinned(int viewType);
}
/**
* Wrapper class for pinned section view and its position in the list.
*/
static class PinnedSection {
public View view;
public int position;
public long id;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/PopupView.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.ui.view.base.BaseRelativeLayout;
/**
* Created by CaoDongping on 11/30/15.
*/
public abstract class PopupView<T> extends BaseRelativeLayout {
public static final int ANIMATION_DIRECTION_BOTTOM_TO_TOP = 0;
public static final int ANIMATION_DIRECTION_TOP_TO_BOTTOM = 1;
public static final int ANIMATION_DIRECTION_LEFT_TO_RIGHT = 2;
public static final int ANIMATION_DIRECTION_RIGHT_TO_LEFT = 3;
public static final int ANIMATE_DURATION = 200;
private boolean inAnimation;
public PopupView(Context context) {
super(context, null, 0);
}
/**
* 显示到Activity上面去
*
* @param activity
* @param data
* @return
*/
public PopupView<T> attachTo(Activity activity, T data) {
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
return attachTo(activity, data, lp);
}
/**
* 显示到Activity上面去
*
* @param activity
* @param data
* @param layoutParams
* @return
*/
public PopupView<T> attachTo(Activity activity, T data, FrameLayout.LayoutParams layoutParams) {
setId(R.id.popup_view_id);
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
if (null != contentView.findViewById(R.id.popup_view_id)) {
return this;
}
render(data);
contentView.addView(this, layoutParams);
animateIn();
return this;
}
protected int getAnimationDirection() {
return ANIMATION_DIRECTION_BOTTOM_TO_TOP;
}
/**
* 动画显示
*/
protected void animateIn() {
if (inAnimation) {
return;
}
setVisibility(INVISIBLE);
inAnimation = true;
post(new Runnable() {
@Override
public void run() {
setVisibility(VISIBLE);
ObjectAnimator alpha = ObjectAnimator.ofFloat(getMaskView(), "alpha", 0, 1);
alpha.setDuration(ANIMATE_DURATION);
alpha.start();
int measuredHeight = getMainView().getMeasuredHeight();
int measuredWidth = getMainView().getMeasuredWidth();
ObjectAnimator translate;
switch (getAnimationDirection()) {
case ANIMATION_DIRECTION_BOTTOM_TO_TOP:
translate = ObjectAnimator.ofFloat(getMainView(), "translationY", measuredHeight, 0);
break;
case ANIMATION_DIRECTION_TOP_TO_BOTTOM:
translate = ObjectAnimator.ofFloat(getMainView(), "translationY", -measuredHeight, 0);
break;
case ANIMATION_DIRECTION_LEFT_TO_RIGHT:
translate = ObjectAnimator.ofFloat(getMainView(), "translationX", -measuredWidth, 0);
break;
case ANIMATION_DIRECTION_RIGHT_TO_LEFT:
translate = ObjectAnimator.ofFloat(getMainView(), "translationX", measuredWidth, 0);
break;
default:
throw new RuntimeException("unknown animation direction");
}
translate.setInterpolator(new AccelerateInterpolator());
translate.setDuration(ANIMATE_DURATION);
translate.start();
translate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
inAnimation = false;
}
});
}
});
}
public void finish() {
finish(null);
}
/**
* 从当前Activity上移除
*/
public void finish(final FinishCallback callback) {
if (!inAnimation) {
inAnimation = true;
ObjectAnimator alpha = ObjectAnimator.ofFloat(getMainView(), "alpha", 1, 0);
alpha.setDuration(ANIMATE_DURATION);
alpha.start();
int measuredHeight = getMainView().getMeasuredHeight();
int measuredWidth = getMainView().getMeasuredWidth();
ObjectAnimator translate;
switch (getAnimationDirection()) {
case ANIMATION_DIRECTION_BOTTOM_TO_TOP:
translate = ObjectAnimator.ofFloat(getMainView(), "translationY", 0, measuredHeight);
break;
case ANIMATION_DIRECTION_TOP_TO_BOTTOM:
translate = ObjectAnimator.ofFloat(getMainView(), "translationY", 0, -measuredHeight);
break;
case ANIMATION_DIRECTION_LEFT_TO_RIGHT:
translate = ObjectAnimator.ofFloat(getMainView(), "translationX", 0, -measuredWidth);
break;
case ANIMATION_DIRECTION_RIGHT_TO_LEFT:
translate = ObjectAnimator.ofFloat(getMainView(), "translationX", 0, measuredWidth);
break;
default:
throw new RuntimeException("unknown animation direction");
}
translate.setInterpolator(new AccelerateInterpolator());
translate.setDuration(ANIMATE_DURATION);
translate.start();
translate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (getParent() instanceof ViewGroup) {
((ViewGroup) getParent()).removeView(PopupView.this);
}
inAnimation = false;
if (callback != null) {
callback.afterFinish();
}
}
});
}
}
/**
* 渲染数据到UI
*
* @param data
*/
protected abstract void render(T data);
/**
* 获取需要fadeIn显示的遮罩视图
*
* @return
*/
protected abstract View getMaskView();
/**
* 获取需要translation的主UI视图
*
* @return
*/
protected abstract View getMainView();
public interface FinishCallback {
void afterFinish();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/ProgressView.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.util.DensityUtil;
import com.pnikosis.materialishprogress.ProgressWheel;
/**
* Created by CaoDongping on 1/5/16.
*/
public class ProgressView extends ProgressWheel {
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ProgressView(Context context) {
super(context);
init();
}
private void init() {
if (isInEditMode()) {
return;
}
setBarColor(getResources().getColor(R.color.colorPrimary));
setBarWidth(DensityUtil.dp2px(2));
spin();
}
public void start() {
setVisibility(VISIBLE);
}
public void stop() {
setVisibility(View.GONE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode() && getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
super.onMeasure(DensityUtil.dp2px(40), DensityUtil.dp2px(40));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/TintStatusBar.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.github.mzule.androidweekly.util.Tinter;
/**
* 占位符View,在支持Tint的设备上,高度为信号栏的高度,在不支持Tint的设备上,高度为0,可以用来作为UI布局的占位符
* Created by CaoDongping on 11/11/15.
*/
public class TintStatusBar extends View {
private int statusBarHeight;
public TintStatusBar(Context context) {
super(context);
init();
}
public TintStatusBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TintStatusBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init() {
statusBarHeight = getStatusBarHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
int height = 0;
if (Tinter.isSupport()) {
height = statusBarHeight;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public void setHeightPercent(float percent) {
ViewGroup.LayoutParams lp = getLayoutParams();
lp.height = (int) (statusBarHeight * percent);
setLayoutParams(lp);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/TranslateView.java
================================================
package com.github.mzule.androidweekly.ui.view;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.api.ApiCallback;
import com.github.mzule.androidweekly.api.DictionaryApi;
import com.github.mzule.androidweekly.entity.Dict;
import com.github.mzule.androidweekly.util.Keyboard;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
import butterknife.OnClick;
/**
* Created by CaoDongping on 3/30/16.
*/
@Layout(R.layout.view_translate)
public class TranslateView extends PopupView<Void> {
@Bind(R.id.queryInput)
EditText queryInput;
@Bind(R.id.resultView)
EditText resultView;
@Bind(R.id.buttonPanel)
View buttonPanel;
public TranslateView(Context context) {
super(context);
}
@OnClick(R.id.maskView)
@Override
public void finish() {
super.finish();
hideKeyboard();
}
private void hideKeyboard() {
if (getContext() instanceof Activity) {
Keyboard.hide((Activity) getContext());
}
}
@OnClick(R.id.clearButton)
void clear() {
queryInput.setText("");
resultView.setText("");
queryInput.requestFocus();
Keyboard.show(getContext());
}
@OnClick(R.id.translateButton)
void translate() {
new DictionaryApi().look(queryInput.getText().toString().toLowerCase(), new ApiCallback<Dict>() {
@Override
public void onSuccess(Dict data, boolean fromCache) {
resultView.setText(data.getContent());
resultView.setSelection(0);
hideKeyboard();
updateResultViewMaxHeight();
}
@Override
public void onFailure(Exception e) {
resultView.setText(Log.getStackTraceString(e));
}
});
}
@Override
protected void render(Void data) {
String paste = getPasteText();
queryInput.requestFocus();
if (!TextUtils.isEmpty(paste)) {
queryInput.setText(paste);
queryInput.setSelection(paste.length());
translate();
}
}
private void updateResultViewMaxHeight() {
int height = getResources().getDisplayMetrics().heightPixels;
resultView.setMaxHeight(height - queryInput.getBottom() - buttonPanel.getMeasuredHeight() - queryInput.getPaddingLeft());
}
@Nullable
private String getPasteText() {
String paste = null;
ClipboardManager manager = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = manager.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0 && clip.getItemAt(0) != null) {
CharSequence text = clip.getItemAt(0).getText();
paste = text == null ? "" : text.toString();
}
return paste;
}
@Override
protected View getMaskView() {
return findViewById(R.id.maskView);
}
@Override
protected View getMainView() {
return findViewById(R.id.mainView);
}
@Override
protected int getAnimationDirection() {
return ANIMATION_DIRECTION_TOP_TO_BOTTOM;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseLinearLayout.java
================================================
package com.github.mzule.androidweekly.ui.view.base;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import com.github.mzule.layoutannotation.LayoutBinder;
import butterknife.ButterKnife;
/**
* Created by CaoDongping on 8/30/16.
*/
public class BaseLinearLayout extends LinearLayout {
public BaseLinearLayout(Context context) {
super(context);
init(context, null);
}
public BaseLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public BaseLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
protected void init(Context context, AttributeSet attrs) {
LayoutBinder.bind(this);
ButterKnife.bind(this);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseRelativeLayout.java
================================================
package com.github.mzule.androidweekly.ui.view.base;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import com.github.mzule.layoutannotation.LayoutBinder;
import butterknife.ButterKnife;
/**
* Created by CaoDongping on 8/30/16.
*/
public class BaseRelativeLayout extends RelativeLayout {
public BaseRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
LayoutBinder.bind(this);
ButterKnife.bind(this);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/ArticleViewType.java
================================================
package com.github.mzule.androidweekly.ui.viewtype;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.entity.Article;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
/**
* Created by CaoDongping on 3/24/16.
*/
@Layout(R.layout.item_article)
public class ArticleViewType extends BaseViewType<Article> {
@Bind(R.id.nameView)
TextView nameView;
@Bind(R.id.briefView)
TextView briefView;
@Bind(R.id.domainView)
TextView domainView;
@Bind(R.id.iconView)
ImageView iconView;
@Override
public void onRender(int position, Article data) {
nameView.setText(data.getTitle());
briefView.setText(data.getBrief());
domainView.setText(data.getDomain());
Glide.with(getContext()).load(data.getImageUrl()).centerCrop().placeholder(R.color.placeholder).into(iconView);
iconView.setVisibility(TextUtils.isEmpty(data.getImageUrl()) ? View.GONE : View.VISIBLE);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/BaseViewType.java
================================================
/*
* Copyright (C) 2016 Baidu, Inc. All Rights Reserved.
*/
package com.github.mzule.androidweekly.ui.viewtype;
import com.github.mzule.easyadapter.ViewType;
import com.github.mzule.layoutannotation.LayoutBinder;
import butterknife.ButterKnife;
/**
* Created by CaoDongping on 8/29/16.
*/
public abstract class BaseViewType<T> extends ViewType<T> {
@Override
public void onCreate() {
setContentView(LayoutBinder.inflate(getContext(), this));
ButterKnife.bind(this, getView());
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SearchHistoryViewType.java
================================================
package com.github.mzule.androidweekly.ui.viewtype;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
/**
* Created by CaoDongping on 4/5/16.
*/
@Layout(R.layout.item_search_history)
public class SearchHistoryViewType extends BaseViewType<String> {
@Bind(R.id.textView)
TextView textView;
@Override
public void onRender(int position, String data) {
textView.setText(data);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SectionViewType.java
================================================
package com.github.mzule.androidweekly.ui.viewtype;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
/**
* Created by CaoDongping on 3/24/16.
*/
@Layout(R.layout.item_section)
public class SectionViewType extends BaseViewType<String> {
@Bind(R.id.sectionName)
TextView sectionName;
@Override
public void onRender(int position, String data) {
sectionName.setText(data);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SlideIssueViewType.java
================================================
package com.github.mzule.androidweekly.ui.viewtype;
import android.view.View;
import android.widget.TextView;
import com.github.mzule.androidweekly.R;
import com.github.mzule.androidweekly.entity.Issue;
import com.github.mzule.layoutannotation.Layout;
import butterknife.Bind;
/**
* Created by CaoDongping on 3/25/16.
*/
@Layout(R.layout.item_slide_issue)
public class SlideIssueViewType extends BaseViewType<Issue> {
@Bind(R.id.nameView)
TextView nameView;
@Bind(R.id.dateView)
TextView dateView;
@Bind(R.id.rootLayout)
View rootLayout;
@Override
public void onRender(int position, Issue data) {
nameView.setText(data.getName());
nameView.setSelected(data.isActive());
dateView.setText(data.getDate());
dateView.setSelected(data.isActive());
int color = getContext().getResources().getColor(data.isActive() ? R.color.colorPrimary : R.color.transparent);
rootLayout.setBackgroundColor(color);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DateUtil.java
================================================
package com.github.mzule.androidweekly.util;
import android.annotation.SuppressLint;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/**
* Created by CaoDongping on 3/28/16.
*/
public class DateUtil {
@SuppressLint("SimpleDateFormat")
private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
public static String format(long time) {
return format.format(time);
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DensityUtil.java
================================================
package com.github.mzule.androidweekly.util;
import com.github.mzule.androidweekly.App;
/**
* Created by CaoDongping on 11/4/15.
*/
public class DensityUtil {
public static int dp2px(float dp) {
float density = App.getInstance().getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5f);
}
public static float px2dp(float px) {
float density = App.getInstance().getResources().getDisplayMetrics().density;
return px / density;
}
public static int screenWidth() {
return App.getInstance().getResources().getDisplayMetrics().widthPixels;
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DictParser.java
================================================
package com.github.mzule.androidweekly.util;
import android.util.Xml;
import com.github.mzule.androidweekly.entity.Dict;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.net.URL;
/**
* Created by CaoDongping on 3/31/16.
*/
public class DictParser {
private Dict dict;
private String url;
public DictParser(String url) {
this.url = url;
}
public Dict parse() throws IOException, XmlPullParserException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new URL(url).openStream(), null);
parser.nextTag();
dict = new Dict();
readDict(parser);
return dict;
}
private void readDict(XmlPullParser parser) throws IOException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, null, "dict");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
switch (name) {
case "key":
dict.setKey(readText(parser));
break;
case "ps":
dict.addPs(readText(parser));
break;
case "pron":
dict.addPron(readText(parser));
break;
case "pos":
dict.addPos(readText(parser));
break;
case "acceptation":
dict.addAcceptation(readText(parser));
break;
case "fy":
dict.setFy(readText(parser));
break;
case "sent":
parseSent(parser);
break;
}
}
}
private void parseSent(XmlPullParser parser) throws IOException, XmlPullParserException {
Dict.Sent sent = new Dict.Sent();
parser.require(XmlPullParser.START_TAG, null, "sent");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
switch (name) {
case "orig":
sent.setOrig(readText(parser));
break;
case "trans":
sent.setTrans(readText(parser));
break;
}
}
dict.addSent(sent);
}
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = null;
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result == null ? null : result.trim();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/IOUtil.java
================================================
package com.github.mzule.androidweekly.util;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by mzule on 4/5/16.
*/
public class IOUtil {
public static void close(Closeable... closeables) {
if (closeables == null) {
return;
}
for (Closeable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void close(AutoCloseable... closeables) {
if (closeables == null) {
return;
}
for (AutoCloseable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static String read(File file) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
} finally {
close(br);
}
return sb.toString();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/JsonUtil.java
================================================
package com.github.mzule.androidweekly.util;
import android.support.annotation.WorkerThread;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.URL;
/**
* Created by CaoDongping on 3/26/16.
*/
public class JsonUtil {
private static final Gson gson = new Gson();
public static String toJson(Object obj) {
try {
return gson.toJson(obj);
} catch (Throwable e) {
return "";
}
}
public static <T> T fromJson(String json, Class<T> cls) {
try {
return gson.fromJson(json, cls);
} catch (Throwable e) {
return null;
}
}
public static <T> T fromJson(String json, Type type) {
try {
return gson.fromJson(json, type);
} catch (Throwable e) {
return null;
}
}
@WorkerThread
public static <T> T fromJson(URL url, Class<T> cls) {
try {
return gson.fromJson(new BufferedReader(new InputStreamReader(url.openConnection().getInputStream())), cls);
} catch (Throwable e) {
return null;
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/Keyboard.java
================================================
package com.github.mzule.androidweekly.util;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
/**
* Created by CaoDongping on 12/21/15.
*/
public class Keyboard {
public static void show(Context context) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
public static void hide(Activity activity) {
View view = activity.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/MD5.java
================================================
package com.github.mzule.androidweekly.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by CaoDongping on 1/4/16.
*/
public class MD5 {
public static String encode(final String s) {
final String MD5 = "MD5";
try {
// Create MD5 Hash
MessageDigest digest = MessageDigest.getInstance(MD5);
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuilder hexString = new StringBuilder();
for (byte aMessageDigest : messageDigest) {
String h = Integer.toHexString(0xFF & aMessageDigest);
while (h.length() < 2) {
h = "0" + h;
}
hexString.append(h);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/StemUtil.java
================================================
package com.github.mzule.androidweekly.util;
import org.tartarus.snowball.ext.EnglishStem;
/**
* Created by CaoDongping on 4/2/16.
*/
public class StemUtil {
public static String stem(String input) {
String[] words = input.replaceAll("[^a-zA-Z ]", " ").toLowerCase().split("\\s+");
StringBuilder sb = new StringBuilder();
EnglishStem stem = new EnglishStem();
for (String w : words) {
stem.setCurrent(w);
stem.stem();
sb.append(stem.getCurrent()).append(" ");
}
return sb.toString();
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/ThreadUtil.java
================================================
package com.github.mzule.androidweekly.util;
/**
* Created by CaoDongping on 1/12/16.
*/
public class ThreadUtil {
public static void sleepUntilNextDraw(long startTime) {
int cost = (int) (System.currentTimeMillis() - startTime);
if (cost < 16) {
try {
Thread.sleep(16 - cost);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
================================================
FILE: app/src/main/java/com/github/mzule/androidweekly/util/Tinter.java
================================================
package com.github.mzule.androidweekly.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.view.Window;
import android.view.WindowManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* <p/>
* 设置Activity的信号栏为透明风格的工具类
* <p/>
* Created by CaoDongping on 9/17/15.
*/
public class Tinter {
/**
* 如果当前系统版本支持Tint,则开启,否则,不作任何事情.
*
* @param activity
*/
public static void enableIfSupport(Activity activity) {
if (isSupport()) {
tint(activity, true);
}
}
/**
* 当前系统版本是否支持Tint
*
* @return
*/
public static boolean isSupport() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
@TargetApi(19)
private static void tint(Activity activity, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
Class<? extends Window> clazz = win.getClass();
try {
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(win, darkModeFlag, darkModeFlag);
} catch (Throwable e) {
}
}
}
================================================
FILE: app/src/main/res/anim/slide_in_left.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="-100%p"
android:toXDelta="0" />
</set>
================================================
FILE: app/src/main/res/anim/slide_in_right.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="100%p"
android:toXDelta="0" />
</set>
================================================
FILE: app/src/main/res/anim/slide_out_left.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:toXDelta="-100%p" />
</set>
================================================
FILE: app/src/main/res/anim/slide_out_right.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>
================================================
FILE: app/src/main/res/color/text_color_slide_date.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/textColorLightGray" android:state_pressed="false" android:state_selected="false" />
<item android:color="@color/white" />
</selector>
================================================
FILE: app/src/main/res/color/text_color_slide_issue.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorPrimary" android:state_pressed="false" android:state_selected="false" />
<item android:color="@color/white" />
</selector>
================================================
FILE: app/src/main/res/drawable/bg_button.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_button_s" android:state_pressed="true" />
<item android:drawable="@drawable/bg_button_n" />
</selector>
================================================
FILE: app/src/main/res/drawable/bg_button_n.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/transparent" />
</shape>
================================================
FILE: app/src/main/res/drawable/bg_button_s.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f0f0f0" />
</shape>
================================================
FILE: app/src/main/res/drawable/bg_dialog.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="3dp" />
</shape>
================================================
FILE: app/src/main/res/drawable/ic_slide_menu.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_slide_menu_n" android:state_pressed="false" android:state_selected="false" />
<item android:drawable="@drawable/ic_slide_menu_s" />
</selector>
================================================
FILE: app/src/main/res/layout/activity_about.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.NaviBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:nb_left_text="ABOUT"
app:nb_right_text="ME" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:lineSpacingMultiplier="1.6"
android:padding="@dimen/space"
android:text="host at github"
android:textColor="@color/textColorGray"
android:textColorLink="@color/colorPrimary"
android:textSize="@dimen/text_size_medium" />
</LinearLayout>
================================================
FILE: app/src/main/res/layout/activity_article.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.mzule.androidweekly.ui.view.ProgressView
android:id="@+id/progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
</LinearLayout>
</ScrollView>
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:id="@+id/tintBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/slideBg" />
<View
style="@style/HorizontalLine"
android:layout_below="@+id/tintBar" />
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/slideBg"
android:gravity="center_vertical"
android:orientation="vertical">
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/favoriteButton"
style="@style/BigControl"
app:materialIcon="star" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/increaseButton"
style="@style/BigControl"
app:materialIcon="plus" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/decreaseButton"
style="@style/BigControl"
app:materialIcon="minus" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/translateButton"
style="@style/BigControl"
app:materialIcon="google_translate" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/copyUrlButton"
style="@style/BigControl"
app:materialIcon="content_copy" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/shareButton"
style="@style/BigControl"
app:materialIcon="share" />
<View style="@style/HorizontalLine" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
================================================
FILE: app/src/main/res/layout/activity_favorite.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.NaviBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:nb_left_text="ANDROID"
app:nb_right_text="FAVORITE" />
<com.github.mzule.androidweekly.ui.view.PinnedSectionListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:overScrollMode="never" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/slideBg"
android:gravity="center_vertical"
android:orientation="vertical">
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/importButton"
style="@style/BigControl"
app:materialIcon="import_icon" />
<View style="@style/HorizontalLine" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/exportButton"
style="@style/BigControl"
app:materialIcon="export" />
<View style="@style/HorizontalLine" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:id="@+id/tintBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white" />
<LinearLayout
android:id="@+id/brandView"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
android:layout_below="@id/tintBar"
android:background="@color/white"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ANDROID"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/small_space"
android:text="WEEKLY"
android:textColor="@color/colorAccent"
android:textSize="@dimen/text_size_large"
android:textStyle="bold" />
</LinearLayout>
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/slideMenuButton"
style="@style/SmallControl"
android:layout_below="@id/tintBar"
app:materialIcon="menu" />
<View
android:id="@+id/lineView"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/brandView"
android:background="@color/lineColor" />
<com.github.mzule.androidweekly.ui.view.PinnedSectionListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/lineView"
android:divider="@null"
android:overScrollMode="never" />
<com.github.mzule.androidweekly.ui.view.ProgressView
android:id="@+id/progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
<LinearLayout
android:id="@+id/slideView"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@color/slideBg"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/lineColor" />
<ListView
android:id="@+id/slideListView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
android:overScrollMode="never"
android:scrollbars="none" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/lineColor" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true">
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/favoriteButton"
style="@style/NormalControl"
app:materialIcon="star" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/searchButton"
style="@style/NormalControl"
app:materialIcon="magnify" />
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/aboutButton"
style="@style/NormalControl"
app:materialIcon="information" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
================================================
FILE: app/src/main/res/layout/activity_search.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.github.mzule.androidweekly.ui.view.IconButton
style="@style/SmallControl"
android:onClick="back"
app:materialIcon="arrow_left" />
<EditText
android:id="@+id/queryInput"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
android:background="@color/transparent"
android:hint="Search local cache here."
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:textColor="@color/textColorGray"
android:textColorHint="@color/textColorHint"
android:textSize="@dimen/text_size_medium">
<requestFocus />
</EditText>
</LinearLayout>
<View style="@style/HorizontalLine" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:overScrollMode="never" />
</LinearLayout>
================================================
FILE: app/src/main/res/layout/activity_search_result.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.NaviBar
android:id="@+id/naviBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:nb_right_text="RESULT" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:overScrollMode="never" />
</LinearLayout>
================================================
FILE: app/src/main/res/layout/item_article.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/space">
<TextView
android:id="@+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="全系BMW 3系闪耀登场"
android:textColor="@color/colorAccent"
android:textSize="@dimen/text_size_medium" />
<ImageView
android:id="@+id/iconView"
android:layout_width="75dp"
android:layout_height="75dp"
android:layout_below="@id/nameView"
android:layout_marginRight="@dimen/space"
android:layout_marginTop="@dimen/space" />
<TextView
android:id="@+id/briefView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/nameView"
android:layout_marginBottom="@dimen/space"
android:layout_marginTop="@dimen/space"
android:layout_toRightOf="@id/iconView"
android:text="新的里程"
android:textColor="@color/textColorGray"
android:textSize="@dimen/text_size_small" />
<TextView
android:id="@+id/domainView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/briefView"
android:layout_toRightOf="@id/iconView"
android:text="medium.com"
android:textColor="@color/textColorLightGray"
android:textSize="@dimen/text_size_small" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentBottom="true"
android:background="@color/lineColor" />
</RelativeLayout>
================================================
FILE: app/src/main/res/layout/item_search_history.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/space"
android:text="You are best."
android:textColor="@color/textColorGray"
android:textSize="@dimen/text_size_medium" />
<View style="@style/HorizontalLine" />
</LinearLayout>
================================================
FILE: app/src/main/res/layout/item_section.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f8f8f8">
<TextView
android:id="@+id/sectionName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/half_space"
android:paddingLeft="@dimen/space"
android:paddingTop="@dimen/half_space"
android:text="Sponsored"
android:textSize="@dimen/text_size_tiny" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignBottom="@id/sectionName"
android:background="@color/lineColor" />
</RelativeLayout>
================================================
FILE: app/src/main/res/layout/item_slide_issue.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/dateView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="@+id/nameView"
android:gravity="center"
android:padding="@dimen/space"
android:text="2013-11-12"
android:textColor="@color/text_color_slide_date"
android:textSize="@dimen/text_size_tiny" />
<TextView
android:id="@+id/nameView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/dateView"
android:padding="@dimen/space"
android:text="Issue-128"
android:textColor="@color/text_color_slide_issue"
android:textSize="@dimen/text_size_medium" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/nameView"
android:background="@color/lineColor" />
</RelativeLayout>
================================================
FILE: app/src/main/res/layout/view_navi_bar.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/brandView"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
android:background="@color/white"
android:gravity="center">
<TextView
android:id="@+id/leftTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ANDROID"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold" />
<TextView
android:id="@+id/rightTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/small_space"
android:text="FAVORITE"
android:textColor="@color/colorAccent"
android:textSize="@dimen/text_size_large"
android:textStyle="bold" />
</LinearLayout>
<com.github.mzule.androidweekly.ui.view.IconButton
android:id="@+id/backButton"
style="@style/SmallControl"
app:materialIcon="arrow_left" />
</RelativeLayout>
<View style="@style/HorizontalLine" />
</LinearLayout>
================================================
FILE: app/src/main/res/layout/view_translate.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/maskView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/mask" />
<RelativeLayout
android:id="@+id/mainView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/space"
android:layout_marginRight="@dimen/space"
android:background="@color/white"
android:clickable="true"
android:orientation="vertical">
<com.github.mzule.androidweekly.ui.view.TintStatusBar
android:id="@+id/tintBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/queryInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tintBar"
android:background="@color/transparent"
android:gravity="left|top"
android:hint="Input query text here..."
android:imeActionLabel="翻译"
android:maxHeight="100dp"
android:padding="@dimen/space"
android:textColor="@color/textColorGray"
android:textColorHint="@color/textColorHint"
android:textSize="@dimen/text_size_small" />
<View
style="@style/HorizontalLine"
android:layout_alignBottom="@+id/queryInput" />
<EditText
android:id="@+id/resultView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/queryInput"
android:background="@color/transparent"
android:editable="false"
android:focusable="false"
android:hint="Result will display here..."
android:padding="@dimen/space"
android:textColor="@color/textColorGray"
android:textColorHint="@color/textColorHint"
android:textSize="@dimen/text_size_small" />
<View
style="@style/HorizontalLine"
android:layout_alignBottom="@+id/resultView" />
<LinearLayout
android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
android:layout_below="@+id/resultView">
<TextView
android:id="@+id/clearButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button"
android:gravity="center"
android:text="Clear"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/text_size_small" />
<View style="@style/VerticalLine" />
<TextView
android:id="@+id/translateButton"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/bg_button"
android:gravity="center"
android:text="Translate"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/text_size_small" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
================================================
FILE: app/src/main/res/values/attrs.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NaviBar">
<attr name="nb_left_text" format="string" />
<attr name="nb_right_text" format="string" />
</declare-styleable>
</resources>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#36bce8</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#464646</color>
<color name="placeholder">#e1e1e1</color>
<color name="lineColor">#d9d9d9</color>
<color name="transparent">#00000000</color>
<color name="bg">#fcfcfc</color>
<color name="white">#ffffff</color>
<color name="slideBg">#ddffffff</color>
<color name="textColorGray">#666666</color>
<color name="textColorLightGray">#999999</color>
<color name="textColorHint">#CCCCCC</color>
<color name="mask">#22000000</color>
</resources>
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
<dimen name="text_size_tiny">10sp</dimen>
<dimen name="text_size_small">12sp</dimen>
<dimen name="text_size_medium">14sp</dimen>
<dimen name="text_size_large">16sp</dimen>
<dimen name="space">12dp</dimen>
<dimen name="half_space">6dp</dimen>
<dimen name="small_space">4dp</dimen>
<dimen name="action_bar_height">40dp</dimen>
</resources>
================================================
FILE: app/src/main/res/values/ids.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="popup_view_id" type="id" />
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">Weekly</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowBackground">@color/bg</item>
</style>
<style name="Dialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@color/transparent</item>
<item name="android:windowBackground">@color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="BigControl">
<item name="android:layout_width">55dp</item>
<item name="android:layout_height">55dp</item>
<item name="android:scaleType">center</item>
<item name="materialIconColor">@color/colorPrimary</item>
<item name="materialIconSize">22dp</item>
<item name="android:background">@drawable/bg_button</item>
</style>
<style name="NormalControl">
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:scaleType">center</item>
<item name="materialIconColor">@color/colorPrimary</item>
<item name="materialIconSize">22dp</item>
<item name="android:background">@drawable/bg_button</item>
</style>
<style name="SmallControl">
<item name="android:layout_width">40dp</item>
<item name="android:layout_height">40dp</item>
<item name="android:scaleType">center</item>
<item name="materialIconColor">@color/colorPrimary</item>
<item name="materialIconSize">22dp</item>
<item name="android:background">@drawable/bg_button</item>
</style>
<style name="HorizontalLine">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1px</item>
<item name="android:background">@color/lineColor</item>
</style>
<style name="VerticalLine">
<item name="android:layout_width">1px</item>
<item name="android:layout_height">match_parent</item>
<item name="android:background">@color/lineColor</item>
</style>
</resources>
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
================================================
FILE: app/src/test/java/com/github/mzule/androidweekly/ExampleUnitTest.java
================================================
package com.github.mzule.androidweekly;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Sat Apr 09 16:59:39 CST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
================================================
FILE: gradle.properties
================================================
## Project-wide Gradle settings.
#
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Thu May 12 10:00:05 CST 2016
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: settings.gradle
================================================
include ':app', ':snowball'
================================================
FILE: snowball/.gitignore
================================================
/build
================================================
FILE: snowball/build.gradle
================================================
apply plugin: 'java'
sourceCompatibility = 1.7
targetCompatibility = 1.7
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
================================================
FILE: snowball/src/main/java/org/tartarus/snowball/Among.java
================================================
package org.tartarus.snowball;
import java.lang.reflect.Method;
public class Among {
public final int s_size; /* search string */
public final char[] s; /* search string */
public final int substring_i; /* index to longest matching substring */
public final int result; /* result of the lookup */
public final Method method; /* method to use if substring matches */
public final SnowballProgram methodobject; /* object to invoke method on */
public Among(String s, int substring_i, int result,
String methodname, SnowballProgram methodobject) {
this.s_size = s.length();
this.s = s.toCharArray();
this.substring_i = substring_i;
this.result = result;
this.methodobject = methodobject;
if (methodname.length() == 0) {
this.method = null;
} else {
try {
this.method = methodobject.getClass().
getDeclaredMethod(methodname, new Class[0]);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
};
================================================
FILE: snowball/src/main/java/org/tartarus/snowball/SnowballProgram.java
================================================
package org.tartarus.snowball;
import java.lang.reflect.InvocationTargetException;
public class SnowballProgram {
// current string
protected StringBuffer current;
protected int cursor;
protected int limit;
protected int limit_backward;
protected int bra;
protected int ket;
protected SnowballProgram() {
current = new StringBuffer();
setCurrent("");
}
/**
* Get the current string.
*/
public String getCurrent() {
String result = current.toString();
// Make a new StringBuffer. If we reuse the old one, and a user of
// the library keeps a reference to the buffer returned (for example,
// by converting it to a String in a way which doesn't force a copy),
// the buffer size will not decrease, and we will risk wasting a large
// amount of memory.
// Thanks to Wolfram Esser for spotting this problem.
current = new StringBuffer();
return result;
}
/**
* Set the current string.
*/
public void setCurrent(String value) {
current.replace(0, current.length(), value);
cursor = 0;
limit = current.length();
limit_backward = 0;
bra = cursor;
ket = limit;
}
protected void copy_from(SnowballProgram other) {
current = other.current;
cursor = other.cursor;
limit = other.limit;
limit_backward = other.limit_backward;
bra = other.bra;
ket = other.ket;
}
protected boolean in_grouping(char[] s, int min, int max) {
if (cursor >= limit) return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min) return false;
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
cursor++;
return true;
}
protected boolean in_grouping_b(char[] s, int min, int max) {
if (cursor <= limit_backward) return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min) return false;
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
cursor--;
return true;
}
protected boolean out_grouping(char[] s, int min, int max) {
if (cursor >= limit) return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min) {
cursor++;
return true;
}
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
cursor++;
return true;
}
return false;
}
protected boolean out_grouping_b(char[] s, int min, int max) {
if (cursor <= limit_backward) return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min) {
cursor--;
return true;
}
ch -= min;
if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
cursor--;
return true;
}
return false;
}
protected boolean in_range(int min, int max) {
if (cursor >= limit) return false;
char ch = current.charAt(cursor);
if (ch > max || ch < min) return false;
cursor++;
return true;
}
protected boolean in_range_b(int min, int max) {
if (cursor <= limit_backward) return false;
char ch = current.charAt(cursor - 1);
if (ch > max || ch < min) return false;
cursor--;
return true;
}
protected boolean out_range(int min, int max) {
if (cursor >= limit) return false;
char ch = current.charAt(cursor);
if (!(ch > max || ch < min)) return false;
cursor++;
return true;
}
protected boolean out_range_b(int min, int max) {
if (cursor <= limit_backward) return false;
char ch = current.charAt(cursor - 1);
if (!(ch > max || ch < min)) return false;
cursor--;
return true;
}
protected boolean eq_s(int s_size, String s) {
if (limit - cursor < s_size) return false;
int i;
for (i = 0; i != s_size; i++) {
if (current.charAt(cursor + i) != s.charAt(i)) return false;
}
cursor += s_size;
return true;
}
protected boolean eq_s_b(int s_size, String s) {
if (cursor - limit_backward < s_size) return false;
int i;
for (i = 0; i != s_size; i++) {
if (current.charAt(cursor - s_size + i) != s.charAt(i)) return false;
}
cursor -= s_size;
return true;
}
protected boolean eq_v(CharSequence s) {
return eq_s(s.length(), s.toString());
}
protected boolean eq_v_b(CharSequence s) {
return eq_s_b(s.length(), s.toString());
}
protected int find_among(Among v[], int v_size) {
int i = 0;
int j = v_size;
int c = cursor;
int l = limit;
int common_i = 0;
int common_j = 0;
boolean first_key_inspected = false;
while (true) {
int k = i + ((j - i) >> 1);
int diff = 0;
int common = common_i < common_j ? common_i : common_j; // smaller
Among w = v[k];
int i2;
for (i2 = common; i2 < w.s_size; i2++) {
if (c + common == l) {
diff = -1;
break;
}
diff = current.charAt(c + common) - w.s[i2];
if (diff != 0) break;
common++;
}
if (diff < 0) {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if (j - i <= 1) {
if (i > 0) break; // v->s has been inspected
if (j == i) break; // only one item in v
// - but now we need to go round once more to get
// v->s inspected. This looks messy, but is actually
// the optimal approach.
if (first_key_inspected) break;
first_key_inspected = true;
}
}
while (true) {
Among w = v[i];
if (common_i >= w.s_size) {
cursor = c + w.s_size;
if (w.method == null) return w.result;
boolean res;
try {
Object resobj = w.method.invoke(w.methodobject,
new Object[0]);
res = resobj.toString().equals("true");
} catch (InvocationTargetException e) {
res = false;
// FIXME - debug message
} catch (IllegalAccessException e) {
res = false;
// FIXME - debug message
}
cursor = c + w.s_size;
if (res) return w.result;
}
i = w.substring_i;
if (i < 0) return 0;
}
}
// find_among_b is for backwards processing. Same comments apply
protected int find_among_b(Among v[], int v_size) {
int i = 0;
int j = v_size;
int c = cursor;
int lb = limit_backward;
int common_i = 0;
int common_j = 0;
boolean first_key_inspected = false;
while (true) {
int k = i + ((j - i) >> 1);
int diff = 0;
int common = common_i < common_j ? common_i : common_j;
Among w = v[k];
int i2;
for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) {
if (c - common == lb) {
diff = -1;
break;
}
diff = current.charAt(c - 1 - common) - w.s[i2];
if (diff != 0) break;
common++;
}
if (diff < 0) {
j = k;
common_j = common;
} else {
i = k;
common_i = common;
}
if (j - i <= 1) {
if (i > 0) break;
if (j == i) break;
if (first_key_inspected) break;
first_key_inspected = true;
}
}
while (true) {
Among w = v[i];
if (common_i >= w.s_size) {
cursor = c - w.s_size;
if (w.method == null) return w.result;
boolean res;
try {
Object resobj = w.method.invoke(w.methodobject,
new Object[0]);
res = resobj.toString().equals("true");
} catch (InvocationTargetException e) {
res = false;
// FIXME - debug message
} catch (IllegalAccessException e) {
res = false;
// FIXME - debug message
}
cursor = c - w.s_size;
if (res) return w.result;
}
i = w.substring_i;
if (i < 0) return 0;
}
}
/* to replace chars between c_bra and c_ket in current by the
* chars in s.
*/
protected int replace_s(int c_bra, int c_ket, String s) {
int adjustment = s.length() - (c_ket - c_bra);
current.replace(c_bra, c_ket, s);
limit += adjustment;
if (cursor >= c_ket) cursor += adjustment;
else if (cursor > c_bra) cursor = c_bra;
return adjustment;
}
protected void slice_check() {
if (bra < 0 ||
bra > ket ||
ket > limit ||
limit > current.length()) // this line could be removed
{
System.err.println("faulty slice operation");
// FIXME: report error somehow.
/*
fprintf(stderr, "faulty slice operation:\n");
debug(z, -1, 0);
exit(1);
*/
}
}
protected void slice_from(String s) {
slice_check();
replace_s(bra, ket, s);
}
protected void slice_from(CharSequence s) {
slice_from(s.toString());
}
protected void slice_del() {
slice_from("");
}
protected void insert(int c_bra, int c_ket, String s) {
int adjustment = replace_s(c_bra, c_ket, s);
if (c_bra <= bra) bra += adjustment;
if (c_bra <= ket) ket += adjustment;
}
protected void insert(int c_bra, int c_ket, CharSequence s) {
insert(c_bra, c_ket, s.toString());
}
/* Copy the slice into the supplied StringBuffer */
protected StringBuffer slice_to(StringBuffer s) {
slice_check();
int len = ket - bra;
s.replace(0, s.length(), current.substring(bra, ket));
return s;
}
/* Copy the slice into the supplied StringBuilder */
protected StringBuilder slice_to(StringBuilder s) {
slice_check();
int len = ket - bra;
s.replace(0, s.length(), current.substring(bra, ket));
return s;
}
protected StringBuffer assign_to(StringBuffer s) {
s.replace(0, s.length(), current.substring(0, limit));
return s;
}
protected StringBuilder assign_to(StringBuilder s) {
s.replace(0, s.length(), current.substring(0, limit));
return s;
}
/*
extern void debug(struct SN_env * z, int number, int line_count)
{ int i;
int limit = SIZE(z->p);
//if (number >= 0) printf("%3d (line %4d): '", number, line_count);
if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
for (i = 0; i <= limit; i++)
{ if (z->lb == i) printf("{");
if (z->bra == i) printf("[");
if (z->c == i) printf("|");
if (z->ket == i) printf("]");
if (z->l == i) printf("}");
if (i < limit)
{ int ch = z->p[i];
if (ch == 0) ch = '#';
printf("%c", ch);
}
}
printf("'\n");
}
*/
};
================================================
FILE: snowball/src/main/java/org/tartarus/snowball/SnowballStemmer.java
================================================
package org.tartarus.snowball;
public abstract class SnowballStemmer extends SnowballProgram {
public abstract boolean stem();
};
================================================
FILE: snowball/src/main/java/org/tartarus/snowball/TestApp.java
================================================
package org.tartarus.snowball;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
public class TestApp {
private static void usage() {
System.err.println("Usage: TestApp <algorithm> <input file> [-o <output file>]");
}
public static void main(String[] args) throws Throwable {
if (args.length < 2) {
usage();
return;
}
Class stemClass = Class.forName("org.tartarus.snowball.ext." +
args[0] + "Stemmer");
SnowballStemmer stemmer = (SnowballStemmer) stemClass.newInstance();
Reader reader;
reader = new InputStreamReader(new FileInputStream(args[1]));
reader = new BufferedReader(reader);
StringBuffer input = new StringBuffer();
OutputStream outstream;
if (args.length > 2) {
if (args.length >= 4 && args[2].equals("-o")) {
outstream = new FileOutputStream(args[3]);
} else {
usage();
return;
}
} else {
outstream = System.out;
}
Writer output = new OutputStreamWriter(outstream);
output = new BufferedWriter(output);
int repeat = 1;
if (args.length > 4) {
repeat = Integer.parseInt(args[4]);
}
Object[] emptyArgs = new Object[0];
int character;
while ((character = reader.read()) != -1) {
char ch = (char) character;
if (Character.isWhitespace((char) ch)) {
if (input.length() > 0) {
stemmer.setCurrent(input.toString());
for (int i = repeat; i != 0; i--) {
stemmer.stem();
}
output.write(stemmer.getCurrent());
output.write('\n');
input.delete(0, input.length());
}
} else {
input.append(Character.toLowerCase(ch));
}
}
output.flush();
}
}
================================================
FILE: snowball/src/main/java/org/tartarus/snowball/ext/EnglishStem.java
================================================
// This file was generated automatically by the Snowball to Java compiler
package org.tartarus.snowball.ext;
import org.tartarus.snowball.Among;
/**
* This class was automatically generated by a Snowball to Java compiler
* It implements the stemming algorithm defined by a snowball script.
*/
public class EnglishStem extends org.tartarus.snowball.SnowballStemmer {
private static final long serialVersionUID = 1L;
private final static EnglishStem methodObject = new EnglishStem();
private final static Among a_0[] = {
new Among("arsen", -1, -1, "", methodObject),
new Among("commun", -1, -1, "", methodObject),
new Among("gener", -1, -1, "", methodObject)
};
private final static Among a_1[] = {
new Among("'", -1, 1, "", methodObject),
new Among("'s'", 0, 1, "", methodObject),
new Among("'s", -1, 1, "", methodObject)
};
private final static Among a_2[] = {
new Among("ied", -1, 2, "", methodObject),
new Among("s", -1, 3, "", methodObject),
new Among("ies", 1, 2, "", methodObject),
new Among("sses", 1, 1, "", methodObject),
new Among("ss", 1, -1, "", methodObject),
new Among("us", 1, -1, "", methodObject)
};
private final static Among a_3[] = {
new Among("", -1, 3, "", methodObject),
new Among("bb", 0, 2, "", methodObject),
new Among("dd", 0, 2, "", methodObject),
new Among("ff", 0, 2, "", methodObject),
new Among("gg", 0, 2, "", methodObject),
new Among("bl", 0, 1, "", methodObject),
new Among("mm", 0, 2, "", methodObject),
new Among("nn", 0, 2, "", methodObject),
new Among("pp", 0, 2, "", methodObject),
new Among("rr", 0, 2, "", methodObject),
new Among("at", 0, 1, "", methodObject),
new Among("tt", 0, 2, "", methodObject),
new Among("iz", 0, 1, "", methodObject)
};
private final static Among a_4[] = {
new Among("ed", -1, 2, "", methodObject),
new Among("eed", 0, 1, "", methodObject),
new Among("ing", -1, 2, "", methodObject),
new Among("edly", -1, 2, "", methodObject),
new Among("eedly", 3, 1, "", methodObject),
new Among("ingly", -1, 2, "", methodObject)
};
private final static Among a_5[] = {
new Among("anci", -1, 3, "", methodObject),
new Among("enci", -1, 2, "", methodObject),
new Among("ogi", -1, 13, "", methodObject),
new Among("li", -1, 16, "", methodObject),
gitextract_qzfdnfdl/
├── .gitignore
├── LICENSE
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── mzule/
│ │ └── androidweekly/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── mzule/
│ │ │ └── androidweekly/
│ │ │ ├── App.java
│ │ │ ├── api/
│ │ │ │ ├── ApiCallback.java
│ │ │ │ ├── ArticleApi.java
│ │ │ │ ├── DictionaryApi.java
│ │ │ │ └── parser/
│ │ │ │ ├── ArticleParser.java
│ │ │ │ ├── ArticleParsers.java
│ │ │ │ ├── DocumentProvider.java
│ │ │ │ ├── FresherArticlesParser.java
│ │ │ │ └── OlderArticlesParser.java
│ │ │ ├── dao/
│ │ │ │ ├── ArticleDao.java
│ │ │ │ ├── FavoriteDao.java
│ │ │ │ ├── IssueListKeeper.java
│ │ │ │ ├── SearchHistoryKeeper.java
│ │ │ │ └── TextZoomKeeper.java
│ │ │ ├── entity/
│ │ │ │ ├── Article.java
│ │ │ │ ├── Dict.java
│ │ │ │ ├── Favorite.java
│ │ │ │ ├── Issue.java
│ │ │ │ └── TranslateResult.java
│ │ │ ├── ui/
│ │ │ │ ├── activity/
│ │ │ │ │ ├── AboutActivity.java
│ │ │ │ │ ├── ArticleActivity.java
│ │ │ │ │ ├── BaseActivity.java
│ │ │ │ │ ├── FavoriteActivity.java
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ ├── SearchActivity.java
│ │ │ │ │ └── SearchResultActivity.java
│ │ │ │ ├── adapter/
│ │ │ │ │ ├── ArticleAdapter.java
│ │ │ │ │ ├── SearchHistoryAdapter.java
│ │ │ │ │ └── SlideAdapter.java
│ │ │ │ ├── view/
│ │ │ │ │ ├── IconButton.java
│ │ │ │ │ ├── NaviBar.java
│ │ │ │ │ ├── PinnedSectionListView.java
│ │ │ │ │ ├── PopupView.java
│ │ │ │ │ ├── ProgressView.java
│ │ │ │ │ ├── TintStatusBar.java
│ │ │ │ │ ├── TranslateView.java
│ │ │ │ │ └── base/
│ │ │ │ │ ├── BaseLinearLayout.java
│ │ │ │ │ └── BaseRelativeLayout.java
│ │ │ │ └── viewtype/
│ │ │ │ ├── ArticleViewType.java
│ │ │ │ ├── BaseViewType.java
│ │ │ │ ├── SearchHistoryViewType.java
│ │ │ │ ├── SectionViewType.java
│ │ │ │ └── SlideIssueViewType.java
│ │ │ └── util/
│ │ │ ├── DateUtil.java
│ │ │ ├── DensityUtil.java
│ │ │ ├── DictParser.java
│ │ │ ├── IOUtil.java
│ │ │ ├── JsonUtil.java
│ │ │ ├── Keyboard.java
│ │ │ ├── MD5.java
│ │ │ ├── StemUtil.java
│ │ │ ├── ThreadUtil.java
│ │ │ └── Tinter.java
│ │ └── res/
│ │ ├── anim/
│ │ │ ├── slide_in_left.xml
│ │ │ ├── slide_in_right.xml
│ │ │ ├── slide_out_left.xml
│ │ │ └── slide_out_right.xml
│ │ ├── color/
│ │ │ ├── text_color_slide_date.xml
│ │ │ └── text_color_slide_issue.xml
│ │ ├── drawable/
│ │ │ ├── bg_button.xml
│ │ │ ├── bg_button_n.xml
│ │ │ ├── bg_button_s.xml
│ │ │ ├── bg_dialog.xml
│ │ │ └── ic_slide_menu.xml
│ │ ├── layout/
│ │ │ ├── activity_about.xml
│ │ │ ├── activity_article.xml
│ │ │ ├── activity_favorite.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_search.xml
│ │ │ ├── activity_search_result.xml
│ │ │ ├── item_article.xml
│ │ │ ├── item_search_history.xml
│ │ │ ├── item_section.xml
│ │ │ ├── item_slide_issue.xml
│ │ │ ├── view_navi_bar.xml
│ │ │ └── view_translate.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── ids.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── com/
│ └── github/
│ └── mzule/
│ └── androidweekly/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── snowball/
├── .gitignore
├── build.gradle
└── src/
└── main/
└── java/
└── org/
└── tartarus/
└── snowball/
├── Among.java
├── SnowballProgram.java
├── SnowballStemmer.java
├── TestApp.java
└── ext/
└── EnglishStem.java
SYMBOL INDEX (396 symbols across 60 files)
FILE: app/src/androidTest/java/com/github/mzule/androidweekly/ApplicationTest.java
class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
method ApplicationTest (line 10) | public ApplicationTest() {
FILE: app/src/main/java/com/github/mzule/androidweekly/App.java
class App (line 8) | public class App extends Application {
method getInstance (line 11) | public static App getInstance() {
method onCreate (line 15) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/api/ApiCallback.java
type ApiCallback (line 6) | public interface ApiCallback<T> {
method onSuccess (line 8) | void onSuccess(T data, boolean fromCache);
method onFailure (line 10) | void onFailure(Exception e);
FILE: app/src/main/java/com/github/mzule/androidweekly/api/ArticleApi.java
class ArticleApi (line 25) | public class ArticleApi {
method ArticleApi (line 30) | public ArticleApi() {
method getPage (line 34) | public void getPage(final String issue, final ApiCallback<List<Object>...
method getArchive (line 72) | public void getArchive(final ApiCallback<List<Issue>> callback) {
method doGetArchive (line 89) | private Response<List<Issue>> doGetArchive() throws Exception {
method doGetPage (line 103) | private Response<List<Object>> doGetPage(String issue) throws Exception {
method postSuccess (line 113) | private <T> void postSuccess(final Response<T> result, final ApiCallba...
method postError (line 122) | private <T> void postError(final Exception e, final ApiCallback<T> cal...
class Response (line 132) | static class Response<T> {
method Response (line 136) | public Response(T data, boolean fromCache) {
FILE: app/src/main/java/com/github/mzule/androidweekly/api/DictionaryApi.java
class DictionaryApi (line 13) | public class DictionaryApi {
method look (line 16) | public void look(String q, final ApiCallback<Dict> callback) {
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParser.java
type ArticleParser (line 9) | public interface ArticleParser {
method parse (line 10) | List<Object> parse(String issue) throws IOException;
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParsers.java
class ArticleParsers (line 8) | public class ArticleParsers {
method get (line 9) | @WorkerThread
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/DocumentProvider.java
class DocumentProvider (line 12) | public class DocumentProvider {
method get (line 13) | public static Document get(String issue) throws IOException {
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/FresherArticlesParser.java
class FresherArticlesParser (line 16) | public class FresherArticlesParser implements ArticleParser {
method parse (line 18) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/api/parser/OlderArticlesParser.java
class OlderArticlesParser (line 16) | public class OlderArticlesParser implements ArticleParser {
method parse (line 18) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/ArticleDao.java
class ArticleDao (line 19) | public class ArticleDao extends SQLiteOpenHelper {
method ArticleDao (line 30) | public ArticleDao() {
method read (line 34) | public List<Article> read(String issue) {
method search (line 44) | public List<Article> search(String q) {
method read (line 55) | @NonNull
method save (line 68) | public void save(Article article) {
method checkExist (line 84) | private boolean checkExist(Article article) {
method onCreate (line 92) | @Override
method onUpgrade (line 107) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/FavoriteDao.java
class FavoriteDao (line 25) | public class FavoriteDao extends SQLiteOpenHelper {
method FavoriteDao (line 38) | public FavoriteDao() {
method read (line 42) | public List<Favorite> read() {
method contains (line 62) | public boolean contains(Article article) {
method save (line 70) | public void save(Article article) {
method save (line 86) | public void save(Favorite favorite) {
method delete (line 103) | public void delete(Article article) {
method exportToFile (line 107) | public void exportToFile() throws IOException {
method importFromFile (line 124) | public void importFromFile() throws IOException {
method onCreate (line 136) | @Override
method onUpgrade (line 152) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/IssueListKeeper.java
class IssueListKeeper (line 17) | public class IssueListKeeper {
method save (line 19) | public static void save(List<Issue> issues) {
method read (line 23) | public static List<Issue> read() {
method getSharedPreferences (line 30) | private static SharedPreferences getSharedPreferences() {
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/SearchHistoryKeeper.java
class SearchHistoryKeeper (line 17) | public class SearchHistoryKeeper {
method save (line 21) | public static void save(String q) {
method read (line 33) | public static List<String> read() {
method getSharedPreferences (line 43) | private static SharedPreferences getSharedPreferences() {
FILE: app/src/main/java/com/github/mzule/androidweekly/dao/TextZoomKeeper.java
class TextZoomKeeper (line 11) | public class TextZoomKeeper {
method save (line 12) | public static void save(int zoom) {
method read (line 16) | public static int read(int def) {
method getSharedPreferences (line 20) | private static SharedPreferences getSharedPreferences() {
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Article.java
class Article (line 9) | public class Article implements Serializable {
method getSection (line 18) | public String getSection() {
method setSection (line 22) | public void setSection(String section) {
method getIssue (line 26) | public String getIssue() {
method setIssue (line 30) | public void setIssue(String issue) {
method getTitle (line 34) | public String getTitle() {
method setTitle (line 38) | public void setTitle(String title) {
method getBrief (line 42) | public String getBrief() {
method setBrief (line 46) | public void setBrief(String brief) {
method getLink (line 50) | public String getLink() {
method setLink (line 54) | public void setLink(String link) {
method getImageUrl (line 58) | public String getImageUrl() {
method setImageUrl (line 62) | public void setImageUrl(String imageUrl) {
method getDomain (line 66) | public String getDomain() {
method setDomain (line 70) | public void setDomain(String domain) {
method getFTS (line 74) | public String getFTS() {
method toString (line 78) | @Override
method hashCode (line 83) | @Override
method equals (line 88) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Dict.java
class Dict (line 11) | public class Dict {
method Dict (line 20) | public Dict() {
method getContent (line 28) | public String getContent() {
method addPos (line 50) | public void addPos(String pos) {
method addAcceptation (line 54) | public void addAcceptation(String acceptation) {
method getPos (line 58) | public List<String> getPos() {
method setPos (line 62) | public void setPos(List<String> pos) {
method getAcceptation (line 66) | public List<String> getAcceptation() {
method setAcceptation (line 70) | public void setAcceptation(List<String> acceptation) {
method addPs (line 74) | public void addPs(String ps) {
method addPron (line 78) | public void addPron(String pron) {
method addSent (line 82) | public void addSent(Sent sent) {
method getKey (line 86) | public String getKey() {
method setKey (line 90) | public void setKey(String key) {
method getPs (line 94) | public List<String> getPs() {
method setPs (line 98) | public void setPs(List<String> ps) {
method getPron (line 102) | public List<String> getPron() {
method setPron (line 106) | public void setPron(List<String> pron) {
method getSent (line 110) | public List<Sent> getSent() {
method setSent (line 114) | public void setSent(List<Sent> sent) {
method getFy (line 118) | public String getFy() {
method setFy (line 122) | public void setFy(String fy) {
class Sent (line 126) | public static class Sent {
method getOrig (line 130) | public String getOrig() {
method setOrig (line 134) | public void setOrig(String orig) {
method getTrans (line 138) | public String getTrans() {
method setTrans (line 142) | public void setTrans(String trans) {
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Favorite.java
class Favorite (line 8) | public class Favorite implements Serializable {
method Favorite (line 12) | public Favorite(Article article) {
method getArticle (line 17) | public Article getArticle() {
method setArticle (line 21) | public void setArticle(Article article) {
method getTime (line 25) | public long getTime() {
method setTime (line 29) | public void setTime(long time) {
method equals (line 33) | @Override
method hashCode (line 38) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/Issue.java
class Issue (line 8) | public class Issue implements Serializable {
method Issue (line 14) | public Issue(String name) {
method Issue (line 18) | public Issue(String name, boolean active) {
method Issue (line 23) | public Issue(String name, String url, String date) {
method getUrl (line 29) | public String getUrl() {
method setUrl (line 33) | public void setUrl(String url) {
method getDate (line 37) | public String getDate() {
method setDate (line 41) | public void setDate(String date) {
method getName (line 45) | public String getName() {
method setName (line 49) | public void setName(String name) {
method isActive (line 53) | public boolean isActive() {
method setActive (line 57) | public void setActive(boolean active) {
FILE: app/src/main/java/com/github/mzule/androidweekly/entity/TranslateResult.java
class TranslateResult (line 10) | public class TranslateResult {
method getFrom (line 16) | public String getFrom() {
method setFrom (line 20) | public void setFrom(String from) {
method getTo (line 24) | public String getTo() {
method setTo (line 28) | public void setTo(String to) {
method getResult (line 32) | public List<Result> getResult() {
method setResult (line 36) | public void setResult(List<Result> result) {
method getDst (line 40) | public String getDst() {
class Result (line 47) | public static class Result {
method Result (line 51) | public Result(String src, String dst) {
method getSrc (line 56) | public String getSrc() {
method setSrc (line 60) | public void setSrc(String src) {
method getDst (line 64) | public String getDst() {
method setDst (line 68) | public void setDst(String dst) {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/AboutActivity.java
class AboutActivity (line 17) | @Layout(R.layout.activity_about)
method makeIntent (line 22) | public static Intent makeIntent(Context context) {
method afterBind (line 26) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/ArticleActivity.java
class ArticleActivity (line 30) | @Layout(R.layout.activity_article)
method makeIntent (line 45) | public static Intent makeIntent(Context context, Article article) {
method favorite (line 51) | @OnClick(R.id.favoriteButton)
method increate (line 63) | @OnClick(R.id.increaseButton)
method decrease (line 68) | @OnClick(R.id.decreaseButton)
method translateAndPaste (line 73) | @OnClick(R.id.translateButton)
method share (line 79) | @OnClick(R.id.shareButton)
method copyUrl (line 89) | @OnClick(R.id.copyUrlButton)
method afterBind (line 98) | @SuppressLint("SetJavaScriptEnabled")
method onStop (line 118) | @Override
method finish (line 124) | @Override
method onBackPressed (line 132) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/BaseActivity.java
class BaseActivity (line 17) | public abstract class BaseActivity extends FragmentActivity {
method onCreate (line 18) | @Override
method back (line 27) | public void back(View v) {
method onBackPressed (line 31) | @Override
method afterBind (line 41) | protected abstract void afterBind();
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/FavoriteActivity.java
class FavoriteActivity (line 30) | @Layout(R.layout.activity_favorite)
method makeIntent (line 40) | public static Intent makeIntent(Context context) {
method onItemClick (line 44) | @OnItemClick(R.id.listView)
method exportToFile (line 52) | @OnClick(R.id.exportButton)
method importFromFile (line 63) | @OnClick(R.id.importButton)
method afterBind (line 76) | @Override
method renderFavorites (line 84) | private void renderFavorites() {
method extract (line 90) | private List<Object> extract(List<Favorite> favorites) {
method onActivityResult (line 102) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/MainActivity.java
class MainActivity (line 25) | @Layout(R.layout.activity_main)
method onSlideItemClick (line 40) | @OnItemClick(R.id.slideListView)
method onItemClick (line 52) | @OnItemClick(R.id.listView)
method onSlideMenuClick (line 60) | @OnClick(R.id.slideMenuButton)
method onFavoriteClick (line 65) | @OnClick(R.id.favoriteButton)
method onSearchClicK (line 71) | @OnClick(R.id.searchButton)
method onAboutClick (line 77) | @OnClick(R.id.aboutButton)
method afterBind (line 83) | @Override
method active (line 97) | private void active(Issue issue) {
method sendArticleListRequest (line 103) | private void sendArticleListRequest(String issue) {
method sendIssueListRequest (line 120) | private void sendIssueListRequest() {
method onBackPressed (line 136) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchActivity.java
class SearchActivity (line 23) | @Layout(R.layout.activity_search)
method makeIntent (line 31) | public static Intent makeIntent(Context context) {
method onItemClick (line 35) | @OnItemClick(R.id.listView)
method afterBind (line 42) | @Override
method onStart (line 58) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchResultActivity.java
class SearchResultActivity (line 24) | @Layout(R.layout.activity_search_result)
method makeIntent (line 31) | public static Intent makeIntent(Context context, String q) {
method onItemClick (line 37) | @OnItemClick(R.id.listView)
method afterBind (line 45) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/ArticleAdapter.java
class ArticleAdapter (line 14) | public class ArticleAdapter extends TypePerEntityAdapter<Object> impleme...
method ArticleAdapter (line 16) | public ArticleAdapter(Context context) {
method mapEntityViewTypes (line 20) | @Override
method isItemViewTypePinned (line 26) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SearchHistoryAdapter.java
class SearchHistoryAdapter (line 12) | public class SearchHistoryAdapter extends SingleTypeAdapter<String> {
method SearchHistoryAdapter (line 13) | public SearchHistoryAdapter(Context context) {
method singleViewType (line 17) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SlideAdapter.java
class SlideAdapter (line 13) | public class SlideAdapter extends SingleTypeAdapter<Issue> {
method SlideAdapter (line 15) | public SlideAdapter(Context context) {
method singleViewType (line 19) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/IconButton.java
class IconButton (line 13) | public class IconButton extends MaterialIconView {
method IconButton (line 14) | public IconButton(Context context) {
method IconButton (line 18) | public IconButton(Context context, AttributeSet attrs) {
method IconButton (line 22) | public IconButton(Context context, AttributeSet attrs, int defStyle) {
method setPressed (line 26) | @Override
method setSelected (line 38) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/NaviBar.java
class NaviBar (line 19) | @Layout(R.layout.view_navi_bar)
method NaviBar (line 27) | public NaviBar(Context context) {
method NaviBar (line 31) | public NaviBar(Context context, AttributeSet attrs) {
method NaviBar (line 35) | public NaviBar(Context context, AttributeSet attrs, int defStyleAttr) {
method init (line 39) | @Override
method back (line 50) | @OnClick(R.id.backButton)
method setLeftText (line 57) | public void setLeftText(String text) {
method setRightText (line 61) | public void setRightText(String text) {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/PinnedSectionListView.java
class PinnedSectionListView (line 46) | public class PinnedSectionListView extends ListView {
method onScrollStateChanged (line 82) | @Override
method onScroll (line 89) | @Override
method onChanged (line 128) | @Override
method onInvalidated (line 135) | @Override
method PinnedSectionListView (line 142) | public PinnedSectionListView(Context context, AttributeSet attrs) {
method PinnedSectionListView (line 147) | public PinnedSectionListView(Context context, AttributeSet attrs, int ...
method isItemViewTypePinned (line 154) | public static boolean isItemViewTypePinned(ListAdapter adapter, int vi...
method initView (line 161) | private void initView() {
method setShadowVisible (line 167) | public void setShadowVisible(boolean visible) {
method initShadow (line 177) | public void initShadow(boolean visible) {
method createPinnedShadow (line 197) | void createPinnedShadow(int position) {
method destroyPinnedShadow (line 242) | void destroyPinnedShadow() {
method ensureShadowForPosition (line 253) | void ensureShadowForPosition(int sectionPosition, int firstVisibleItem...
method findFirstVisibleSectionPosition (line 293) | int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleI...
method findCurrentSectionPosition (line 312) | int findCurrentSectionPosition(int fromPosition) {
method recreatePinnedShadow (line 336) | void recreatePinnedShadow() {
method setOnScrollListener (line 348) | @Override
method onRestoreInstanceState (line 357) | @Override
method setAdapter (line 368) | @Override
method onLayout (line 391) | @Override
method dispatchDraw (line 403) | @Override
method dispatchTouchEvent (line 436) | @Override
method isPinnedViewTouched (line 496) | private boolean isPinnedViewTouched(View view, float x, float y) {
method clearTouchTarget (line 509) | private void clearTouchTarget() {
method performPinnedItemClick (line 517) | private boolean performPinnedItemClick() {
type PinnedSectionListAdapter (line 536) | public static interface PinnedSectionListAdapter extends ListAdapter {
method isItemViewTypePinned (line 540) | boolean isItemViewTypePinned(int viewType);
class PinnedSection (line 546) | static class PinnedSection {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/PopupView.java
class PopupView (line 20) | public abstract class PopupView<T> extends BaseRelativeLayout {
method PopupView (line 28) | public PopupView(Context context) {
method attachTo (line 39) | public PopupView<T> attachTo(Activity activity, T data) {
method attachTo (line 52) | public PopupView<T> attachTo(Activity activity, T data, FrameLayout.La...
method getAnimationDirection (line 64) | protected int getAnimationDirection() {
method animateIn (line 71) | protected void animateIn() {
method finish (line 116) | public void finish() {
method finish (line 123) | public void finish(final FinishCallback callback) {
method render (line 171) | protected abstract void render(T data);
method getMaskView (line 178) | protected abstract View getMaskView();
method getMainView (line 186) | protected abstract View getMainView();
type FinishCallback (line 188) | public interface FinishCallback {
method afterFinish (line 189) | void afterFinish();
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/ProgressView.java
class ProgressView (line 16) | public class ProgressView extends ProgressWheel {
method ProgressView (line 17) | public ProgressView(Context context, AttributeSet attrs) {
method ProgressView (line 22) | public ProgressView(Context context) {
method init (line 27) | private void init() {
method start (line 36) | public void start() {
method stop (line 40) | public void stop() {
method onMeasure (line 44) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/TintStatusBar.java
class TintStatusBar (line 14) | public class TintStatusBar extends View {
method TintStatusBar (line 17) | public TintStatusBar(Context context) {
method TintStatusBar (line 22) | public TintStatusBar(Context context, AttributeSet attrs) {
method TintStatusBar (line 27) | public TintStatusBar(Context context, AttributeSet attrs, int defStyle...
method init (line 32) | public void init() {
method onMeasure (line 36) | @Override
method getStatusBarHeight (line 48) | public int getStatusBarHeight() {
method setHeightPercent (line 57) | public void setHeightPercent(float percent) {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/TranslateView.java
class TranslateView (line 26) | @Layout(R.layout.view_translate)
method TranslateView (line 35) | public TranslateView(Context context) {
method finish (line 39) | @OnClick(R.id.maskView)
method hideKeyboard (line 46) | private void hideKeyboard() {
method clear (line 52) | @OnClick(R.id.clearButton)
method translate (line 60) | @OnClick(R.id.translateButton)
method render (line 78) | @Override
method updateResultViewMaxHeight (line 89) | private void updateResultViewMaxHeight() {
method getPasteText (line 94) | @Nullable
method getMaskView (line 106) | @Override
method getMainView (line 111) | @Override
method getAnimationDirection (line 116) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseLinearLayout.java
class BaseLinearLayout (line 15) | public class BaseLinearLayout extends LinearLayout {
method BaseLinearLayout (line 17) | public BaseLinearLayout(Context context) {
method BaseLinearLayout (line 22) | public BaseLinearLayout(Context context, AttributeSet attrs) {
method BaseLinearLayout (line 27) | public BaseLinearLayout(Context context, AttributeSet attrs, int defSt...
method init (line 32) | protected void init(Context context, AttributeSet attrs) {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseRelativeLayout.java
class BaseRelativeLayout (line 15) | public class BaseRelativeLayout extends RelativeLayout {
method BaseRelativeLayout (line 17) | public BaseRelativeLayout(Context context, AttributeSet attrs, int def...
method init (line 22) | private void init() {
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/ArticleViewType.java
class ArticleViewType (line 18) | @Layout(R.layout.item_article)
method onRender (line 29) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/BaseViewType.java
class BaseViewType (line 15) | public abstract class BaseViewType<T> extends ViewType<T> {
method onCreate (line 16) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SearchHistoryViewType.java
class SearchHistoryViewType (line 13) | @Layout(R.layout.item_search_history)
method onRender (line 18) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SectionViewType.java
class SectionViewType (line 13) | @Layout(R.layout.item_section)
method onRender (line 18) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SlideIssueViewType.java
class SlideIssueViewType (line 15) | @Layout(R.layout.item_slide_issue)
method onRender (line 24) | @Override
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DateUtil.java
class DateUtil (line 11) | public class DateUtil {
method format (line 15) | public static String format(long time) {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DensityUtil.java
class DensityUtil (line 9) | public class DensityUtil {
method dp2px (line 10) | public static int dp2px(float dp) {
method px2dp (line 15) | public static float px2dp(float px) {
method screenWidth (line 20) | public static int screenWidth() {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/DictParser.java
class DictParser (line 16) | public class DictParser {
method DictParser (line 20) | public DictParser(String url) {
method parse (line 24) | public Dict parse() throws IOException, XmlPullParserException {
method readDict (line 33) | private void readDict(XmlPullParser parser) throws IOException, XmlPul...
method parseSent (line 67) | private void parseSent(XmlPullParser parser) throws IOException, XmlPu...
method readText (line 88) | private String readText(XmlPullParser parser) throws IOException, XmlP...
FILE: app/src/main/java/com/github/mzule/androidweekly/util/IOUtil.java
class IOUtil (line 13) | public class IOUtil {
method close (line 14) | public static void close(Closeable... closeables) {
method close (line 29) | public static void close(AutoCloseable... closeables) {
method read (line 44) | public static String read(File file) throws IOException {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/JsonUtil.java
class JsonUtil (line 15) | public class JsonUtil {
method toJson (line 18) | public static String toJson(Object obj) {
method fromJson (line 26) | public static <T> T fromJson(String json, Class<T> cls) {
method fromJson (line 34) | public static <T> T fromJson(String json, Type type) {
method fromJson (line 42) | @WorkerThread
FILE: app/src/main/java/com/github/mzule/androidweekly/util/Keyboard.java
class Keyboard (line 11) | public class Keyboard {
method show (line 12) | public static void show(Context context) {
method hide (line 17) | public static void hide(Activity activity) {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/MD5.java
class MD5 (line 9) | public class MD5 {
method encode (line 11) | public static String encode(final String s) {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/StemUtil.java
class StemUtil (line 8) | public class StemUtil {
method stem (line 9) | public static String stem(String input) {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/ThreadUtil.java
class ThreadUtil (line 6) | public class ThreadUtil {
method sleepUntilNextDraw (line 7) | public static void sleepUntilNextDraw(long startTime) {
FILE: app/src/main/java/com/github/mzule/androidweekly/util/Tinter.java
class Tinter (line 18) | public class Tinter {
method enableIfSupport (line 25) | public static void enableIfSupport(Activity activity) {
method isSupport (line 36) | public static boolean isSupport() {
method tint (line 40) | @TargetApi(19)
FILE: app/src/test/java/com/github/mzule/androidweekly/ExampleUnitTest.java
class ExampleUnitTest (line 10) | public class ExampleUnitTest {
method addition_isCorrect (line 11) | @Test
FILE: snowball/src/main/java/org/tartarus/snowball/Among.java
class Among (line 5) | public class Among {
method Among (line 13) | public Among(String s, int substring_i, int result,
FILE: snowball/src/main/java/org/tartarus/snowball/SnowballProgram.java
class SnowballProgram (line 6) | public class SnowballProgram {
method SnowballProgram (line 15) | protected SnowballProgram() {
method getCurrent (line 23) | public String getCurrent() {
method setCurrent (line 38) | public void setCurrent(String value) {
method copy_from (line 47) | protected void copy_from(SnowballProgram other) {
method in_grouping (line 56) | protected boolean in_grouping(char[] s, int min, int max) {
method in_grouping_b (line 66) | protected boolean in_grouping_b(char[] s, int min, int max) {
method out_grouping (line 76) | protected boolean out_grouping(char[] s, int min, int max) {
method out_grouping_b (line 91) | protected boolean out_grouping_b(char[] s, int min, int max) {
method in_range (line 106) | protected boolean in_range(int min, int max) {
method in_range_b (line 114) | protected boolean in_range_b(int min, int max) {
method out_range (line 122) | protected boolean out_range(int min, int max) {
method out_range_b (line 130) | protected boolean out_range_b(int min, int max) {
method eq_s (line 138) | protected boolean eq_s(int s_size, String s) {
method eq_s_b (line 148) | protected boolean eq_s_b(int s_size, String s) {
method eq_v (line 158) | protected boolean eq_v(CharSequence s) {
method eq_v_b (line 162) | protected boolean eq_v_b(CharSequence s) {
method find_among (line 166) | protected int find_among(Among v[], int v_size) {
method find_among_b (line 238) | protected int find_among_b(Among v[], int v_size) {
method replace_s (line 308) | protected int replace_s(int c_bra, int c_ket, String s) {
method slice_check (line 317) | protected void slice_check() {
method slice_from (line 333) | protected void slice_from(String s) {
method slice_from (line 338) | protected void slice_from(CharSequence s) {
method slice_del (line 342) | protected void slice_del() {
method insert (line 346) | protected void insert(int c_bra, int c_ket, String s) {
method insert (line 352) | protected void insert(int c_bra, int c_ket, CharSequence s) {
method slice_to (line 357) | protected StringBuffer slice_to(StringBuffer s) {
method slice_to (line 365) | protected StringBuilder slice_to(StringBuilder s) {
method assign_to (line 372) | protected StringBuffer assign_to(StringBuffer s) {
method assign_to (line 377) | protected StringBuilder assign_to(StringBuilder s) {
FILE: snowball/src/main/java/org/tartarus/snowball/SnowballStemmer.java
class SnowballStemmer (line 4) | public abstract class SnowballStemmer extends SnowballProgram {
method stem (line 5) | public abstract boolean stem();
FILE: snowball/src/main/java/org/tartarus/snowball/TestApp.java
class TestApp (line 14) | public class TestApp {
method usage (line 15) | private static void usage() {
method main (line 19) | public static void main(String[] args) throws Throwable {
FILE: snowball/src/main/java/org/tartarus/snowball/ext/EnglishStem.java
class EnglishStem (line 12) | public class EnglishStem extends org.tartarus.snowball.SnowballStemmer {
method copy_from (line 171) | private void copy_from(EnglishStem other) {
method r_prelude (line 178) | private boolean r_prelude() {
method r_mark_regions (line 275) | private boolean r_mark_regions() {
method r_shortv (line 370) | private boolean r_shortv() {
method r_R1 (line 407) | private boolean r_R1() {
method r_R2 (line 414) | private boolean r_R2() {
method r_Step_1a (line 421) | private boolean r_Step_1a() {
method r_Step_1b (line 524) | private boolean r_Step_1b() {
method r_Step_1c (line 633) | private boolean r_Step_1c() {
method r_Step_2 (line 680) | private boolean r_Step_2() {
method r_Step_3 (line 790) | private boolean r_Step_3() {
method r_Step_4 (line 847) | private boolean r_Step_4() {
method r_Step_5 (line 899) | private boolean r_Step_5() {
method r_exception2 (line 970) | private boolean r_exception2() {
method r_exception1 (line 987) | private boolean r_exception1() {
method r_postlude (line 1065) | private boolean r_postlude() {
method stem (line 1114) | public boolean stem() {
method equals (line 1288) | public boolean equals(Object o) {
method hashCode (line 1292) | public int hashCode() {
Condensed preview — 106 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (239K chars).
[
{
"path": ".gitignore",
"chars": 65,
"preview": "*.iml\n.gradle\n/local.properties\n.idea\n.DS_Store\n/build\n/captures\n"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1594,
"preview": "# AndroidWeekly\n\n一个第三方 androidweekly.net 的客户端,主要用 jsoup 抓取了 androidweekly.net 的数据进行展示,很适合在空暇时间阅读浏览。\n\n## 目前实现的功能\n\n1. 文章列表"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 1161,
"preview": "apply plugin: 'com.android.application'\napply plugin: 'android-apt'\n\nandroid {\n compileSdkVersion 23\n buildToolsVe"
},
{
"path": "app/proguard-rules.pro",
"chars": 663,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
},
{
"path": "app/src/androidTest/java/com/github/mzule/androidweekly/ApplicationTest.java",
"chars": 361,
"preview": "package com.github.mzule.androidweekly;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n "
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 1341,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/App.java",
"chars": 365,
"preview": "package com.github.mzule.androidweekly;\n\nimport android.app.Application;\n\n/**\n * Created by CaoDongping on 3/24/16.\n */\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/ApiCallback.java",
"chars": 210,
"preview": "package com.github.mzule.androidweekly.api;\n\n/**\n * Created by CaoDongping on 3/24/16.\n */\npublic interface ApiCallback<"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/ArticleApi.java",
"chars": 4560,
"preview": "package com.github.mzule.androidweekly.api;\n\n\nimport android.os.Handler;\nimport android.text.TextUtils;\n\nimport com.gith"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/DictionaryApi.java",
"chars": 1347,
"preview": "package com.github.mzule.androidweekly.api;\n\nimport android.os.Handler;\n\nimport com.github.mzule.androidweekly.entity.Di"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParser.java",
"chars": 242,
"preview": "package com.github.mzule.androidweekly.api.parser;\n\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * Created b"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/parser/ArticleParsers.java",
"chars": 453,
"preview": "package com.github.mzule.androidweekly.api.parser;\n\nimport android.support.annotation.WorkerThread;\n\n/**\n * Created by C"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/parser/DocumentProvider.java",
"chars": 476,
"preview": "package com.github.mzule.androidweekly.api.parser;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\n\nimport jav"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/parser/FresherArticlesParser.java",
"chars": 2482,
"preview": "package com.github.mzule.androidweekly.api.parser;\n\nimport com.github.mzule.androidweekly.entity.Article;\n\nimport org.js"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/api/parser/OlderArticlesParser.java",
"chars": 2658,
"preview": "package com.github.mzule.androidweekly.api.parser;\n\nimport com.github.mzule.androidweekly.entity.Article;\n\nimport org.js"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/dao/ArticleDao.java",
"chars": 3974,
"preview": "package com.github.mzule.androidweekly.dao;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimpor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/dao/FavoriteDao.java",
"chars": 5853,
"preview": "package com.github.mzule.androidweekly.dao;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimpor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/dao/IssueListKeeper.java",
"chars": 1048,
"preview": "package com.github.mzule.androidweekly.dao;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/dao/SearchHistoryKeeper.java",
"chars": 1314,
"preview": "package com.github.mzule.androidweekly.dao;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\ni"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/dao/TextZoomKeeper.java",
"chars": 618,
"preview": "package com.github.mzule.androidweekly.dao;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/entity/Article.java",
"chars": 1960,
"preview": "package com.github.mzule.androidweekly.entity;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\n\n/**\n * Created by"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/entity/Dict.java",
"chars": 3168,
"preview": "package com.github.mzule.androidweekly.entity;\n\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java."
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/entity/Favorite.java",
"chars": 851,
"preview": "package com.github.mzule.androidweekly.entity;\n\nimport java.io.Serializable;\n\n/**\n * Created by CaoDongping on 3/28/16.\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/entity/Issue.java",
"chars": 1116,
"preview": "package com.github.mzule.androidweekly.entity;\n\nimport java.io.Serializable;\n\n/**\n * Created by CaoDongping on 3/25/16.\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/entity/TranslateResult.java",
"chars": 1405,
"preview": "package com.github.mzule.androidweekly.entity;\n\nimport com.google.gson.annotations.SerializedName;\n\nimport java.util.Lis"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/AboutActivity.java",
"chars": 1178,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/ArticleActivity.java",
"chars": 4491,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.annotation.SuppressLint;\nimport android.content.Clip"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/BaseActivity.java",
"chars": 1110,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.os.Bundle;\nimport android.support.v4.app.FragmentAct"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/FavoriteActivity.java",
"chars": 3502,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/MainActivity.java",
"chars": 4289,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.support.v4.view.GravityCompat;\nimport android.suppor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchActivity.java",
"chars": 2059,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/activity/SearchResultActivity.java",
"chars": 1747,
"preview": "package com.github.mzule.androidweekly.ui.activity;\n\nimport android.content.Context;\nimport android.content.Intent;\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/adapter/ArticleAdapter.java",
"chars": 985,
"preview": "package com.github.mzule.androidweekly.ui.adapter;\n\nimport android.content.Context;\n\nimport com.github.mzule.androidweek"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SearchHistoryAdapter.java",
"chars": 582,
"preview": "package com.github.mzule.androidweekly.ui.adapter;\n\nimport android.content.Context;\n\nimport com.github.mzule.androidweek"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/adapter/SlideAdapter.java",
"chars": 613,
"preview": "package com.github.mzule.androidweekly.ui.adapter;\n\nimport android.content.Context;\n\nimport com.github.mzule.androidweek"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/IconButton.java",
"chars": 1469,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/NaviBar.java",
"chars": 1740,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport and"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/PinnedSectionListView.java",
"chars": 20139,
"preview": "/*\n * Copyright (C) 2013 Sergej Shafarenka, halfbit.de\n *\n * Licensed under the Apache License, Version 2.0 (the \"Licens"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/PopupView.java",
"chars": 6721,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorLis"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/ProgressView.java",
"chars": 1410,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimpor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/TintStatusBar.java",
"chars": 1809,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimpor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/TranslateView.java",
"chars": 3499,
"preview": "package com.github.mzule.androidweekly.ui.view;\n\nimport android.app.Activity;\nimport android.content.ClipData;\nimport an"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseLinearLayout.java",
"chars": 893,
"preview": "package com.github.mzule.androidweekly.ui.view.base;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/view/base/BaseRelativeLayout.java",
"chars": 608,
"preview": "package com.github.mzule.androidweekly.ui.view.base;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/ArticleViewType.java",
"chars": 1146,
"preview": "package com.github.mzule.androidweekly.ui.viewtype;\n\nimport android.text.TextUtils;\nimport android.view.View;\nimport and"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/BaseViewType.java",
"chars": 517,
"preview": "/*\n * Copyright (C) 2016 Baidu, Inc. All Rights Reserved.\n */\npackage com.github.mzule.androidweekly.ui.viewtype;\n\nimpor"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SearchHistoryViewType.java",
"chars": 509,
"preview": "package com.github.mzule.androidweekly.ui.viewtype;\n\nimport android.widget.TextView;\n\nimport com.github.mzule.androidwee"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SectionViewType.java",
"chars": 506,
"preview": "package com.github.mzule.androidweekly.ui.viewtype;\n\nimport android.widget.TextView;\n\nimport com.github.mzule.androidwee"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/ui/viewtype/SlideIssueViewType.java",
"chars": 988,
"preview": "package com.github.mzule.androidweekly.ui.viewtype;\n\nimport android.view.View;\nimport android.widget.TextView;\n\nimport c"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/DateUtil.java",
"chars": 431,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport android.annotation.SuppressLint;\n\nimport java.text.DateFormat;\nimpo"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/DensityUtil.java",
"chars": 632,
"preview": "package com.github.mzule.androidweekly.util;\n\n\nimport com.github.mzule.androidweekly.App;\n\n/**\n * Created by CaoDongping"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/DictParser.java",
"chars": 2932,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport android.util.Xml;\n\nimport com.github.mzule.androidweekly.entity.Dic"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/IOUtil.java",
"chars": 1545,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.Fi"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/JsonUtil.java",
"chars": 1206,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport android.support.annotation.WorkerThread;\n\nimport com.google.gson.Gs"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/Keyboard.java",
"chars": 810,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androi"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/MD5.java",
"chars": 1005,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmEx"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/StemUtil.java",
"chars": 584,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport org.tartarus.snowball.ext.EnglishStem;\n\n/**\n * Created by CaoDongpi"
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/ThreadUtil.java",
"chars": 445,
"preview": "package com.github.mzule.androidweekly.util;\n\n/**\n * Created by CaoDongping on 1/12/16.\n */\npublic class ThreadUtil {\n "
},
{
"path": "app/src/main/java/com/github/mzule/androidweekly/util/Tinter.java",
"chars": 1725,
"preview": "package com.github.mzule.androidweekly.util;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport a"
},
{
"path": "app/src/main/res/anim/slide_in_left.xml",
"chars": 260,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <translate\n "
},
{
"path": "app/src/main/res/anim/slide_in_right.xml",
"chars": 259,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <translate\n "
},
{
"path": "app/src/main/res/anim/slide_out_left.xml",
"chars": 260,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <translate\n "
},
{
"path": "app/src/main/res/anim/slide_out_right.xml",
"chars": 259,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <translate\n "
},
{
"path": "app/src/main/res/color/text_color_slide_date.xml",
"chars": 278,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/src/main/res/color/text_color_slide_issue.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/src/main/res/drawable/bg_button.xml",
"chars": 257,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/src/main/res/drawable/bg_button_n.xml",
"chars": 163,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <solid and"
},
{
"path": "app/src/main/res/drawable/bg_button_s.xml",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <solid and"
},
{
"path": "app/src/main/res/drawable/bg_dialog.xml",
"chars": 224,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:sha"
},
{
"path": "app/src/main/res/drawable/ic_slide_menu.xml",
"chars": 297,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/src/main/res/layout/activity_about.xml",
"chars": 972,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "app/src/main/res/layout/activity_article.xml",
"chars": 3653,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com"
},
{
"path": "app/src/main/res/layout/activity_favorite.xml",
"chars": 1852,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com"
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 4692,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com"
},
{
"path": "app/src/main/res/layout/activity_search.xml",
"chars": 1663,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "app/src/main/res/layout/activity_search_result.xml",
"chars": 727,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "app/src/main/res/layout/item_article.xml",
"chars": 2091,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n a"
},
{
"path": "app/src/main/res/layout/item_search_history.xml",
"chars": 606,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app/src/main/res/layout/item_section.xml",
"chars": 807,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/layout/item_slide_issue.xml",
"chars": 1241,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/layout/view_navi_bar.xml",
"chars": 1944,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "app/src/main/res/layout/view_translate.xml",
"chars": 3668,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app/src/main/res/values/attrs.xml",
"chars": 234,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"NaviBar\">\n <attr name=\"nb_left_te"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 657,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#36bce8</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/dimens.xml",
"chars": 382,
"preview": "<resources>\n <dimen name=\"text_size_tiny\">10sp</dimen>\n <dimen name=\"text_size_small\">12sp</dimen>\n <dimen name"
},
{
"path": "app/src/main/res/values/ids.xml",
"chars": 107,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <item name=\"popup_view_id\" type=\"id\" />\n</resources>"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 69,
"preview": "<resources>\n <string name=\"app_name\">Weekly</string>\n</resources>\n"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 2578,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
},
{
"path": "app/src/main/res/values-w820dp/dimens.xml",
"chars": 358,
"preview": "<resources>\n <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n (such as s"
},
{
"path": "app/src/test/java/com/github/mzule/androidweekly/ExampleUnitTest.java",
"chars": 323,
"preview": "package com.github.mzule.androidweekly;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * To work on un"
},
{
"path": "build.gradle",
"chars": 431,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n r"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 231,
"preview": "#Sat Apr 09 16:59:39 CST 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 753,
"preview": "## Project-wide Gradle settings.\n#\n# For more details on how to configure your build environment visit\n# http://www.grad"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "settings.gradle",
"chars": 28,
"preview": "include ':app', ':snowball'\n"
},
{
"path": "snowball/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "snowball/build.gradle",
"chars": 145,
"preview": "apply plugin: 'java'\n\nsourceCompatibility = 1.7\ntargetCompatibility = 1.7\n\ndependencies {\n compile fileTree(dir: 'lib"
},
{
"path": "snowball/src/main/java/org/tartarus/snowball/Among.java",
"chars": 1132,
"preview": "package org.tartarus.snowball;\n\nimport java.lang.reflect.Method;\n\npublic class Among {\n public final int s_size; /* s"
},
{
"path": "snowball/src/main/java/org/tartarus/snowball/SnowballProgram.java",
"chars": 12014,
"preview": "\npackage org.tartarus.snowball;\n\nimport java.lang.reflect.InvocationTargetException;\n\npublic class SnowballProgram {\n "
},
{
"path": "snowball/src/main/java/org/tartarus/snowball/SnowballStemmer.java",
"chars": 136,
"preview": "\npackage org.tartarus.snowball;\n\npublic abstract class SnowballStemmer extends SnowballProgram {\n public abstract boo"
},
{
"path": "snowball/src/main/java/org/tartarus/snowball/TestApp.java",
"chars": 2260,
"preview": "\npackage org.tartarus.snowball;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileInputS"
},
{
"path": "snowball/src/main/java/org/tartarus/snowball/ext/EnglishStem.java",
"chars": 39245,
"preview": "// This file was generated automatically by the Snowball to Java compiler\n\npackage org.tartarus.snowball.ext;\n\nimport or"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the mzule/AndroidWeekly GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 106 files (214.3 KB), approximately 52.7k tokens, and a symbol index with 396 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.