├── .gitignore
├── Daily.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── libs
│ └── universal-image-loader-1.9.3-with-sources.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── aspsine
│ │ └── zhihu
│ │ └── daily
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── aspsine
│ │ └── zhihu
│ │ └── daily
│ │ ├── App.java
│ │ ├── Constants.java
│ │ ├── CrashHandler.java
│ │ ├── animation
│ │ └── AnimationEndListener.java
│ │ ├── api
│ │ ├── DailyApi.java
│ │ ├── DailyApiService.java
│ │ └── RestApi.java
│ │ ├── db
│ │ ├── CacheDao.java
│ │ ├── DBOpenHelper.java
│ │ └── SQLUtils.java
│ │ ├── interfaces
│ │ └── NavigationDrawerCallbacks.java
│ │ ├── model
│ │ ├── Cache.java
│ │ ├── DailyStories.java
│ │ ├── Editor.java
│ │ ├── StartImage.java
│ │ ├── Story.java
│ │ ├── Theme.java
│ │ └── Themes.java
│ │ ├── network
│ │ ├── BaseHttp.java
│ │ ├── BaseHttpClient.java
│ │ ├── CacheInterceptor.java
│ │ ├── Http.java
│ │ └── OkHttp.java
│ │ ├── respository
│ │ ├── CacheRepositoryImpl.java
│ │ ├── NetRepositoryImpl.java
│ │ ├── RepositoryImpl.java
│ │ └── interfaces
│ │ │ ├── CacheRepository.java
│ │ │ ├── NetRepository.java
│ │ │ └── Repository.java
│ │ ├── ui
│ │ ├── activity
│ │ │ ├── BaseAppCompatActivity.java
│ │ │ ├── GuiderActivity.java
│ │ │ ├── NavigationDrawerActivity.java
│ │ │ ├── SettingsActivity.java
│ │ │ └── StoryActivity.java
│ │ ├── adapter
│ │ │ ├── DailyStoriesAdapter.java
│ │ │ ├── NavigationDrawerAdapter.java
│ │ │ ├── ThemeStoriesAdapter.java
│ │ │ └── holder
│ │ │ │ ├── DateViewHolder.java
│ │ │ │ ├── HeaderViewPagerHolder.java
│ │ │ │ ├── RecyclerHeaderViewHolder.java
│ │ │ │ └── StoryViewHolder.java
│ │ ├── fragment
│ │ │ ├── BaseFragment.java
│ │ │ ├── DailyStoriesFragment.java
│ │ │ ├── GuideFragment.java
│ │ │ ├── NavigationFragment.java
│ │ │ ├── SettingsFragment.java
│ │ │ ├── SplashFragment.java
│ │ │ ├── StoryFragment.java
│ │ │ └── ThemeStoriesFragment.java
│ │ └── widget
│ │ │ ├── AvatarsView.java
│ │ │ ├── CheckableLinearLayout.java
│ │ │ ├── CircleBitmapDisplayer.java
│ │ │ ├── CirclePageIndicator.java
│ │ │ ├── LoadMoreRecyclerView.java
│ │ │ ├── MySwipeRefreshLayout.java
│ │ │ ├── MyViewPager.java
│ │ │ ├── PageIndicator.java
│ │ │ └── StoryHeaderView.java
│ │ └── util
│ │ ├── DateUtils.java
│ │ ├── DensityUtil.java
│ │ ├── FileUtils.java
│ │ ├── IntentUtils.java
│ │ ├── L.java
│ │ ├── ListUtils.java
│ │ ├── NetWorkUtils.java
│ │ ├── ScrollPullDownHelper.java
│ │ ├── SharedPrefUtils.java
│ │ ├── UIUtils.java
│ │ └── WebUtils.java
│ └── res
│ ├── anim
│ └── splash.xml
│ ├── drawable-hdpi
│ ├── comment_avatar.png
│ ├── dark_comment_avatar.png
│ ├── drawer_shadow.9.png
│ ├── home_pic.png
│ ├── ic_launcher.png
│ ├── ic_logo.png
│ ├── menu_home.png
│ └── splash_logo.png
│ ├── drawable-mdpi
│ ├── comment_avatar.png
│ ├── dark_comment_avatar.png
│ ├── drawer_shadow.9.png
│ ├── home_pic.png
│ ├── ic_launcher.png
│ ├── ic_logo.png
│ ├── menu_home.png
│ └── splash_logo.png
│ ├── drawable-xhdpi
│ ├── comment_avatar.png
│ ├── dark_comment_avatar.png
│ ├── drawer_shadow.9.png
│ ├── home_pic.png
│ ├── ic_launcher.png
│ ├── ic_logo.png
│ ├── menu_home.png
│ └── splash_logo.png
│ ├── drawable-xxhdpi
│ ├── comment_avatar.png
│ ├── dark_comment_avatar.png
│ ├── drawer_shadow.9.png
│ ├── home_pic.png
│ ├── ic_launcher.png
│ ├── ic_logo.png
│ ├── menu_home.png
│ └── splash_logo.png
│ ├── drawable-xxxhdpi
│ └── ic_launcher.png
│ ├── drawable
│ ├── bg_splash.jpg
│ ├── circle_mask.xml
│ ├── dark_image_small_default.png
│ ├── image_small_default.png
│ ├── mask.xml
│ └── selected_navdrawer_item_background.xml
│ ├── layout
│ ├── activity_guider.xml
│ ├── activity_navigation_drawer.xml
│ ├── activity_settings.xml
│ ├── activity_story.xml
│ ├── fragment_daily_stories.xml
│ ├── fragment_guide.xml
│ ├── fragment_navigation.xml
│ ├── fragment_settings.xml
│ ├── fragment_splash.xml
│ ├── fragment_story.xml
│ ├── fragment_theme_stories.xml
│ ├── layout_actionbar_toolbar.xml
│ ├── layout_avatars.xml
│ ├── nav_drawer_header.xml
│ ├── nav_drawer_item.xml
│ ├── nav_drawer_separator.xml
│ ├── recycler_header.xml
│ ├── recycler_header_viewpager.xml
│ ├── recycler_item_date.xml
│ ├── recycler_item_story.xml
│ ├── view_avatars.xml
│ └── view_header_story.xml
│ ├── menu
│ ├── global.xml
│ ├── menu_guider.xml
│ ├── menu_navigation_drawer.xml
│ └── menu_story.xml
│ ├── values-v19
│ └── styles.xml
│ ├── values-v21
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ ├── values-zh
│ └── strings.xml
│ ├── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── default.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── strings_activity_settings.xml
│ └── styles.xml
│ └── xml
│ ├── pref_data_sync.xml
│ ├── pref_general.xml
│ ├── pref_headers.xml
│ └── pref_notification.xml
├── art
├── daily.apk
├── detail.png
├── drawer.png
├── main.png
├── section.png
└── splash.png
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea
4 | .DS_Store
5 | /build
6 |
--------------------------------------------------------------------------------
/Daily.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Daily
2 | A demo app of Zhihu Daily with full Material Design and new widgets. It's more lighter(less than 2mb) and smarter(no ad, no account) than official app.
3 |
4 | ### Download
5 | [download](https://raw.githubusercontent.com/Aspsine/Daily/master/art/daily.apk)
6 |
7 | ### Features
8 | - Full Material Design
9 | - Android Compat Theme
10 | - RecyclerView
11 | - Toolbar
12 | - SwipeRefreshLayout
13 | - CardView
14 | - DrawerLayout
15 | - ActionBarDrawerToggle
16 | - Animations
17 | - RESTful API Design
18 |
19 | ### Libraris:
20 | - com.android.support:support-v4:22.1.0
21 | - com.android.support:appcompat-v7:22.1.0
22 | - com.android.support:recyclerview-v7:22.1.0
23 | - com.android.support:cardview-v7:22.1.0
24 | - com.google.code.gson:gson:2.3.1
25 | - com.jakewharton:butterknife:6.0.0
26 | - com.squareup.retrofit:retrofit:1.9.0
27 | - com.squareup.okhttp:okhttp:2.3.0
28 |
29 | ### Version
30 | - 1.0 Beta
31 |
32 | ### TODO List
33 | - Actionbar date change(Done)
34 | - Item read status(set color grey)
35 | - Add News section List(Done)
36 | - Off-line data cache(Done)
37 | - Settings
38 | - MVC -> MVP project Refactoring
39 | - Network interface encryption
40 | - Proguard
41 |
42 | ### ScreenShot
43 | 
44 | 
45 | 
46 | 
47 | 
48 |
49 | ### Contact Me
50 | - Github: github.com/aspsine
51 | - Email: littleximail@gmail.com
52 | - Linkedin: cn.linkedin.com/in/aspsine
53 |
54 | ### License
55 |
56 | Copyright 2015 Zhihu Inc. All rights reserved.
57 |
58 | Licensed under the Apache License, Version 2.0 (the "License");
59 | you may not use this file except in compliance with the License.
60 | You may obtain a copy of the License at
61 |
62 | http://www.apache.org/licenses/LICENSE-2.0
63 |
64 | Unless required by applicable law or agreed to in writing, software
65 | distributed under the License is distributed on an "AS IS" BASIS,
66 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67 | See the License for the specific language governing permissions and
68 | limitations under the License.
69 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | app.iml
3 |
4 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.aspsine.zhihu.daily"
9 | minSdkVersion 11
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 |
25 | compile 'com.android.support:support-v4:22.1.0'
26 | compile 'com.android.support:appcompat-v7:22.1.0'
27 | compile 'com.android.support:recyclerview-v7:22.1.0'
28 | compile 'com.android.support:cardview-v7:22.1.0'
29 | compile 'com.google.code.gson:gson:2.3.1'
30 | compile 'com.jakewharton:butterknife:6.0.0'
31 | compile 'com.squareup.retrofit:retrofit:1.9.0'
32 | compile 'com.squareup.okhttp:okhttp:2.3.0'
33 | }
34 |
--------------------------------------------------------------------------------
/app/libs/universal-image-loader-1.9.3-with-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/libs/universal-image-loader-1.9.3-with-sources.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/aspsine/zhihu/daily/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
38 |
39 |
40 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/App.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.os.StrictMode;
7 |
8 | import com.aspsine.zhihu.daily.respository.RepositoryImpl;
9 | import com.aspsine.zhihu.daily.respository.interfaces.Repository;
10 | import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
11 | import com.nostra13.universalimageloader.core.ImageLoader;
12 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
13 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
14 |
15 | /**
16 | * Created by sf on 2015/1/12.
17 | *
18 | * Application of the app
19 | */
20 | public class App extends Application {
21 | private static Context applicationContext;
22 | private static Repository sRepository;
23 |
24 | @Override
25 | public void onCreate() {
26 |
27 | setStrictMode();
28 |
29 | super.onCreate();
30 |
31 | applicationContext = getApplicationContext();
32 |
33 | // CrashHandler.getInstance(getApplicationContext());
34 |
35 | initImageLoader(getApplicationContext());
36 | }
37 |
38 | /**
39 | * issue: retrofit Memory leak in StrickMode
40 | * https://github.com/square/retrofit/issues/801
41 | */
42 | private void setStrictMode() {
43 | if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
44 | StrictMode.enableDefaults();
45 | }
46 | }
47 |
48 | private void initImageLoader(final Context context) {
49 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
50 | .threadPriority(Thread.NORM_PRIORITY - 2)
51 | .denyCacheImageMultipleSizesInMemory()
52 | .diskCacheFileNameGenerator(new Md5FileNameGenerator())
53 | .diskCacheSize(Constants.Config.IMAGE_CACHE_SIZE) // 50 Mb
54 | .tasksProcessingOrder(QueueProcessingType.LIFO)
55 | // .writeDebugLogs() // Remove for release app
56 | .build();
57 | ImageLoader.getInstance().init(config);
58 | }
59 |
60 | public static Context getContext() {
61 | return applicationContext;
62 | }
63 |
64 | /**
65 | * NOTE:there is no multiThread use simple singleton
66 | * @return
67 | */
68 | public static Repository getRepository() {
69 | if (sRepository == null) {
70 | sRepository = new RepositoryImpl(applicationContext);
71 | }
72 | return sRepository;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/Constants.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily;
2 |
3 | /**
4 | * Created by Aspsine on 2015/2/28.
5 | */
6 | public class Constants {
7 | public static class Config {
8 | public static final String CHARSET = "UTF-8";
9 |
10 | public static final String DATABASE_NAME = "DailyDB";
11 | public static final int DATABASE_VERSION = 1;
12 |
13 | public static final int IMAGE_CACHE_SIZE = 50 * 1024 * 1024;
14 |
15 | public static final int HTTP_CACHE_SIZE = 20 * 1024 * 1024;
16 | public static final int HTTP_CONNECT_TIMEOUT = 15 * 1000;
17 | public static final int HTTP_READ_TIMEOUT = 20 * 1000;
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/CrashHandler.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.content.pm.PackageManager.NameNotFoundException;
7 | import android.os.Build;
8 | import android.os.Debug;
9 | import android.os.Environment;
10 | import android.util.Log;
11 |
12 | import java.io.File;
13 | import java.io.FileOutputStream;
14 | import java.io.PrintWriter;
15 | import java.io.StringWriter;
16 | import java.io.Writer;
17 | import java.lang.Thread.UncaughtExceptionHandler;
18 | import java.lang.reflect.Field;
19 | import java.text.DateFormat;
20 | import java.text.SimpleDateFormat;
21 | import java.util.Date;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | /**
26 | * 处理程序中未捕获的异常,将异常写入日志文件
27 | */
28 | public class CrashHandler implements UncaughtExceptionHandler {
29 | public static final String TAG = CrashHandler.class.getSimpleName();
30 |
31 | private static CrashHandler instance = null;
32 |
33 | private Context mContext;
34 |
35 | private UncaughtExceptionHandler mDefaultHandler;
36 |
37 | private Map infos = new HashMap();
38 |
39 | private CrashHandler() {
40 | }
41 |
42 | private CrashHandler(Context context) {
43 | mContext = context;
44 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
45 | Thread.setDefaultUncaughtExceptionHandler(this);
46 | }
47 |
48 | public static CrashHandler getInstance(Context context) {
49 | if (instance == null) {
50 | synchronized (CrashHandler.class) {
51 | if (instance == null) {
52 | instance = new CrashHandler(context);
53 | }
54 | }
55 | }
56 | return instance;
57 | }
58 |
59 | @Override
60 | public void uncaughtException(Thread thread, Throwable ex) {
61 | if (!handleException(ex) && mDefaultHandler != null) {
62 | mDefaultHandler.uncaughtException(thread, ex);
63 | } else {
64 | try {
65 | Thread.sleep(3000);
66 | } catch (InterruptedException e) {
67 | Log.e("error : ", e.getMessage());
68 | }
69 | System.exit(0);
70 | }
71 | }
72 |
73 | private boolean handleException(final Throwable ex) {
74 |
75 | // 如果是调试状态则不生成异常文件,让系统默认的异常处理器来处理
76 | if (Debug.isDebuggerConnected())
77 | return false;
78 | if (ex == null)
79 | return false;
80 | // 收集设备参数信息
81 | collectDeviceInfo(mContext);
82 | // 保存日志文件
83 | saveCrashInfo2File(ex);
84 | return true;
85 | }
86 |
87 | private void collectDeviceInfo(Context ctx) {
88 | try {
89 | PackageManager pm = ctx.getPackageManager();
90 | PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
91 | if (pi != null) {
92 | String versionName = pi.versionName == null ? "null" : pi.versionName;
93 | String versionCode = pi.versionCode + "";
94 | infos.put("versionName", versionName);
95 | infos.put("versionCode", versionCode);
96 | }
97 | } catch (NameNotFoundException e) {
98 | Log.e(TAG, "an error occurred when collect package info", e);
99 | }
100 | Field[] fields = Build.class.getDeclaredFields();
101 | for (Field field : fields) {
102 | try {
103 | field.setAccessible(true);
104 | infos.put(field.getName(), field.get(null).toString());
105 | } catch (Exception e) {
106 | Log.e(TAG, "an error occurred when collect crash info", e);
107 | }
108 | }
109 | }
110 |
111 | private void saveCrashInfo2File(Throwable ex) {
112 | StringBuffer sb = new StringBuffer();
113 | for (Map.Entry entry : infos.entrySet()) {
114 | String key = entry.getKey();
115 | String value = entry.getValue();
116 | sb.append(key + "=" + value + "\n");
117 | }
118 |
119 | Writer writer = new StringWriter();
120 | PrintWriter printWriter = new PrintWriter(writer);
121 | ex.printStackTrace(printWriter);
122 | Throwable cause = ex.getCause();
123 | while (cause != null) {
124 | cause.printStackTrace(printWriter);
125 | cause = cause.getCause();
126 | }
127 | printWriter.close();
128 | String result = writer.toString();
129 | sb.append(result);
130 | DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
131 | try {
132 | String fileName = String.format("crash-%s.log", df.format(new Date(System.currentTimeMillis())));
133 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
134 | String path = "/sdcard/daily/log/";
135 | File dir = new File(path);
136 | if (!dir.exists())
137 | dir.mkdirs();
138 | FileOutputStream fos = new FileOutputStream(path + fileName);
139 | fos.write(sb.toString().getBytes());
140 | fos.close();
141 | }
142 | } catch (Exception e) {
143 | Log.e(TAG, "an error occured while writing file...", e);
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/animation/AnimationEndListener.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.animation;
2 |
3 | import android.view.animation.Animation;
4 |
5 | /**
6 | * Created by sf on 2015/1/13.
7 | */
8 | public class AnimationEndListener implements Animation.AnimationListener {
9 | @Override
10 | public void onAnimationStart(Animation animation) {
11 |
12 | }
13 |
14 | @Override
15 | public void onAnimationEnd(Animation animation) {
16 |
17 | }
18 |
19 | @Override
20 | public void onAnimationRepeat(Animation animation) {
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/api/DailyApi.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.api;
2 |
3 | /**
4 | * http://blog.robinchutaux.com/blog/using-retrofit-with-activeandroid/
5 | * https://gist.github.com/polbins/1c7f9303d2b7d169a3b1
6 | * http://mattlogan.me/creating-a-retrofitlike-database-client
7 | * https://github.com/square/okhttp/wiki/Interceptors
8 | * https://github.com/square/retrofit/issues/693
9 | * Created by Aspsine on 2015/3/30.
10 | */
11 | public class DailyApi {
12 |
13 | private static final String API = "http://news.at.zhihu.com/api/4";
14 |
15 | private static DailyApiService dailyApiService;
16 |
17 | public static DailyApiService createApi() {
18 | if (dailyApiService == null) {
19 | synchronized (DailyApi.class) {
20 | if (dailyApiService == null) {
21 | dailyApiService = RestApi.createApi(DailyApiService.class, API);
22 | }
23 | }
24 | }
25 | return dailyApiService;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/api/DailyApiService.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.api;
2 |
3 | import com.aspsine.zhihu.daily.model.DailyStories;
4 | import com.aspsine.zhihu.daily.model.StartImage;
5 | import com.aspsine.zhihu.daily.model.Story;
6 | import com.aspsine.zhihu.daily.model.Theme;
7 | import com.aspsine.zhihu.daily.model.Themes;
8 |
9 | import retrofit.Callback;
10 | import retrofit.http.GET;
11 | import retrofit.http.Path;
12 |
13 | /**
14 | * Created by Aspsine on 2015/3/30.
15 | */
16 | public interface DailyApiService {
17 |
18 | @GET("/start-image/{width}*{height}")
19 | void getStartImage(@Path("width") int width, @Path("height") int height, Callback callback);
20 |
21 | @GET("/news/latest")
22 | void getLatestDailyStories(Callback callback);
23 |
24 | @GET("/news/before/{date}")
25 | void getBeforeDailyStories(@Path("date") String date, Callback callback);
26 |
27 | @GET("/news/{storyId}")
28 | void getStoryDetail(@Path("storyId") String storyId, Callback callback);
29 |
30 | @GET("/themes")
31 | void getThemes(Callback callback);
32 |
33 | @GET("/theme/{themeId}")
34 | void getTheme(@Path("themeId") String themeId, Callback callback);
35 |
36 | @GET("/theme/{themeId}/before/{storyId}")
37 | void getThemeBeforeStory(@Path("themeId") String themeId, @Path("storyId") String storyId, Callback callback);
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/api/RestApi.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.api;
2 |
3 | import com.aspsine.zhihu.daily.App;
4 | import com.aspsine.zhihu.daily.BuildConfig;
5 | import com.aspsine.zhihu.daily.network.OkHttp;
6 | import com.google.gson.GsonBuilder;
7 |
8 | import retrofit.RestAdapter;
9 | import retrofit.client.OkClient;
10 | import retrofit.converter.GsonConverter;
11 |
12 | /**
13 | * Created by Aspsine on 2015/4/1.
14 | */
15 | public class RestApi {
16 |
17 | private static RestAdapter restAdapter;
18 |
19 | public static T createApi(Class clazz, String api) {
20 | if (restAdapter == null) {
21 | synchronized (RestApi.class) {
22 | if (restAdapter == null) {
23 | restAdapter = new RestAdapter.Builder()
24 | .setEndpoint(api)
25 | .setClient(new OkClient(OkHttp.createHttpClient(App.getContext())))
26 | .setConverter(new GsonConverter(new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()))
27 | .setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)
28 | .build();
29 | }
30 | }
31 | }
32 | return restAdapter.create(clazz);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/db/CacheDao.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.db;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 |
7 | import com.aspsine.zhihu.daily.model.Cache;
8 |
9 | /**
10 | * Created by Aspsine on 2015/4/10.
11 | */
12 | public class CacheDao {
13 | public static final String TABLE_NAME = Cache.class.getSimpleName();
14 | private DBOpenHelper mHelper;
15 |
16 | public CacheDao(Context context) {
17 | mHelper = DBOpenHelper.getInstance(context);
18 | }
19 |
20 | public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
21 | String constraint = ifNotExists ? "IF NOT EXISTS " : "";
22 | db.execSQL("CREATE TABLE " + constraint
23 | + TABLE_NAME
24 | + " (" +
25 | "_id INTEGER PRIMARY KEY ," + // 0: id
26 | "request TEXT," + // 1: request
27 | "response TEXT," + // 2: response
28 | "time INTEGER);"); // 3: time
29 | }
30 |
31 | /**
32 | * Drops the underlying database table.
33 | */
34 | public static void dropTable(SQLiteDatabase db, boolean ifExists) {
35 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + TABLE_NAME;
36 | db.execSQL(sql);
37 | }
38 |
39 | public void insertCache(Cache cache) {
40 | SQLiteDatabase db = mHelper.getWritableDatabase();
41 | db.execSQL("insert into "
42 | + TABLE_NAME
43 | + " (request, response, time) values(?,?,?)",
44 | new Object[]{cache.getRequest(), cache.getResponse(), cache.getTime()});
45 | db.close();
46 | }
47 |
48 | public void deleteCache(String request) {
49 | SQLiteDatabase db = mHelper.getWritableDatabase();
50 | db.execSQL("delete from "
51 | + TABLE_NAME
52 | + " where request=?",
53 | new Object[]{request});
54 | db.close();
55 | }
56 |
57 | public synchronized void updateCache(Cache cache) {
58 | SQLiteDatabase db = mHelper.getWritableDatabase();
59 | Cursor cursor = db.rawQuery("select * from "
60 | + TABLE_NAME
61 | + " where request = ?",
62 | new String[]{cache.getRequest()});
63 |
64 | boolean isExist = cursor.moveToNext();
65 | if (isExist) {
66 | db.execSQL("delete from "
67 | + TABLE_NAME
68 | + " where request=?",
69 | new Object[]{cache.getRequest()});
70 | }
71 | db.execSQL("insert into "
72 | + TABLE_NAME
73 | + " (request, response, time) values(?,?,?)",
74 | new Object[]{cache.getRequest(), cache.getResponse(), cache.getTime()});
75 | cursor.close();
76 | db.close();
77 | }
78 |
79 | public synchronized Cache getCache(String request) {
80 | SQLiteDatabase db = mHelper.getReadableDatabase();
81 | Cursor cursor = db.rawQuery("select * from "
82 | + TABLE_NAME
83 | + " where request = ?",
84 | new String[]{request});
85 |
86 | Cache cache = new Cache();
87 | while (cursor.moveToNext()) {
88 | cache.setRequest(cursor.getString(cursor.getColumnIndex("request")));
89 | cache.setResponse(cursor.getString(cursor.getColumnIndex("response")));
90 | cache.setTime(cursor.getLong(cursor.getColumnIndex("time")));
91 | break;
92 | }
93 | cursor.close();
94 | db.close();
95 | return cache;
96 | }
97 |
98 | public boolean exists(String request) {
99 | SQLiteDatabase db = mHelper.getReadableDatabase();
100 | Cursor cursor = db.rawQuery("select * from "
101 | + TABLE_NAME
102 | + " where request = ?",
103 | new String[]{request});
104 | boolean isExist = cursor.moveToNext();
105 | cursor.close();
106 | db.close();
107 | return isExist;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/db/DBOpenHelper.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.db;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | import com.aspsine.zhihu.daily.Constants;
8 | import com.aspsine.zhihu.daily.util.L;
9 |
10 | /**
11 | * Created by Aspsine on 2015/4/10.
12 | */
13 | public class DBOpenHelper extends SQLiteOpenHelper {
14 | private static final String TAG = "Database";
15 |
16 | private static final int DB_VERSION = Constants.Config.DATABASE_VERSION;
17 | private static final String DB_NAME = Constants.Config.DATABASE_NAME;
18 |
19 | private static DBOpenHelper sDBOpenHelper;
20 | /**
21 | * Creates underlying database table using DAOs.
22 | */
23 | private void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
24 | CacheDao.createTable(db, ifNotExists);
25 | }
26 |
27 | /**
28 | * Drops underlying database table using DAOs.
29 | */
30 | private void dropAllTables(SQLiteDatabase db, boolean ifExists) {
31 | CacheDao.dropTable(db, ifExists);
32 | }
33 |
34 | public static DBOpenHelper getInstance(Context context) {
35 | if (sDBOpenHelper == null) {
36 | synchronized (DBOpenHelper.class) {
37 | if (sDBOpenHelper == null) {
38 | sDBOpenHelper = new DBOpenHelper(context);
39 | }
40 | }
41 | }
42 | return sDBOpenHelper;
43 | }
44 |
45 | private DBOpenHelper(Context context) {
46 | super(context, DB_NAME, null, DB_VERSION);
47 | }
48 |
49 | @Override
50 | public void onCreate(SQLiteDatabase db) {
51 | L.i(TAG, "Creating tables for DB version " + DB_VERSION);
52 | createAllTables(db, false);
53 | }
54 |
55 | @Override
56 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
57 | L.i(TAG, "Upgrading DB from version " + oldVersion + " to " + newVersion + " by dropping all tables");
58 | dropAllTables(db, true);
59 | onCreate(db);
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/db/SQLUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.db;
2 |
3 | /**
4 | * Created by Aspsine on 2015/4/21.
5 | */
6 | public class SQLUtils {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/interfaces/NavigationDrawerCallbacks.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.interfaces;
2 |
3 | /**
4 | * Created by sf on 2015/1/16.
5 | * Callbacks interface that all activities using this fragment must implement.
6 | */
7 | public interface NavigationDrawerCallbacks {
8 | /**
9 | * Called when an item in the navigation drawer is selected.
10 | */
11 | void onNavigationDrawerItemSelected(int position);
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/Cache.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 |
5 | /**
6 | * Created by Aspsine on 2015/4/10.
7 | */
8 | public class Cache {
9 | private long id;
10 | @Expose
11 | private String request;
12 | @Expose
13 | private String response;
14 | @Expose
15 | private long time;
16 |
17 | public Cache() {
18 | }
19 |
20 | public Cache(String request, String response, long time) {
21 | this.request = request;
22 | this.response = response;
23 | this.time = time;
24 | }
25 |
26 | public String getRequest() {
27 | return request;
28 | }
29 |
30 | public void setRequest(String request) {
31 | this.request = request;
32 | }
33 |
34 | public String getResponse() {
35 | return response;
36 | }
37 |
38 | public void setResponse(String response) {
39 | this.response = response;
40 | }
41 |
42 | public long getTime() {
43 | return time;
44 | }
45 |
46 | public void setTime(long time) {
47 | this.time = time;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/DailyStories.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 | import com.google.gson.annotations.SerializedName;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by Aspsine on 2015/3/10.
10 | */
11 | public class DailyStories {
12 | @Expose
13 | private String date;
14 | @Expose
15 | private List stories;
16 | @Expose
17 | @SerializedName("top_stories")
18 | private List topStories;
19 |
20 | public String getDate() {
21 | return date;
22 | }
23 |
24 | public void setDate(String date) {
25 | this.date = date;
26 | }
27 |
28 | public List getStories() {
29 | return stories;
30 | }
31 |
32 | public void setStories(List stories) {
33 | this.stories = stories;
34 | }
35 |
36 | public List getTopStories() {
37 | return topStories;
38 | }
39 |
40 | public void setTopStories(List topStories) {
41 | this.topStories = topStories;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/Editor.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 |
5 | /**
6 | * Created by aspsine on 15-3-25.
7 | */
8 | public class Editor {
9 | @Expose
10 | private String id;
11 | @Expose
12 | private String avatar;
13 | @Expose
14 | private String name;
15 |
16 | public String getId() {
17 | return id;
18 | }
19 |
20 | public void setId(String id) {
21 | this.id = id;
22 | }
23 |
24 | public String getAvatar() {
25 | return avatar;
26 | }
27 |
28 | public void setAvatar(String avatar) {
29 | this.avatar = avatar;
30 | }
31 |
32 | public String getName() {
33 | return name;
34 | }
35 |
36 | public void setName(String name) {
37 | this.name = name;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/StartImage.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 |
5 | /**
6 | * Created by Aspsine on 2015/3/30.
7 | */
8 | public class StartImage {
9 | @Expose
10 | private String text;
11 | @Expose
12 | private String img;
13 |
14 | public String getText() {
15 | return text;
16 | }
17 |
18 | public void setText(String text) {
19 | this.text = text;
20 | }
21 |
22 | public String getImg() {
23 | return img;
24 | }
25 |
26 | public void setImg(String img) {
27 | this.img = img;
28 | }
29 |
30 | public boolean isValueEquals(StartImage startImage) {
31 | return this.text.equals(startImage.getText()) && this.img.equals(startImage.getImg());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/Story.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 | import com.google.gson.annotations.SerializedName;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by Aspsine on 2015/2/27.
10 | */
11 | public class Story {
12 | @Expose
13 | private List images;
14 | @Expose
15 | private String type;
16 | @Expose
17 | private String id;
18 | @Expose
19 | @SerializedName("ga_prefix")
20 | private String gaPrefix;
21 | @Expose
22 | private String title;
23 | @Expose
24 | @SerializedName("multipic")
25 | private String multiPic;
26 | @Expose
27 | private String image;
28 | @Expose
29 | @SerializedName("share_url")
30 | private String shareUrl;
31 | @Expose
32 | private String body;
33 | @Expose
34 | @SerializedName("image_source")
35 | private String imageSource;
36 | @Expose
37 | @SerializedName("js")
38 | private List jsList;
39 | @Expose
40 | @SerializedName("css")
41 | private List cssList;
42 | @Expose
43 | private List recommenders;
44 | @Expose
45 | private Theme theme;
46 |
47 | private String thumbnail;
48 | private String url;
49 | private String sectionThumbnail;
50 | private String sectionId;
51 | private String sectionName;
52 |
53 | public List getImages() {
54 | return images;
55 | }
56 |
57 | public void setImages(List images) {
58 | this.images = images;
59 | }
60 |
61 | public String getType() {
62 | return type;
63 | }
64 |
65 | public void setType(String type) {
66 | this.type = type;
67 | }
68 |
69 | public String getId() {
70 | return id;
71 | }
72 |
73 | public void setId(String id) {
74 | this.id = id;
75 | }
76 |
77 | public String getGaPrefix() {
78 | return gaPrefix;
79 | }
80 |
81 | public void setGaPrefix(String gaPrefix) {
82 | this.gaPrefix = gaPrefix;
83 | }
84 |
85 | public String getTitle() {
86 | return title;
87 | }
88 |
89 | public void setTitle(String title) {
90 | this.title = title;
91 | }
92 |
93 | public String getMultiPic() {
94 | return multiPic;
95 | }
96 |
97 | public void setMultiPic(String multiPic) {
98 | this.multiPic = multiPic;
99 | }
100 |
101 | public String getImage() {
102 | return image;
103 | }
104 |
105 | public void setImage(String image) {
106 | this.image = image;
107 | }
108 |
109 | public String getThumbnail() {
110 | return thumbnail;
111 | }
112 |
113 | public void setThumbnail(String thumbnail) {
114 | this.thumbnail = thumbnail;
115 | }
116 |
117 | public String getShareUrl() {
118 | return shareUrl;
119 | }
120 |
121 | public void setShareUrl(String shareUrl) {
122 | this.shareUrl = shareUrl;
123 | }
124 |
125 | public String getUrl() {
126 | return url;
127 | }
128 |
129 | public void setUrl(String url) {
130 | this.url = url;
131 | }
132 |
133 | public String getBody() {
134 | return body;
135 | }
136 |
137 | public void setBody(String body) {
138 | this.body = body;
139 | }
140 |
141 | public String getImageSource() {
142 | return imageSource;
143 | }
144 |
145 | public void setImageSource(String imageSource) {
146 | this.imageSource = imageSource;
147 | }
148 |
149 | public String getSectionThumbnail() {
150 | return sectionThumbnail;
151 | }
152 |
153 | public void setSectionThumbnail(String sectionThumbnail) {
154 | this.sectionThumbnail = sectionThumbnail;
155 | }
156 |
157 | public String getSectionId() {
158 | return sectionId;
159 | }
160 |
161 | public void setSectionId(String sectionId) {
162 | this.sectionId = sectionId;
163 | }
164 |
165 | public List getJsList() {
166 | return jsList;
167 | }
168 |
169 | public void setJsList(List jsList) {
170 | this.jsList = jsList;
171 | }
172 |
173 | public String getSectionName() {
174 | return sectionName;
175 | }
176 |
177 | public void setSectionName(String sectionName) {
178 | this.sectionName = sectionName;
179 | }
180 |
181 | public List getCssList() {
182 | return cssList;
183 | }
184 |
185 | public void setCssList(List cssList) {
186 | this.cssList = cssList;
187 | }
188 |
189 | public List getRecommenders() {
190 | return recommenders;
191 | }
192 |
193 | public void setRecommenders(List recommenders) {
194 | this.recommenders = recommenders;
195 | }
196 |
197 | public Theme getTheme() {
198 | return theme;
199 | }
200 |
201 | public void setTheme(Theme theme) {
202 | this.theme = theme;
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/Theme.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by Aspsine on 2015/3/19.
9 | */
10 | public class Theme {
11 | @Expose
12 | private String color;
13 | @Expose
14 | private String thumbnail;
15 | @Expose
16 | private String image;
17 | @Expose
18 | private String background;
19 | @Expose
20 | private String description;
21 | @Expose
22 | private String id;
23 | @Expose
24 | private String name;
25 | @Expose
26 | private List stories;
27 | @Expose
28 | private List editors;
29 |
30 | public String getColor() {
31 | return color;
32 | }
33 |
34 | public void setColor(String color) {
35 | this.color = color;
36 | }
37 |
38 | public String getThumbnail() {
39 | return thumbnail;
40 | }
41 |
42 | public void setThumbnail(String thumbnail) {
43 | this.thumbnail = thumbnail;
44 | }
45 |
46 | public String getImage() {
47 | return image;
48 | }
49 |
50 | public void setImage(String image) {
51 | this.image = image;
52 | }
53 |
54 | public String getBackground() {
55 | return background;
56 | }
57 |
58 | public void setBackground(String background) {
59 | this.background = background;
60 | }
61 |
62 | public String getDescription() {
63 | return description;
64 | }
65 |
66 | public void setDescription(String description) {
67 | this.description = description;
68 | }
69 |
70 | public String getId() {
71 | return id;
72 | }
73 |
74 | public void setId(String id) {
75 | this.id = id;
76 | }
77 |
78 | public String getName() {
79 | return name;
80 | }
81 |
82 | public void setName(String name) {
83 | this.name = name;
84 | }
85 |
86 | public List getStories() {
87 | return stories;
88 | }
89 |
90 | public void setStories(List stories) {
91 | this.stories = stories;
92 | }
93 |
94 | public List getEditors() {
95 | return editors;
96 | }
97 |
98 | public void setEditors(List editors) {
99 | this.editors = editors;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/model/Themes.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.model;
2 |
3 | import com.google.gson.annotations.Expose;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by Aspsine on 2015/3/19.
9 | */
10 | public class Themes {
11 | @Expose
12 | private int limit;
13 | @Expose
14 | private List subscribed;
15 | @Expose
16 | private List others;
17 |
18 | public int getLimit() {
19 | return limit;
20 | }
21 |
22 | public void setLimit(int limit) {
23 | this.limit = limit;
24 | }
25 |
26 | public List getSubscribed() {
27 | return subscribed;
28 | }
29 |
30 | public void setSubscribed(List subscribed) {
31 | this.subscribed = subscribed;
32 | }
33 |
34 | public List getOthers() {
35 | return others;
36 | }
37 |
38 | public void setOthers(List others) {
39 | this.others = others;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/network/BaseHttp.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.network;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.net.HttpURLConnection;
7 | import java.net.URL;
8 |
9 | /**
10 | * Created by Aspsine on 2015/2/28.
11 | */
12 | public class BaseHttp {
13 |
14 | protected static String get(String urlAddress) throws IOException {
15 | URL url = new URL(urlAddress);
16 | HttpURLConnection con = (HttpURLConnection) url.openConnection();
17 | con.setRequestMethod("GET");
18 | con.setRequestProperty("User-Agent", "Mozilla/5.0");
19 |
20 | try {
21 | if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
22 | BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), Http.CHARSET));
23 | String inputLine;
24 | StringBuilder response = new StringBuilder();
25 |
26 | while ((inputLine = in.readLine()) != null) {
27 | response.append(inputLine);
28 | }
29 |
30 | in.close();
31 | return response.toString();
32 | } else {
33 | throw new IOException("Network Error - response code:" + con.getResponseCode());
34 | }
35 | } finally {
36 | con.disconnect();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/network/BaseHttpClient.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.network;
2 |
3 | import org.apache.http.HttpResponse;
4 | import org.apache.http.HttpStatus;
5 | import org.apache.http.client.HttpClient;
6 | import org.apache.http.client.methods.HttpGet;
7 | import org.apache.http.impl.client.DefaultHttpClient;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.io.InputStreamReader;
13 |
14 | /**
15 | * Created by Aspsine on 2015/3/3.
16 | */
17 | public class BaseHttpClient {
18 |
19 | protected static String get(String urlAddress) throws IOException {
20 | HttpGet httpGet = new HttpGet(urlAddress);
21 | HttpClient httpClient = new DefaultHttpClient();
22 | HttpResponse httpResponse = httpClient.execute(httpGet);
23 | if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
24 | InputStream inputStream = httpResponse.getEntity().getContent();
25 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Http.CHARSET));
26 | String inputLine;
27 | StringBuilder response = new StringBuilder();
28 |
29 | while ((inputLine = reader.readLine()) != null) {
30 | response.append(inputLine);
31 | }
32 | inputStream.close();
33 | reader.close();
34 | return response.toString();
35 | }
36 | throw new IOException("");
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/network/CacheInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.network;
2 |
3 | import com.aspsine.zhihu.daily.App;
4 | import com.aspsine.zhihu.daily.util.NetWorkUtils;
5 | import com.squareup.okhttp.Interceptor;
6 | import com.squareup.okhttp.Request;
7 | import com.squareup.okhttp.Response;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * Created by Aspsine on 2015/4/1.
13 | */
14 | public class CacheInterceptor implements Interceptor {
15 | private static final String CACHE_CONTROL = "Cache-Control";
16 |
17 | @Override
18 | public Response intercept(Chain chain) throws IOException {
19 |
20 | Request request = chain.request();
21 | // Add Cache Control only for GET methods
22 | if (request.method().equals("GET")) {
23 | if (NetWorkUtils.isNetWorkAvailable(App.getContext())) {
24 | request.newBuilder().addHeader(CACHE_CONTROL, "only-if-cached").build();
25 | } else {
26 | request.newBuilder().addHeader(CACHE_CONTROL, "public, max-stale=2419200").build();
27 | }
28 | }
29 | Response response = chain.proceed(request);
30 | // Re-write response CC header to force use of cache
31 | return response.newBuilder()
32 | .header("Cache-Control", "public, max-age=" + 60 * 10) // 10min
33 | .build();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/network/Http.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.network;
2 |
3 | import android.os.Build;
4 |
5 | import com.aspsine.zhihu.daily.Constants;
6 | import com.aspsine.zhihu.daily.util.L;
7 |
8 | import java.io.IOException;
9 | import java.io.UnsupportedEncodingException;
10 | import java.net.URLEncoder;
11 | import java.util.Iterator;
12 | import java.util.Map;
13 |
14 | /**
15 | * Created by Aspsine on 2015/2/28.
16 | */
17 | public class Http {
18 | protected static final String CHARSET = Constants.Config.CHARSET;
19 |
20 | public static String get(String baseUrl) throws IOException {
21 | L.i("url", baseUrl);
22 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
23 | return BaseHttpClient.get(baseUrl);
24 | } else {
25 | return BaseHttp.get(baseUrl);
26 | }
27 | }
28 |
29 | public static String get(String baseUrl, Map params) throws IOException {
30 | return get(makeUrl(baseUrl, params));
31 | }
32 |
33 | public static String get(String baseUrl, String key, String value) throws IOException {
34 | return get(baseUrl + "?" + concatKeyValue(key, value));
35 | }
36 |
37 | public static String get(String baseUrl, String suffix) throws IOException {
38 | return get(baseUrl + encodeString(suffix));
39 | }
40 |
41 | public static String get(String baseUrl, String suffix, boolean replaceSpace) throws IOException {
42 | if (replaceSpace) {
43 | return get(baseUrl + encodeString(suffix).replace("+", "%20"));
44 | } else {
45 | return get(baseUrl, suffix);
46 | }
47 | }
48 |
49 |
50 | protected static String makeUrl(String baseUrl, Map params) {
51 | if (params == null || params.size() == 0) {
52 | return baseUrl;
53 | }
54 |
55 | StringBuilder sb = new StringBuilder();
56 | sb.append(baseUrl);
57 | sb.append("?");
58 |
59 | for (Iterator> iterator = params.entrySet().iterator(); iterator.hasNext(); sb.append("&")) {
60 | Map.Entry item = iterator.next();
61 | sb.append(concatKeyValue(item.getKey(), item.getValue()));
62 | }
63 |
64 | return sb.toString();
65 | }
66 |
67 | protected static String concatKeyValue(String key, String value) {
68 | return encodeString(key) + "=" + encodeString(value);
69 | }
70 |
71 | protected static String encodeString(String str) {
72 | try {
73 | return URLEncoder.encode(str, CHARSET);
74 | } catch (UnsupportedEncodingException e) {
75 | return "";
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/network/OkHttp.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.network;
2 |
3 | import android.content.Context;
4 |
5 | import com.aspsine.zhihu.daily.Constants;
6 | import com.aspsine.zhihu.daily.util.FileUtils;
7 | import com.squareup.okhttp.Cache;
8 | import com.squareup.okhttp.OkHttpClient;
9 |
10 | import java.util.concurrent.TimeUnit;
11 |
12 | /**
13 | * Created by Aspsine on 2015/3/31.
14 | */
15 | public class OkHttp {
16 | private static OkHttpClient okHttpClient;
17 |
18 | public static OkHttpClient createHttpClient(Context context) {
19 | if (okHttpClient == null) {
20 | synchronized (OkHttp.class) {
21 | okHttpClient = new OkHttpClient();
22 | okHttpClient.setCache(new Cache(FileUtils.getHttpCacheDir(context), Constants.Config.HTTP_CACHE_SIZE));
23 | okHttpClient.setConnectTimeout(Constants.Config.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
24 | okHttpClient.setReadTimeout(Constants.Config.HTTP_READ_TIMEOUT, TimeUnit.MILLISECONDS);
25 | okHttpClient.networkInterceptors().add(new CacheInterceptor());
26 | }
27 | }
28 | return okHttpClient;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/respository/CacheRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.respository;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import com.aspsine.zhihu.daily.db.CacheDao;
7 | import com.aspsine.zhihu.daily.model.Cache;
8 | import com.aspsine.zhihu.daily.model.DailyStories;
9 | import com.aspsine.zhihu.daily.model.StartImage;
10 | import com.aspsine.zhihu.daily.model.Story;
11 | import com.aspsine.zhihu.daily.model.Theme;
12 | import com.aspsine.zhihu.daily.model.Themes;
13 | import com.aspsine.zhihu.daily.respository.interfaces.CacheRepository;
14 | import com.aspsine.zhihu.daily.util.L;
15 | import com.aspsine.zhihu.daily.util.SharedPrefUtils;
16 | import com.google.gson.Gson;
17 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
18 | import com.nostra13.universalimageloader.core.ImageLoader;
19 | import com.nostra13.universalimageloader.core.assist.ImageSize;
20 |
21 | import java.text.DateFormat;
22 | import java.text.SimpleDateFormat;
23 | import java.util.Calendar;
24 |
25 | /**
26 | * Created by Aspsine on 2015/4/10.
27 | */
28 | public class CacheRepositoryImpl implements CacheRepository {
29 | private static final String TAG = CacheRepositoryImpl.class.getSimpleName();
30 | private static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
31 | private Context mContext;
32 | private CacheDao mCacheDao;
33 | private Gson mGson;
34 |
35 | public CacheRepositoryImpl(Context context) {
36 | this.mContext = context;
37 | this.mCacheDao = new CacheDao(context);
38 | this.mGson = new Gson();
39 | }
40 |
41 | @Override
42 | public void getStartImage(Callback callback) {
43 | String mOldJsonString = SharedPrefUtils.getSplashJson(mContext);
44 | if (!TextUtils.isEmpty(mOldJsonString)) {
45 | StartImage startImage = new Gson().fromJson(mOldJsonString, StartImage.class);
46 | callback.success(startImage);
47 | } else {
48 | callback.failure(getException(StartImage.class));
49 | }
50 | }
51 |
52 | @Override
53 | public void saveStartImage(int width, int height, DisplayImageOptions options, StartImage startImage) {
54 | String mOldJsonString = SharedPrefUtils.getSplashJson(mContext);
55 | StartImage old = new Gson().fromJson(mOldJsonString, StartImage.class);
56 | if (old == null || !startImage.getImg().equals(old.getImg())) {
57 | SharedPrefUtils.setSplashJson(mContext, new Gson().toJson(startImage));
58 | ImageLoader.getInstance().loadImage(startImage.getImg(), new ImageSize(width, height), options, null);
59 | L.i(TAG, "new image.");
60 | } else {
61 | L.i(TAG, "old image.");
62 | }
63 | }
64 |
65 | @Override
66 | public void getLatestDailyStories(String url, Callback callback) {
67 | getDataObject(url, DailyStories.class, callback);
68 | }
69 |
70 | @Override
71 | public void saveLatestDailyStories(DailyStories dailyStories, String url) {
72 | saveCacheToDB(dailyStories, url);
73 | }
74 |
75 | @Override
76 | public void getBeforeDailyStories(String url, Callback callback) {
77 | getDataObject(url, DailyStories.class, callback);
78 | }
79 |
80 | @Override
81 | public void saveBeforeDailyStories(DailyStories dailyStories, String url) {
82 | saveCacheToDB(dailyStories, url);
83 | }
84 |
85 | @Override
86 | public void getStoryDetail(String url, Callback callback) {
87 | getDataObject(url, Story.class, callback);
88 | }
89 |
90 | @Override
91 | public void saveStoryDetail(Story story, String url) {
92 | saveCacheToDB(story, url);
93 | }
94 |
95 | @Override
96 | public void getThemes(String url, Callback callback) {
97 | getDataObject(url, Themes.class, callback);
98 | }
99 |
100 | @Override
101 | public void saveThemes(Themes themes, String url) {
102 | saveCacheToDB(themes, url);
103 | }
104 |
105 | @Override
106 | public void getTheme(String url, Callback callback) {
107 | getDataObject(url, Theme.class, callback);
108 | }
109 |
110 | @Override
111 | public void saveTheme(Theme theme, String url) {
112 | saveCacheToDB(theme, url);
113 | }
114 |
115 | @Override
116 | public void getThemeBeforeStory(String url, Callback callback) {
117 | getDataObject(url, Theme.class, callback);
118 | }
119 |
120 | @Override
121 | public void saveThemeBeforeStory(Theme theme, String url) {
122 | saveCacheToDB(theme, url);
123 | }
124 |
125 | private void getDataObject(String url, Class classOfT, CacheRepository.Callback callback) {
126 | String json = mCacheDao.getCache(url).getResponse();
127 | T t = mGson.fromJson(json, classOfT);
128 | if (t != null) {
129 | callback.success(t);
130 | L.i(TAG, "get" + classOfT.getSimpleName() + " cache");
131 | } else {
132 | callback.failure(getException(classOfT));
133 | }
134 | }
135 |
136 | private void saveCacheToDB(Object o, String url) {
137 | Cache cache = new Cache(url, mGson.toJson(o), Long.valueOf(df.format(Calendar.getInstance().getTimeInMillis())));
138 | mCacheDao.updateCache(cache);
139 | }
140 |
141 | private Exception getException(Class clazz) {
142 | return new Exception(clazz.getSimpleName() + " cache not found!");
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/respository/NetRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.respository;
2 |
3 | import com.aspsine.zhihu.daily.api.DailyApi;
4 | import com.aspsine.zhihu.daily.model.DailyStories;
5 | import com.aspsine.zhihu.daily.model.StartImage;
6 | import com.aspsine.zhihu.daily.model.Story;
7 | import com.aspsine.zhihu.daily.model.Theme;
8 | import com.aspsine.zhihu.daily.model.Themes;
9 | import com.aspsine.zhihu.daily.respository.interfaces.NetRepository;
10 | import com.aspsine.zhihu.daily.util.L;
11 |
12 | import retrofit.RetrofitError;
13 | import retrofit.client.Response;
14 |
15 | /**
16 | * Created by Aspsine on 2015/4/21.
17 | */
18 | public class NetRepositoryImpl implements NetRepository {
19 | private static final String TAG = NetRepositoryImpl.class.getSimpleName();
20 |
21 | @Override
22 | public void getStartImage(int width, int height, final Callback callback) {
23 | DailyApi.createApi().getStartImage(width, height, new retrofit.Callback() {
24 | @Override
25 | public void success(StartImage startImage, Response response) {
26 | callback.success(startImage, response.getUrl());
27 | }
28 |
29 | @Override
30 | public void failure(RetrofitError error) {
31 | callback.failure(error, error.getUrl());
32 | }
33 | });
34 | }
35 |
36 | @Override
37 | public void getLatestDailyStories(final Callback callback) {
38 | DailyApi.createApi().getLatestDailyStories(new retrofit.Callback() {
39 | @Override
40 | public void success(DailyStories dailyStories, Response response) {
41 | callback.success(dailyStories, response.getUrl());
42 | L.i(TAG, "getLatestDailyStories net");
43 | }
44 |
45 | @Override
46 | public void failure(RetrofitError error) {
47 | callback.failure(error, error.getUrl());
48 | }
49 | });
50 | }
51 |
52 | @Override
53 | public void getBeforeDailyStories(String date, final Callback callback) {
54 | DailyApi.createApi().getBeforeDailyStories(date, new retrofit.Callback() {
55 | @Override
56 | public void success(DailyStories dailyStories, Response response) {
57 | callback.success(dailyStories, response.getUrl());
58 | L.i(TAG, "getBeforeDailyStories net");
59 | }
60 |
61 | @Override
62 | public void failure(RetrofitError error) {
63 | callback.failure(error, error.getUrl());
64 | }
65 | });
66 | }
67 |
68 | @Override
69 | public void getStoryDetail(String storyId, final Callback callback) {
70 | DailyApi.createApi().getStoryDetail(storyId, new retrofit.Callback() {
71 | @Override
72 | public void success(Story story, Response response) {
73 | callback.success(story, response.getUrl());
74 | L.i(TAG, "getStoryDetail net");
75 | }
76 |
77 | @Override
78 | public void failure(RetrofitError error) {
79 | callback.failure(error, error.getUrl());
80 | }
81 | });
82 | }
83 |
84 | @Override
85 | public void getThemes(final Callback callback) {
86 | DailyApi.createApi().getThemes(new retrofit.Callback() {
87 | @Override
88 | public void success(Themes themes, Response response) {
89 | callback.success(themes, response.getUrl());
90 | L.i(TAG, "getThemes net");
91 | }
92 |
93 | @Override
94 | public void failure(RetrofitError error) {
95 | callback.failure(error, error.getUrl());
96 | }
97 | });
98 | }
99 |
100 | @Override
101 | public void getTheme(String themeId, final Callback callback) {
102 | DailyApi.createApi().getTheme(themeId, new retrofit.Callback() {
103 | @Override
104 | public void success(Theme theme, Response response) {
105 | callback.success(theme, response.getUrl());
106 | L.i(TAG, "getTheme net");
107 | }
108 |
109 | @Override
110 | public void failure(RetrofitError error) {
111 | callback.failure(error, error.getUrl());
112 | }
113 | });
114 | }
115 |
116 | @Override
117 | public void getThemeBeforeStory(String themeId, String storyId, final Callback callback) {
118 | DailyApi.createApi().getThemeBeforeStory(themeId, storyId, new retrofit.Callback() {
119 | @Override
120 | public void success(Theme theme, Response response) {
121 | callback.success(theme, response.getUrl());
122 | L.i(TAG, "getThemeBeforeStory net");
123 | }
124 |
125 | @Override
126 | public void failure(RetrofitError error) {
127 | callback.failure(error, error.getUrl());
128 | }
129 | });
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/respository/interfaces/CacheRepository.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.respository.interfaces;
2 |
3 | import com.aspsine.zhihu.daily.model.DailyStories;
4 | import com.aspsine.zhihu.daily.model.StartImage;
5 | import com.aspsine.zhihu.daily.model.Story;
6 | import com.aspsine.zhihu.daily.model.Theme;
7 | import com.aspsine.zhihu.daily.model.Themes;
8 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
9 |
10 | /**
11 | * Created by Aspsine on 2015/4/10.
12 | */
13 | public interface CacheRepository {
14 | void getStartImage(Callback callback);
15 |
16 | void saveStartImage(int width, int height, DisplayImageOptions options, StartImage startImage);
17 |
18 | void getLatestDailyStories(String url, Callback callback);
19 |
20 | void saveLatestDailyStories(DailyStories dailyStories, String url);
21 |
22 | void getBeforeDailyStories(String url, Callback callback);
23 |
24 | void saveBeforeDailyStories(DailyStories dailyStories, String url);
25 |
26 | void getStoryDetail(String url, Callback callback);
27 |
28 | void saveStoryDetail(Story story, String url);
29 |
30 | void getThemes(String url, Callback callback);
31 |
32 | void saveThemes(Themes themes, String url);
33 |
34 | void getTheme(String url, Callback callback);
35 |
36 | void saveTheme(Theme theme, String url);
37 |
38 | void getThemeBeforeStory(String url, Callback callback);
39 |
40 | void saveThemeBeforeStory(Theme theme, String url);
41 |
42 |
43 | public interface Callback {
44 |
45 | /**
46 | * Successful
47 | *
48 | * @param t
49 | */
50 | public void success(T t);
51 |
52 |
53 | /**
54 | * Unsuccessful
55 | *
56 | * @param e unexpected exception.
57 | */
58 | public void failure(Exception e);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/respository/interfaces/NetRepository.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.respository.interfaces;
2 |
3 | import com.aspsine.zhihu.daily.model.DailyStories;
4 | import com.aspsine.zhihu.daily.model.StartImage;
5 | import com.aspsine.zhihu.daily.model.Story;
6 | import com.aspsine.zhihu.daily.model.Theme;
7 | import com.aspsine.zhihu.daily.model.Themes;
8 |
9 | /**
10 | * Created by Aspsine on 2015/4/21.
11 | */
12 | public interface NetRepository {
13 | void getStartImage(int width, int height, Callback callback);
14 |
15 | void getLatestDailyStories(Callback callback);
16 |
17 | void getBeforeDailyStories(String date, Callback callback);
18 |
19 | void getStoryDetail(String storyId, Callback callback);
20 |
21 | void getThemes(Callback callback);
22 |
23 | void getTheme(String themeId, Callback callback);
24 |
25 | void getThemeBeforeStory(String themeId, String storyId, Callback callback);
26 |
27 | public interface Callback {
28 |
29 | /**
30 | * Successful
31 | *
32 | * @param t
33 | * @param url
34 | */
35 | public void success(T t, String url);
36 |
37 |
38 | /**
39 | * Unsuccessful
40 | *
41 | * @param e unexpected exception.
42 | */
43 | public void failure(Exception e, String url);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/respository/interfaces/Repository.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.respository.interfaces;
2 |
3 | import com.aspsine.zhihu.daily.model.DailyStories;
4 | import com.aspsine.zhihu.daily.model.StartImage;
5 | import com.aspsine.zhihu.daily.model.Story;
6 | import com.aspsine.zhihu.daily.model.Theme;
7 | import com.aspsine.zhihu.daily.model.Themes;
8 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
9 |
10 |
11 | /**
12 | * Created by Aspsine on 2015/4/21.
13 | */
14 | public interface Repository {
15 | void getStartImage(int width, int height, DisplayImageOptions options, Callback callback);
16 |
17 | void getLatestDailyStories(Callback callback);
18 |
19 | void getBeforeDailyStories(String date, Callback callback);
20 |
21 | void getStoryDetail(String storyId, Callback callback);
22 |
23 | void getThemes(Callback callback);
24 |
25 | void getTheme(String themeId, Callback callback);
26 |
27 | void getThemeBeforeStory(String themeId, String storyId, Callback callback);
28 |
29 | public interface Callback {
30 |
31 | /**
32 | * Successful
33 | *
34 | * @param t
35 | * @param outDate
36 | */
37 | public void success(T t, boolean outDate);
38 |
39 |
40 | /**
41 | * Unsuccessful
42 | *
43 | * @param e unexpected exception.
44 | */
45 | public void failure(Exception e);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/activity/BaseAppCompatActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.activity;
2 |
3 | import android.content.Intent;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBar;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.Toolbar;
9 | import android.view.MenuItem;
10 |
11 | import com.aspsine.zhihu.daily.R;
12 | import com.aspsine.zhihu.daily.util.UIUtils;
13 |
14 | /**
15 | * Created by Aspsine on 2015/3/24.
16 | */
17 | public abstract class BaseAppCompatActivity extends AppCompatActivity {
18 | public Toolbar mActionBarToolbar;
19 |
20 | protected abstract int getContentViewLayoutId();
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(getContentViewLayoutId());
26 | mActionBarToolbar = (Toolbar) findViewById(R.id.actionbarToolbar);
27 | if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
28 | int statusBarHeight = UIUtils.getStatusBarHeight(this);
29 | mActionBarToolbar.setPadding(0, statusBarHeight, 0, 0);
30 | }
31 | setupActionBar();
32 | }
33 |
34 | private void setupActionBar() {
35 | setSupportActionBar(mActionBarToolbar);
36 | ActionBar actionBar = getSupportActionBar();
37 | if (actionBar != null && !(this instanceof NavigationDrawerActivity)) {
38 | actionBar.setDisplayHomeAsUpEnabled(true);
39 | }
40 | }
41 |
42 | @Override
43 | public boolean onOptionsItemSelected(MenuItem item) {
44 | // Handle action bar item clicks here. The action bar will
45 | // automatically handle clicks on the Home/Up button, so long
46 | // as you specify a parent activity in AndroidManifest.xml.
47 | int id = item.getItemId();
48 |
49 | if (id == android.R.id.home) {
50 | onBackPressed();
51 | return true;
52 | } else if (id == R.id.action_settings) {
53 | // startActivity(new Intent(this, SettingsActivity.class));
54 | return true;
55 | }
56 |
57 | return super.onOptionsItemSelected(item);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/activity/GuiderActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.FragmentActivity;
5 | import android.support.v4.app.FragmentManager;
6 |
7 | import com.aspsine.zhihu.daily.R;
8 | import com.aspsine.zhihu.daily.ui.fragment.GuideFragment;
9 | import com.aspsine.zhihu.daily.ui.fragment.SplashFragment;
10 | import com.aspsine.zhihu.daily.util.IntentUtils;
11 | import com.aspsine.zhihu.daily.util.SharedPrefUtils;
12 |
13 | public class GuiderActivity extends FragmentActivity {
14 | private SplashFragment mSplashFragment;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_guider);
20 |
21 | FragmentManager fm = getSupportFragmentManager();
22 |
23 | if (SharedPrefUtils.isFirstLaunch(this)) {
24 | guide(fm);
25 | } else {
26 | splash(fm);
27 | }
28 | }
29 |
30 | void splash(FragmentManager fm) {
31 |
32 | mSplashFragment = new SplashFragment();
33 |
34 | if (fm.findFragmentByTag(SplashFragment.TAG) == null) {
35 | fm.beginTransaction()
36 | .add(R.id.container, mSplashFragment, SplashFragment.TAG)
37 | .commit();
38 | }
39 | }
40 |
41 | void guide(FragmentManager fm) {
42 | if (fm.findFragmentByTag(GuideFragment.TAG) == null) {
43 | fm.beginTransaction()
44 | .add(R.id.container, new GuideFragment(), GuideFragment.TAG)
45 | .commit();
46 | }
47 | }
48 |
49 | public void intentToMainActivity() {
50 | IntentUtils.intentToMainActivity(this);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/activity/NavigationDrawerActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentManager;
6 | import android.support.v4.app.FragmentTransaction;
7 | import android.support.v4.widget.DrawerLayout;
8 | import android.support.v7.app.ActionBar;
9 | import android.view.Menu;
10 |
11 | import com.aspsine.zhihu.daily.R;
12 | import com.aspsine.zhihu.daily.interfaces.NavigationDrawerCallbacks;
13 | import com.aspsine.zhihu.daily.ui.fragment.BaseFragment;
14 | import com.aspsine.zhihu.daily.ui.fragment.DailyStoriesFragment;
15 | import com.aspsine.zhihu.daily.ui.fragment.NavigationFragment;
16 | import com.aspsine.zhihu.daily.ui.fragment.ThemeStoriesFragment;
17 |
18 | public class NavigationDrawerActivity extends BaseAppCompatActivity implements NavigationDrawerCallbacks {
19 | private static final String TAG = NavigationDrawerActivity.class.getSimpleName();
20 |
21 | private NavigationFragment mNavigationFragment;
22 |
23 | private CharSequence mTitle = "";
24 |
25 | @Override
26 | protected int getContentViewLayoutId() {
27 | return R.layout.activity_navigation_drawer;
28 | }
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setUpDrawer();
34 | if (savedInstanceState == null) {
35 | mNavigationFragment.selectItem(NavigationFragment.getDefaultNavDrawerItem());
36 | }
37 | }
38 |
39 | private void setUpDrawer() {
40 | mNavigationFragment = (NavigationFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
41 | mTitle = getTitle();
42 | mNavigationFragment.setup(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mActionBarToolbar);
43 | }
44 |
45 | private int lastPosition = 0;
46 |
47 | @Override
48 | public void onNavigationDrawerItemSelected(int position) {
49 | // update the main content by replacing fragments
50 | FragmentManager fm = getSupportFragmentManager();
51 | FragmentTransaction ft = fm.beginTransaction();
52 |
53 | Fragment lastFragment = fm.findFragmentByTag(getTag(lastPosition));
54 | if (lastFragment != null) {
55 | ft.detach(lastFragment);
56 | }
57 |
58 | Fragment fragment = fm.findFragmentByTag(getTag(position));
59 | if (fragment == null) {
60 | fragment = getFragmentItem(position);
61 | ft.add(R.id.container, fragment, getTag(position));
62 | } else {
63 | ft.attach(fragment);
64 | }
65 |
66 | ft.commit();
67 | lastPosition = position;
68 |
69 | mTitle = mNavigationFragment.getTitle(position);
70 | restoreActionBar();
71 | }
72 |
73 | private int getId(Fragment fragment) {
74 | return ((BaseFragment) fragment).getThemeNumber();
75 | }
76 |
77 | private String getTag(int position) {
78 | switch (position) {
79 | case 0:
80 | return DailyStoriesFragment.TAG;
81 | default:
82 | return ThemeStoriesFragment.TAG + position;
83 | }
84 | }
85 |
86 | private Fragment getFragmentItem(int position) {
87 | return BaseFragment.newInstance(position, mNavigationFragment.getSectionId(position));
88 | }
89 |
90 | public void restoreActionBar() {
91 | ActionBar actionBar = getSupportActionBar();
92 | actionBar.setDisplayShowTitleEnabled(true);
93 | actionBar.setTitle(mTitle);
94 | }
95 |
96 | @Override
97 | public boolean onCreateOptionsMenu(Menu menu) {
98 | if (!mNavigationFragment.isDrawerOpen()) {
99 | // Only show items in the action bar relevant to this screen
100 | // if the drawer is not showing. Otherwise, let the drawer
101 | // decide what to show in the action bar.
102 | getMenuInflater().inflate(R.menu.menu_navigation_drawer, menu);
103 | return true;
104 | }
105 | return super.onCreateOptionsMenu(menu);
106 | }
107 |
108 | @Override
109 | public void onBackPressed() {
110 | if (mNavigationFragment.isDrawerOpen()) {
111 | mNavigationFragment.closeDrawer();
112 | } else {
113 | if (mNavigationFragment.getCurrentSelectedPosition() != NavigationFragment.getDefaultNavDrawerItem()) {
114 | mNavigationFragment.selectItem(NavigationFragment.getDefaultNavDrawerItem());
115 | } else {
116 | super.onBackPressed();
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/activity/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.activity;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.aspsine.zhihu.daily.R;
6 | import com.aspsine.zhihu.daily.ui.fragment.SettingsFragment;
7 |
8 | public class SettingsActivity extends BaseAppCompatActivity {
9 |
10 | @Override
11 | protected int getContentViewLayoutId() {
12 | return R.layout.activity_settings;
13 | }
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | if (savedInstanceState == null) {
19 | getFragmentManager().beginTransaction()
20 | .replace(R.id.container, new SettingsFragment())
21 | .commit();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/activity/StoryActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentManager;
6 |
7 | import com.aspsine.zhihu.daily.R;
8 | import com.aspsine.zhihu.daily.ui.fragment.DailyStoriesFragment;
9 | import com.aspsine.zhihu.daily.ui.fragment.StoryFragment;
10 | import com.aspsine.zhihu.daily.util.L;
11 |
12 | public class StoryActivity extends BaseAppCompatActivity {
13 |
14 | @Override
15 | protected int getContentViewLayoutId() {
16 | return R.layout.activity_story;
17 | }
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | getSupportActionBar().setTitle(null);
23 | if (savedInstanceState == null) {
24 | String storyId = getIntent().getStringExtra(DailyStoriesFragment.EXTRA_STORY_ID);
25 | StoryFragment storyFragment = StoryFragment.newInstance(storyId);
26 | storyFragment.setToolBar(mActionBarToolbar);
27 | getSupportFragmentManager().beginTransaction()
28 | .add(R.id.container, storyFragment, StoryFragment.TAG)
29 | .commit();
30 | }
31 | }
32 |
33 | @Override
34 | public void onBackPressed() {
35 | super.onBackPressed();
36 | finish();
37 | }
38 |
39 | @Override
40 | protected void onDestroy() {
41 | L.i("StoryActivity", "onDestroy");
42 | super.onDestroy();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/adapter/ThemeStoriesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.aspsine.zhihu.daily.R;
9 | import com.aspsine.zhihu.daily.model.Editor;
10 | import com.aspsine.zhihu.daily.model.Story;
11 | import com.aspsine.zhihu.daily.model.Theme;
12 | import com.aspsine.zhihu.daily.ui.adapter.holder.StoryViewHolder;
13 | import com.aspsine.zhihu.daily.ui.widget.AvatarsView;
14 | import com.aspsine.zhihu.daily.ui.widget.StoryHeaderView;
15 | import com.aspsine.zhihu.daily.util.DensityUtil;
16 | import com.aspsine.zhihu.daily.util.UIUtils;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * Created by Aspsine on 2015/3/26.
23 | */
24 | public class ThemeStoriesAdapter extends RecyclerView.Adapter {
25 | private Theme mTheme;
26 |
27 | public ThemeStoriesAdapter() {
28 | }
29 |
30 | public void setTheme(Theme theme) {
31 | mTheme = theme;
32 | notifyDataSetChanged();
33 | }
34 |
35 | public void appendStories(List stories) {
36 | mTheme.getStories().addAll(stories);
37 | notifyDataSetChanged();
38 | }
39 |
40 | public static final class Type {
41 | public static final int TYPE_HEADER = 0;
42 | public static final int TYPE_AVATARS = 1;
43 | public static final int TYPE_ITEM = 2;
44 | }
45 |
46 | @Override
47 | public int getItemViewType(int position) {
48 | if (!TextUtils.isEmpty(mTheme.getBackground()) && position == 0) {
49 | return Type.TYPE_HEADER;
50 | } else if (hasEditors() && position == 1) {
51 | return Type.TYPE_AVATARS;
52 | } else {
53 | return Type.TYPE_ITEM;
54 | }
55 | }
56 |
57 | @Override
58 | public int getItemCount() {
59 | int count = 0;
60 | if (mTheme != null) {
61 | if (!TextUtils.isEmpty(mTheme.getBackground())) {
62 | count += 1;
63 | }
64 | if (mTheme.getEditors() != null && mTheme.getEditors().size() > 0) {
65 | count += 1;
66 | }
67 | if (mTheme.getStories() != null) {
68 | count = count + mTheme.getStories().size();
69 | }
70 | }
71 | return count;
72 | }
73 |
74 | @Override
75 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
76 | RecyclerView.ViewHolder viewHolder = null;
77 | switch (viewType) {
78 | case Type.TYPE_HEADER:
79 | viewHolder = new HeaderViewHolder(StoryHeaderView.newInstance(parent));
80 | break;
81 | case Type.TYPE_AVATARS:
82 | AvatarsView avatarsView = new AvatarsView(parent.getContext());
83 | RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
84 | lp.setMargins(0, DensityUtil.dip2px(parent.getContext(), 8), 0, 0);
85 | avatarsView.setLayoutParams(lp);
86 | viewHolder = new AvatarViewHolder(avatarsView);
87 | break;
88 | case Type.TYPE_ITEM:
89 | viewHolder = new StoryViewHolder(UIUtils.inflate(R.layout.recycler_item_story, parent));
90 | break;
91 | }
92 | return viewHolder;
93 | }
94 |
95 | @Override
96 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
97 | int viewType = getItemViewType(position);
98 | switch (viewType) {
99 | case Type.TYPE_HEADER:
100 | ((StoryHeaderView) holder.itemView)
101 | .bindData(mTheme.getDescription(), null, mTheme.getBackground());
102 | break;
103 | case Type.TYPE_AVATARS:
104 | List images = new ArrayList<>();
105 | for (Editor editor : mTheme.getEditors()) {
106 | images.add(editor.getAvatar());
107 | }
108 | ((AvatarsView) holder.itemView).bindData(holder.itemView.getResources().getString(R.string.avatar_title_editor), images);
109 | break;
110 | case Type.TYPE_ITEM:
111 | StoryViewHolder storyViewHolder = (StoryViewHolder) holder;
112 | final int storyPosition = hasEditors() ? position - 2 : position - 1;
113 | storyViewHolder.bindStoryView(mTheme.getStories().get(storyPosition));
114 | break;
115 | default:
116 | throw new IllegalArgumentException("error view type!");
117 | }
118 | }
119 |
120 | private boolean hasEditors() {
121 | return mTheme.getEditors() != null && mTheme.getEditors().size() > 0;
122 | }
123 |
124 | public static final class HeaderViewHolder extends RecyclerView.ViewHolder {
125 | public HeaderViewHolder(View itemView) {
126 | super(itemView);
127 | }
128 | }
129 |
130 | public static final class AvatarViewHolder extends RecyclerView.ViewHolder {
131 |
132 | public AvatarViewHolder(View itemView) {
133 | super(itemView);
134 | }
135 | }
136 |
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/adapter/holder/DateViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.adapter.holder;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | import com.aspsine.zhihu.daily.R;
9 | import com.aspsine.zhihu.daily.util.DateUtils;
10 |
11 | /**
12 | * Created by Aspsine on 2015/3/11.
13 | */
14 | public class DateViewHolder extends RecyclerView.ViewHolder {
15 | public TextView tvDate;
16 |
17 | public DateViewHolder(View itemView) {
18 | super(itemView);
19 |
20 | tvDate = (TextView) itemView.findViewById(R.id.date);
21 | }
22 |
23 | public void bindDateView(String date) {
24 | tvDate.setText(getDate(date, itemView.getContext()));
25 | }
26 |
27 | public static String getDate(String date, Context context) {
28 | if (DateUtils.isToday(date)) {
29 | return context.getResources().getString(R.string.recycler_item_main_today_hottest);
30 | } else {
31 | return DateUtils.getMainPageDate(date);
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/adapter/holder/HeaderViewPagerHolder.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.adapter.holder;
2 |
3 | import android.app.Activity;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.view.PagerAdapter;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.aspsine.zhihu.daily.R;
11 | import com.aspsine.zhihu.daily.model.Story;
12 | import com.aspsine.zhihu.daily.ui.widget.CirclePageIndicator;
13 | import com.aspsine.zhihu.daily.ui.widget.MyViewPager;
14 | import com.aspsine.zhihu.daily.ui.widget.StoryHeaderView;
15 | import com.aspsine.zhihu.daily.util.IntentUtils;
16 | import com.aspsine.zhihu.daily.util.ListUtils;
17 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
18 |
19 | import java.util.List;
20 |
21 | /**
22 | * Created by Aspsine on 2015/3/11.
23 | */
24 | public class HeaderViewPagerHolder extends RecyclerView.ViewHolder {
25 | private static final String TAG = HeaderViewPagerHolder.class.getSimpleName();
26 | private MyViewPager viewPager;
27 | private CirclePageIndicator indicator;
28 | private PagerAdapter mPagerAdapter;
29 |
30 | public HeaderViewPagerHolder(@Nullable View itemView, List stories) {
31 | super(itemView);
32 |
33 | viewPager = (MyViewPager) itemView.findViewById(R.id.viewPager);
34 | indicator = (CirclePageIndicator) itemView.findViewById(R.id.indicator);
35 | if (ListUtils.isEmpty(stories)) {
36 | return;
37 | } else if (stories.size() < 2) {
38 | indicator.setVisibility(View.GONE);
39 | }
40 | mPagerAdapter = new HeaderPagerAdapter(stories);
41 | }
42 |
43 | public void bindHeaderView() {
44 | if (viewPager.getAdapter() == null) {
45 | viewPager.setAdapter(mPagerAdapter);
46 | indicator.setViewPager(viewPager);
47 | } else {
48 | mPagerAdapter.notifyDataSetChanged();
49 | }
50 | }
51 |
52 | public boolean isAutoScrolling() {
53 | if (viewPager != null) {
54 | return viewPager.isAutoScrolling();
55 | }
56 | return false;
57 | }
58 |
59 | public void stopAutoScroll() {
60 | if (viewPager != null) {
61 | viewPager.stopAutoScroll();
62 | }
63 | }
64 |
65 | public void startAutoScroll() {
66 | if (viewPager != null) {
67 | viewPager.startAutoScroll();
68 | }
69 | }
70 |
71 | private final static class HeaderPagerAdapter extends PagerAdapter {
72 | private List mStories;
73 | private DisplayImageOptions mOptions;
74 |
75 | private int mChildCount;
76 |
77 | public HeaderPagerAdapter(List stories) {
78 | mStories = stories;
79 | this.mOptions = new DisplayImageOptions.Builder()
80 | .cacheInMemory(true)
81 | .cacheOnDisk(true)
82 | .considerExifParams(true)
83 | .build();
84 | }
85 |
86 | @Override
87 | public int getCount() {
88 | return mStories == null ? 0 : mStories.size();
89 | }
90 |
91 | @Override
92 | public boolean isViewFromObject(View view, Object object) {
93 | return view == object;
94 | }
95 |
96 | @Override
97 | public Object instantiateItem(final ViewGroup container, final int position) {
98 | StoryHeaderView storyHeaderView = StoryHeaderView.newInstance(container);
99 | final Story story = mStories.get(position);
100 | storyHeaderView.bindData(story.getTitle(), story.getImageSource(), story.getImage(), mOptions);
101 | storyHeaderView.setOnClickListener(new View.OnClickListener() {
102 | @Override
103 | public void onClick(View v) {
104 | IntentUtils.intentToStoryActivity((Activity) v.getContext(), story);
105 | }
106 | });
107 | container.addView(storyHeaderView);
108 | return storyHeaderView;
109 | }
110 |
111 | @Override
112 | public void destroyItem(ViewGroup container, int position, Object object) {
113 | container.removeView((StoryHeaderView) object);
114 | }
115 |
116 | @Override
117 | public void notifyDataSetChanged() {
118 | super.notifyDataSetChanged();
119 | mChildCount = getCount();
120 | }
121 |
122 | @Override
123 | public int getItemPosition(Object object) {
124 | if (mChildCount > 0) {
125 | mChildCount--;
126 | return POSITION_NONE;
127 | }
128 | return super.getItemPosition(object);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/adapter/holder/RecyclerHeaderViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.adapter.holder;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | /**
7 | * Created by Aspsine on 2015/3/2.
8 | */
9 | public class RecyclerHeaderViewHolder extends RecyclerView.ViewHolder {
10 |
11 | public RecyclerHeaderViewHolder(View itemView) {
12 | super(itemView);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/adapter/holder/StoryViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.adapter.holder;
2 |
3 | import android.app.Activity;
4 | import android.support.v7.widget.CardView;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.text.Html;
7 | import android.text.TextUtils;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 |
13 | import com.aspsine.zhihu.daily.R;
14 | import com.aspsine.zhihu.daily.model.Story;
15 | import com.aspsine.zhihu.daily.ui.activity.NavigationDrawerActivity;
16 | import com.aspsine.zhihu.daily.ui.fragment.NavigationFragment;
17 | import com.aspsine.zhihu.daily.util.IntentUtils;
18 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
19 | import com.nostra13.universalimageloader.core.ImageLoader;
20 |
21 | /**
22 | * Created by Aspsine on 2015/3/11.
23 | */
24 | public class StoryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
25 | private CardView card;
26 | private TextView text;
27 | private TextView theme;
28 | private ImageView image;
29 | private ImageView ivMultiPic;
30 | private ImageView line;
31 | private RelativeLayout rlContent;
32 | private DisplayImageOptions mOptions;
33 | private Story mStory;
34 |
35 | public StoryViewHolder(View itemView) {
36 | super(itemView);
37 |
38 | this.mOptions = new DisplayImageOptions.Builder()
39 | .showImageOnLoading(R.drawable.image_small_default)
40 | .showImageForEmptyUri(R.drawable.image_small_default)
41 | .showImageOnFail(R.drawable.image_small_default)
42 | .cacheInMemory(true)
43 | .cacheOnDisk(true)
44 | .considerExifParams(true)
45 | .build();
46 |
47 | card = (CardView) itemView.findViewById(R.id.card);
48 | text = (TextView) itemView.findViewById(R.id.text);
49 | image = (ImageView) itemView.findViewById(R.id.image);
50 | ivMultiPic = (ImageView) itemView.findViewById(R.id.ivMultiPic);
51 | rlContent = (RelativeLayout) itemView.findViewById(R.id.rl_content);
52 | theme = (TextView) itemView.findViewById(R.id.theme);
53 | line = (ImageView) itemView.findViewById(R.id.line);
54 | card.setOnClickListener(this);
55 | theme.setOnClickListener(this);
56 | }
57 |
58 | @Override
59 | public void onClick(View v) {
60 | if (v.getId() == R.id.card) {
61 | IntentUtils.intentToStoryActivity((Activity) v.getContext(), mStory);
62 | } else if (v.getId() == R.id.theme) {
63 | final NavigationFragment navigationFragment = (NavigationFragment) ((NavigationDrawerActivity) itemView.getContext()).getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
64 | if (navigationFragment != null && navigationFragment.isAdded()) {
65 | navigationFragment.openDrawer();
66 | v.postDelayed(new Runnable() {
67 | @Override
68 | public void run() {
69 | navigationFragment.selectTheme(mStory.getTheme());
70 | }
71 | }, 500);
72 | }
73 | }
74 | }
75 |
76 | public void bindStoryView(Story story) {
77 | mStory = story;
78 | if (mStory.getTheme() == null) {
79 | theme.setVisibility(View.GONE);
80 | line.setVisibility(View.GONE);
81 | } else {
82 | theme.setVisibility(View.VISIBLE);
83 | line.setVisibility(View.VISIBLE);
84 | StringBuilder sb = new StringBuilder();
85 | sb.append(itemView.getResources().getString(R.string.recycler_item_main_select_from))
86 | .append(" ").append("")
87 | .append(mStory.getTheme().getName())
88 | .append(" ");
89 | theme.setText(Html.fromHtml(sb.toString()));
90 | }
91 | text.setText(String.valueOf(mStory.getTitle()));
92 |
93 | String imageUrl = mStory.getImages() == null ? "" : mStory.getImages().get(0);
94 | if (TextUtils.isEmpty(imageUrl) || TextUtils.isEmpty(mStory.getMultiPic())) {
95 | ivMultiPic.setVisibility(View.GONE);
96 | } else if (Boolean.valueOf(mStory.getMultiPic())) {
97 | ivMultiPic.setVisibility(View.VISIBLE);
98 | }
99 |
100 | if (TextUtils.isEmpty(imageUrl)) {
101 | image.setVisibility(View.GONE);
102 | } else {
103 | image.setVisibility(View.VISIBLE);
104 | ImageLoader.getInstance().displayImage(imageUrl, image, mOptions);
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/fragment/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 |
6 | /**
7 | * Created by Aspsine on 2015/3/19.
8 | */
9 | public class BaseFragment extends Fragment {
10 | private static final String TAG = BaseFragment.class.getSimpleName();
11 | /**
12 | * The fragment argument representing the section number for this
13 | * fragment.
14 | */
15 | public static final String ARG_THEME_NUMBER = "theme_number";
16 | public static final String ARG_THEME_ID = "theme_id";
17 |
18 | public static final int THEME_NUMBER_MAIN = 0;
19 | public static final String THEME_ID_MAIN = "section_id_main";
20 |
21 | public static final String EXTRA_STORY_ID = "extra_story_id";
22 |
23 | private int mArgThemeNumber;
24 |
25 | private String mArgThemeId;
26 |
27 | public BaseFragment() {
28 | }
29 |
30 | public static BaseFragment newInstance(int position, String sectionId) {
31 | Bundle bundle = new Bundle();
32 | bundle.putInt(ARG_THEME_NUMBER, position);
33 | bundle.putString(ARG_THEME_ID, sectionId);
34 | BaseFragment fragment = null;
35 | if (position == 0) {
36 | fragment = new DailyStoriesFragment();
37 | } else {
38 | fragment = new ThemeStoriesFragment();
39 | }
40 | fragment.setArguments(bundle);
41 | return fragment;
42 | }
43 |
44 | @Override
45 | public void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | mArgThemeNumber = getArguments().getInt(ARG_THEME_NUMBER);
48 | mArgThemeId = getArguments().getString(ARG_THEME_ID);
49 | }
50 |
51 | public int getThemeNumber() {
52 | return mArgThemeNumber;
53 | }
54 |
55 | public String getThemeId() {
56 | return mArgThemeId;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/fragment/GuideFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.fragment;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.text.Html;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.TextView;
12 |
13 | import com.aspsine.zhihu.daily.R;
14 | import com.aspsine.zhihu.daily.ui.activity.GuiderActivity;
15 | import com.aspsine.zhihu.daily.util.SharedPrefUtils;
16 |
17 | /**
18 | *
19 | */
20 | public class GuideFragment extends Fragment {
21 | public static final String TAG = GuideFragment.class.getSimpleName();
22 |
23 | String hello = "Welcome This application is a simple demonstration of Zhihu Daily Android developed by me. It's a free app. All the information, content and api copyright is belong to Zhihu. Inc.
-Aspsine
About Email: littleximail@gmail.com
Github: github.com/aspsine
";
24 |
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | }
29 |
30 | @Override
31 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
32 | View rootView = inflater.inflate(R.layout.fragment_guide, container, false);
33 | TextView tvHello = (TextView) rootView.findViewById(R.id.tvHello);
34 | tvHello.setText(Html.fromHtml(hello));
35 | rootView.findViewById(R.id.btnEnter).setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | SharedPrefUtils.markFirstLaunch(getActivity());
39 | ((GuiderActivity)getActivity()).intentToMainActivity();
40 | }
41 | });
42 | return rootView;
43 | }
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/fragment/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.fragment;
2 |
3 |
4 | import android.app.Fragment;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceFragment;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.aspsine.zhihu.daily.R;
14 |
15 | /**
16 | * A simple {@link Fragment} subclass.
17 | */
18 | public class SettingsFragment extends PreferenceFragment {
19 |
20 |
21 | public SettingsFragment() {
22 | // Required empty public constructor
23 | }
24 |
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | addPreferencesFromResource(R.xml.pref_general);
29 | }
30 |
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
33 | Bundle savedInstanceState) {
34 | setHasOptionsMenu(true);
35 | // Inflate the layout for this fragment
36 | return super.onCreateView(inflater, container, savedInstanceState);
37 | }
38 |
39 | @Override
40 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
41 | super.onCreateOptionsMenu(menu, inflater);
42 | inflater.inflate(R.menu.menu_story, menu);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/fragment/SplashFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.fragment;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.view.animation.Animation;
12 | import android.view.animation.AnimationUtils;
13 | import android.widget.ImageView;
14 | import android.widget.RelativeLayout;
15 | import android.widget.TextView;
16 |
17 | import com.aspsine.zhihu.daily.App;
18 | import com.aspsine.zhihu.daily.R;
19 | import com.aspsine.zhihu.daily.animation.AnimationEndListener;
20 | import com.aspsine.zhihu.daily.model.StartImage;
21 | import com.aspsine.zhihu.daily.respository.interfaces.Repository;
22 | import com.aspsine.zhihu.daily.ui.activity.GuiderActivity;
23 | import com.aspsine.zhihu.daily.util.DensityUtil;
24 | import com.aspsine.zhihu.daily.util.L;
25 | import com.aspsine.zhihu.daily.util.UIUtils;
26 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
27 | import com.nostra13.universalimageloader.core.ImageLoader;
28 | import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
29 |
30 | /**
31 | * Created by sf on 2015/1/13.
32 | * splash page
33 | */
34 | public class SplashFragment extends Fragment {
35 | public static final String TAG = SplashFragment.class.getSimpleName();
36 |
37 | private TextView tvAuthor;
38 | private ImageView ivLogo;
39 | public ImageView ivSplash;
40 | public Animation mIvSplashAnim;
41 |
42 | private final DisplayImageOptions mOptions = new DisplayImageOptions.Builder()
43 | .cacheInMemory(false)
44 | .cacheOnDisk(true)
45 | .considerExifParams(true)
46 | .build();
47 |
48 | private int mWidth;
49 | private int mHeight;
50 |
51 | @Override
52 | public void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | mIvSplashAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.splash);
55 |
56 | // if api >= 19 use themes in values-v19 has a full screen splash.
57 | mWidth = DensityUtil.getScreenWidth(getActivity());
58 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
59 | mHeight = DensityUtil.getScreenHeightWithDecorations(getActivity());
60 | } else {
61 | mHeight = DensityUtil.getScreenHeight(getActivity());
62 | }
63 | L.i(TAG, "screen height = " + mHeight);
64 | }
65 |
66 | @Override
67 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
68 | return inflater.inflate(R.layout.fragment_splash, container, false);
69 | }
70 |
71 | @Override
72 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
73 | super.onViewCreated(view, savedInstanceState);
74 | tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
75 | ivSplash = (ImageView) view.findViewById(R.id.splash);
76 | ivLogo = (ImageView) view.findViewById(R.id.ivLogo);
77 |
78 | // if api >= 19 use themes in values-v19 has a full screen splash.
79 | // so we need relayout the tvAuthor and ivLogo by set a bigger marginBottom
80 | int navigationBarHeight = UIUtils.getNavigationBarHeight(getActivity());
81 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
82 |
83 | int tvMarginBottom = navigationBarHeight + DensityUtil.dip2px(getActivity(), 8);
84 | int logoMarginBottom = navigationBarHeight + DensityUtil.dip2px(getActivity(), 48);
85 | ((RelativeLayout.LayoutParams) tvAuthor.getLayoutParams()).setMargins(0, 0, 0, tvMarginBottom);
86 | ((RelativeLayout.LayoutParams) ivLogo.getLayoutParams()).setMargins(0, 0, 0, logoMarginBottom);
87 |
88 | tvAuthor.requestLayout();
89 | ivLogo.requestLayout();
90 | }
91 | }
92 |
93 | @Override
94 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
95 | super.onActivityCreated(savedInstanceState);
96 | mIvSplashAnim.setAnimationListener(animListener);
97 | refresh();
98 | }
99 |
100 | @Override
101 | public void onDetach() {
102 | super.onDetach();
103 | mIvSplashAnim = null;
104 | }
105 |
106 | private final Animation.AnimationListener animListener = new AnimationEndListener() {
107 | @Override
108 | public void onAnimationEnd(Animation animation) {
109 | ivSplash.setVisibility(View.GONE);
110 | ((GuiderActivity) getActivity()).intentToMainActivity();
111 | }
112 | };
113 |
114 | private void refresh() {
115 |
116 | App.getRepository().getStartImage(mWidth, mHeight, mOptions, new Repository.Callback() {
117 | @Override
118 | public void success(StartImage startImage, boolean outDate) {
119 | tvAuthor.setText(startImage.getText());
120 | ImageLoader.getInstance().displayImage(startImage.getImg(), ivSplash, mOptions, new SimpleImageLoadingListener(){
121 | @Override
122 | public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
123 | super.onLoadingComplete(imageUri, view, loadedImage);
124 | ivSplash.startAnimation(mIvSplashAnim);
125 | }
126 | });
127 |
128 | }
129 |
130 | @Override
131 | public void failure(Exception e) {
132 | L.i(TAG, "default image.");
133 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
134 | ivSplash.setBackground(getResources().getDrawable(R.drawable.bg_splash));
135 | }else{
136 | ivSplash.setBackgroundDrawable(getResources().getDrawable(R.drawable.bg_splash));
137 | }
138 | ivSplash.setAnimation(mIvSplashAnim);
139 | tvAuthor.setText(getResources().getString(R.string.splash_text));
140 | e.printStackTrace();
141 | }
142 | });
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/fragment/ThemeStoriesFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.widget.SwipeRefreshLayout;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.Toast;
11 |
12 | import com.aspsine.zhihu.daily.App;
13 | import com.aspsine.zhihu.daily.R;
14 | import com.aspsine.zhihu.daily.model.Theme;
15 | import com.aspsine.zhihu.daily.respository.interfaces.Repository;
16 | import com.aspsine.zhihu.daily.ui.adapter.ThemeStoriesAdapter;
17 | import com.aspsine.zhihu.daily.ui.widget.LoadMoreRecyclerView;
18 | import com.aspsine.zhihu.daily.util.L;
19 |
20 | /**
21 | * Created by Aspsine on 2015/3/25.
22 | */
23 | public class ThemeStoriesFragment extends BaseFragment {
24 | public static final String TAG = ThemeStoriesFragment.class.getSimpleName();
25 |
26 | private SwipeRefreshLayout swipeRefreshLayout;
27 |
28 | private LoadMoreRecyclerView recyclerView;
29 |
30 | private ThemeStoriesAdapter mAdapter;
31 |
32 | private String mThemeId;
33 |
34 | private String mLastStoryId;
35 |
36 | /**
37 | * Flag to indicate whither the data is successful loaded
38 | */
39 | private boolean isDataLoaded;
40 |
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | if (savedInstanceState == null) {
45 | mAdapter = new ThemeStoriesAdapter();
46 | }
47 | }
48 |
49 | @Override
50 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
51 | L.i(TAG, getThemeNumber() + " : " + getThemeId());
52 | return inflater.inflate(R.layout.fragment_theme_stories, container, false);
53 | }
54 |
55 | @Override
56 | public void onViewCreated(View view, Bundle savedInstanceState) {
57 | super.onViewCreated(view, savedInstanceState);
58 | swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout);
59 | recyclerView = (LoadMoreRecyclerView) view.findViewById(R.id.recyclerView);
60 | recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
61 | // TODO adapter
62 | recyclerView.setAdapter(mAdapter);
63 | swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_dark, android.R.color.holo_blue_light, android.R.color.holo_green_light, android.R.color.holo_green_light);
64 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
65 | @Override
66 | public void onRefresh() {
67 | refresh();
68 | }
69 | });
70 |
71 | recyclerView.setOnLoadMoreListener(new LoadMoreRecyclerView.onLoadMoreListener() {
72 | @Override
73 | public void onLoadMore() {
74 | recyclerView.setLoadingMore(true);
75 | loadMore();
76 | }
77 |
78 | @Override
79 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
80 |
81 | }
82 | });
83 | }
84 |
85 | @Override
86 | public void onActivityCreated(Bundle savedInstanceState) {
87 | super.onActivityCreated(savedInstanceState);
88 | mThemeId = getThemeId();
89 | swipeRefreshLayout.post(new Runnable() {
90 | @Override
91 | public void run() {
92 | if (!isDataLoaded) {
93 | swipeRefreshLayout.setRefreshing(true);
94 | refresh();
95 | }
96 | }
97 | });
98 | }
99 |
100 | @Override
101 | public void onDetach() {
102 | super.onDetach();
103 | }
104 |
105 | private void refresh() {
106 | isDataLoaded = false;
107 |
108 | App.getRepository().getTheme(mThemeId, new Repository.Callback() {
109 | @Override
110 | public void success(Theme theme, boolean outDate) {
111 | isDataLoaded = true;
112 | swipeRefreshLayout.setRefreshing(false);
113 | if (theme != null && mAdapter != null) {
114 | if (theme.getStories().size() > 0) {
115 | mLastStoryId = theme.getStories().get(theme.getStories().size() - 1).getId();
116 | }
117 | L.i(TAG, "last story id: " + mLastStoryId);
118 | mAdapter.setTheme(theme);
119 | }
120 | }
121 |
122 | @Override
123 | public void failure(Exception e) {
124 | isDataLoaded = false;
125 | swipeRefreshLayout.setRefreshing(false);
126 | Toast.makeText(getActivity(), "refresh error", Toast.LENGTH_SHORT).show();
127 | e.printStackTrace();
128 | }
129 | });
130 | }
131 |
132 | private void loadMore() {
133 |
134 | App.getRepository().getThemeBeforeStory(mThemeId, mLastStoryId, new Repository.Callback() {
135 | @Override
136 | public void success(Theme theme, boolean outDate) {
137 | recyclerView.setLoadingMore(false);
138 | if (theme != null && mAdapter != null) {
139 | if (theme.getStories().size() > 0) {
140 | mLastStoryId = theme.getStories().get(theme.getStories().size() - 1).getId();
141 | mAdapter.appendStories(theme.getStories());
142 | }
143 | }
144 | }
145 |
146 | @Override
147 | public void failure(Exception e) {
148 | recyclerView.setLoadingMore(false);
149 | Toast.makeText(getActivity(), "load more error", Toast.LENGTH_SHORT).show();
150 | e.printStackTrace();
151 | }
152 | });
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/AvatarsView.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.view.MotionEvent;
7 | import android.widget.HorizontalScrollView;
8 | import android.widget.ImageView;
9 | import android.widget.LinearLayout;
10 | import android.widget.TextView;
11 |
12 | import com.aspsine.zhihu.daily.R;
13 | import com.aspsine.zhihu.daily.util.DensityUtil;
14 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
15 | import com.nostra13.universalimageloader.core.ImageLoader;
16 |
17 | import java.util.List;
18 |
19 | import butterknife.ButterKnife;
20 | import butterknife.InjectView;
21 |
22 | /**
23 | * Created by aspsine on 15-3-28.
24 | */
25 | public class AvatarsView extends HorizontalScrollView {
26 | @InjectView(R.id.title)
27 | TextView title;
28 | @InjectView(R.id.llAvatarContainer)
29 | LinearLayout llAvatarContainer;
30 | private DisplayImageOptions mOptions;
31 |
32 | public AvatarsView(Context context) {
33 | this(context, null);
34 | }
35 |
36 | public AvatarsView(Context context, AttributeSet attrs) {
37 | this(context, attrs, 0);
38 | }
39 |
40 | public AvatarsView(Context context, AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | init();
43 | }
44 |
45 | private void init() {
46 | setOverScrollMode(OVER_SCROLL_NEVER);
47 | LayoutInflater.from(getContext()).inflate(R.layout.view_avatars, this, true);
48 | ButterKnife.inject(this);
49 | mOptions = new DisplayImageOptions.Builder()
50 | .showImageOnLoading(R.drawable.comment_avatar)
51 | .showImageForEmptyUri(R.drawable.comment_avatar)
52 | .showImageOnFail(R.drawable.comment_avatar)
53 | .displayer(new CircleBitmapDisplayer())
54 | .cacheInMemory(true)
55 | .cacheOnDisk(true)
56 | .considerExifParams(true)
57 | .build();
58 | }
59 |
60 | public void bindData(String name, List images) {
61 | title.setText(name);
62 | int hw = DensityUtil.dip2px(getContext(), 36);
63 | int margin = DensityUtil.dip2px(getContext(), 8);
64 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(hw, hw);
65 | lp.setMargins(margin, margin, margin, margin);
66 | llAvatarContainer.removeAllViews();
67 | if (images != null && images.size() > 0) {
68 | for (String url : images) {
69 | ImageView imageView = new ImageView(getContext());
70 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
71 | imageView.setLayoutParams(lp);
72 | llAvatarContainer.addView(imageView);
73 | ImageLoader.getInstance().displayImage(url, imageView, mOptions);
74 | }
75 | }
76 | }
77 |
78 |
79 | private float mDownX;
80 | private float mDownY;
81 | @Override
82 | public boolean dispatchTouchEvent(MotionEvent ev) {
83 | switch (ev.getAction()) {
84 | case MotionEvent.ACTION_DOWN:
85 | mDownX = ev.getX();
86 | mDownY = ev.getY();
87 | getParent().requestDisallowInterceptTouchEvent(true);
88 | break;
89 | case MotionEvent.ACTION_CANCEL:
90 | case MotionEvent.ACTION_UP:
91 | getParent().requestDisallowInterceptTouchEvent(false);
92 | break;
93 | case MotionEvent.ACTION_MOVE:
94 | if (Math.abs(ev.getX() - mDownX) > Math.abs(ev.getY() - mDownY)) {
95 |
96 | //不允许拦截事件,自己处理
97 | getParent().requestDisallowInterceptTouchEvent(true);
98 | } else {
99 | getParent().requestDisallowInterceptTouchEvent(false);
100 | }
101 | break;
102 | }
103 | return super.dispatchTouchEvent(ev);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/CheckableLinearLayout.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Checkable;
10 | import android.widget.LinearLayout;
11 |
12 | /**
13 | * Created by Aspsine on 2015/3/23.
14 | */
15 | public class CheckableLinearLayout extends LinearLayout implements Checkable {
16 |
17 | private boolean mChecked;
18 |
19 | private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
20 |
21 | public CheckableLinearLayout(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public CheckableLinearLayout(Context context, AttributeSet attrs) {
26 | this(context, attrs, 0);
27 | }
28 |
29 | public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
30 | super(context, attrs, defStyleAttr);
31 | init();
32 | }
33 |
34 | private void init() {
35 | // setClickable(true);
36 | // if (getBackground() == null) {
37 | // setBackgroundResource(R.drawable.mca__list_item_selector);
38 | // }
39 | }
40 |
41 | /**********************/
42 | /** Handle clicks **/
43 | /**
44 | * ******************
45 | */
46 |
47 | @Override
48 | public boolean performClick() {
49 | toggle();
50 | return super.performClick();
51 | }
52 |
53 | @Override
54 | public boolean onInterceptTouchEvent(MotionEvent ev) {
55 | return onTouchEvent(ev);
56 | }
57 |
58 | /**************************/
59 | /** Checkable **/
60 | /**
61 | * **********************
62 | */
63 |
64 | public void toggle() {
65 | setChecked(!mChecked);
66 | }
67 |
68 | public boolean isChecked() {
69 | return mChecked;
70 | }
71 |
72 | public void setChecked(boolean checked) {
73 | if (mChecked != checked) {
74 | mChecked = checked;
75 | refreshDrawableState();
76 | setCheckedRecursive(this, checked);
77 | }
78 | }
79 |
80 | private void setCheckedRecursive(ViewGroup parent, boolean checked) {
81 | int count = parent.getChildCount();
82 | for (int i = 0; i < count; i++) {
83 | View v = parent.getChildAt(i);
84 | if (v instanceof Checkable) {
85 | ((Checkable) v).setChecked(checked);
86 | }
87 |
88 | if (v instanceof ViewGroup) {
89 | setCheckedRecursive((ViewGroup) v, checked);
90 | }
91 | }
92 | }
93 |
94 | /**************************/
95 | /** Drawable States **/
96 | /**
97 | * **********************
98 | */
99 |
100 | @Override
101 | protected int[] onCreateDrawableState(int extraSpace) {
102 | final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
103 | if (isChecked()) {
104 | mergeDrawableStates(drawableState, CHECKED_STATE_SET);
105 | }
106 | return drawableState;
107 | }
108 |
109 | @Override
110 | protected void drawableStateChanged() {
111 | super.drawableStateChanged();
112 |
113 | Drawable drawable = getBackground();
114 | if (drawable != null) {
115 | int[] myDrawableState = getDrawableState();
116 | drawable.setState(myDrawableState);
117 | invalidate();
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/LoadMoreRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 |
8 | import com.aspsine.zhihu.daily.util.L;
9 |
10 | /**
11 | * Created by Aspsine on 2015/3/20.
12 | *
13 | * be careful! current version just support LinearLayoutManager
14 | *
15 | * Version 1.0 beta
16 | */
17 | public class LoadMoreRecyclerView extends RecyclerView {
18 | private static final String TAG = LoadMoreRecyclerView.class.getSimpleName();
19 | private boolean mIsLoadingMore = false;
20 | private onLoadMoreListener mListener;
21 |
22 | public LoadMoreRecyclerView(Context context) {
23 | this(context, null);
24 | }
25 |
26 | public LoadMoreRecyclerView(Context context, AttributeSet attrs) {
27 | super(context, attrs, 0);
28 | }
29 |
30 | public LoadMoreRecyclerView(Context context, AttributeSet attrs, int defStyle) {
31 | super(context, attrs, defStyle);
32 | }
33 |
34 | void init() {
35 |
36 | this.setOnScrollListener(new onLoadMoreScrollListener());
37 | }
38 |
39 | public static class onLoadMoreScrollListener extends OnScrollListener {
40 |
41 | @Override
42 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
43 | LoadMoreRecyclerView view = (LoadMoreRecyclerView) recyclerView;
44 | onLoadMoreListener onLoadMoreListener = view.getOnLoadMoreListener();
45 |
46 | onLoadMoreListener.onScrolled(recyclerView, dx, dy);
47 |
48 | LinearLayoutManager layoutManager = (LinearLayoutManager) view.getLayoutManager();
49 | int lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition();
50 | int itemCount = layoutManager.getItemCount();
51 | if (lastVisibleItem >= itemCount - 1 && !view.getLoadingMore()) {
52 | onLoadMoreListener.onLoadMore();
53 | L.i(TAG, "load more: lastVisibleItem = " + lastVisibleItem + ", itemCount" + itemCount);
54 | } else {
55 | super.onScrolled(recyclerView, dx, dy);
56 | }
57 | }
58 | }
59 |
60 |
61 | public void setOnLoadMoreListener(onLoadMoreListener listener) {
62 | this.mListener = listener;
63 | init();
64 | }
65 |
66 | public onLoadMoreListener getOnLoadMoreListener() {
67 | return this.mListener;
68 | }
69 |
70 | public void setLoadingMore(boolean isLoading) {
71 | mIsLoadingMore = isLoading;
72 | }
73 |
74 | public boolean getLoadingMore() {
75 | return mIsLoadingMore;
76 | }
77 |
78 | public interface onLoadMoreListener {
79 | public void onLoadMore();
80 |
81 | public void onScrolled(RecyclerView recyclerView, int dx, int dy);
82 | }
83 |
84 | @Override
85 | public void setLayoutManager(LayoutManager layout) {
86 | if (layout instanceof LinearLayoutManager) {
87 | super.setLayoutManager(layout);
88 | } else {
89 | throw new IllegalArgumentException("LoadMoreRecyclerView must have a LinearLayoutManager!");
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/MySwipeRefreshLayout.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.support.v4.widget.SwipeRefreshLayout;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 | /**
9 | * Created by Aspsine on 2015/3/11.
10 | */
11 | public class MySwipeRefreshLayout extends SwipeRefreshLayout {
12 | private float xDistance, yDistance, xLast, yLast;
13 |
14 | public MySwipeRefreshLayout(Context context) {
15 | super(context);
16 | }
17 |
18 | public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
19 | super(context, attrs);
20 | }
21 |
22 | @Override
23 | public boolean onInterceptTouchEvent(MotionEvent ev) {
24 |
25 | switch (ev.getAction()) {
26 | case MotionEvent.ACTION_DOWN:
27 | xDistance = yDistance = 0f;
28 | xLast = ev.getX();
29 | yLast = ev.getY();
30 | break;
31 | case MotionEvent.ACTION_UP:
32 | break;
33 | case MotionEvent.ACTION_MOVE:
34 | final float curX = ev.getX();
35 | final float curY = ev.getY();
36 | xDistance += Math.abs(curX - xLast);
37 | yDistance += Math.abs(curY - yLast);
38 | xLast = curX;
39 | yLast = curY;
40 | if (xDistance > yDistance) {
41 | return false;
42 | }
43 | }
44 | return super.onInterceptTouchEvent(ev);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/MyViewPager.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.support.v4.view.PagerAdapter;
7 | import android.support.v4.view.ViewPager;
8 | import android.util.AttributeSet;
9 | import android.view.MotionEvent;
10 |
11 | import com.aspsine.zhihu.daily.util.L;
12 |
13 | /**
14 | * Created by Aspsine on 2015/3/11.
15 | */
16 | public class MyViewPager extends ViewPager {
17 | private static final String TAG = MyViewPager.class.getSimpleName();
18 | private static final int WHAT_SCROLL = 0;
19 | private long mDelayTime = 5000;
20 |
21 | private float mDownX;
22 | private float mDownY;
23 |
24 | private boolean isAutoScroll;
25 | public boolean isStopByTouch;
26 |
27 | public MyViewPager(Context context) {
28 | this(context, null);
29 | }
30 |
31 | public MyViewPager(Context context, AttributeSet attrs) {
32 | super(context, attrs);
33 | }
34 |
35 | @Override
36 | public boolean dispatchTouchEvent(MotionEvent ev) {
37 | switch (ev.getAction()) {
38 | case MotionEvent.ACTION_DOWN:
39 | mDownX = ev.getX();
40 | mDownY = ev.getY();
41 | getParent().requestDisallowInterceptTouchEvent(true);
42 | break;
43 | case MotionEvent.ACTION_CANCEL:
44 | case MotionEvent.ACTION_UP:
45 | getParent().requestDisallowInterceptTouchEvent(false);
46 | break;
47 | case MotionEvent.ACTION_MOVE:
48 | if (Math.abs(ev.getX() - mDownX) > Math.abs(ev.getY() - mDownY)) {
49 |
50 | //不允许拦截事件,自己处理
51 | getParent().requestDisallowInterceptTouchEvent(true);
52 | } else {
53 | getParent().requestDisallowInterceptTouchEvent(false);
54 | }
55 | break;
56 | }
57 | if (ev.getAction() == MotionEvent.ACTION_DOWN) {
58 | stopAutoScroll();
59 | isStopByTouch = true;
60 | } else if (ev.getAction() == MotionEvent.ACTION_UP && isStopByTouch) {
61 | startAutoScroll();
62 | }
63 | return super.dispatchTouchEvent(ev);
64 | }
65 |
66 | public void setDelayTime(int delayTime) {
67 | this.mDelayTime = delayTime;
68 | }
69 |
70 |
71 | public void startAutoScroll() {
72 | isAutoScroll = true;
73 | sendScrollMessage(mDelayTime);
74 | }
75 |
76 | public void stopAutoScroll() {
77 | isAutoScroll = false;
78 | handler.removeMessages(WHAT_SCROLL);
79 | }
80 |
81 | public boolean isAutoScrolling() {
82 | return isAutoScroll;
83 | }
84 |
85 | private void sendScrollMessage(long delayTimeInMills) {
86 | if (isAutoScroll) {
87 | handler.removeMessages(WHAT_SCROLL);
88 | handler.sendEmptyMessageDelayed(WHAT_SCROLL, delayTimeInMills);
89 | }
90 | }
91 |
92 | private void scrollOnce() {
93 | PagerAdapter adapter = getAdapter();
94 | int currentItem = getCurrentItem();
95 | int count;
96 | if (adapter == null || (count = adapter.getCount()) < 1) {
97 | stopAutoScroll();
98 | return;
99 | }
100 | if (currentItem < count) {
101 | currentItem++;
102 | }
103 | if (currentItem == count) {
104 | currentItem = 0;
105 | }
106 | L.i(TAG, currentItem + "");
107 | setCurrentItem(currentItem);
108 | }
109 |
110 | private final Handler handler = new Handler() {
111 | @Override
112 | public void handleMessage(Message msg) {
113 | super.handleMessage(msg);
114 | if (msg.what == WHAT_SCROLL) {
115 | scrollOnce();
116 | sendScrollMessage(mDelayTime);
117 | }
118 | }
119 | };
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/PageIndicator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Patrik Akerfeldt
3 | * Copyright (C) 2011 Jake Wharton
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.aspsine.zhihu.daily.ui.widget;
19 |
20 | import android.support.v4.view.ViewPager;
21 |
22 | /**
23 | * Copyright 2012 Jake Wharton
24 | * Copyright 2011 Patrik Åkerfeldt
25 | * Copyright 2011 Francisco Figueiredo Jr.
26 | *
27 | * Licensed under the Apache License, Version 2.0 (the "License");
28 | * you may not use this file except in compliance with the License.
29 | * You may obtain a copy of the License at
30 | * http://www.apache.org/licenses/LICENSE-2.0
31 | * Unless required by applicable law or agreed to in writing, software
32 | * distributed under the License is distributed on an "AS IS" BASIS,
33 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 | * See the License for the specific language governing permissions and
35 | * limitations under the License.
36 | *
37 | *
38 | * A PageIndicator is responsible to show an visual indicator on the total views
39 | * number and the current visible view.
40 | */
41 | public interface PageIndicator extends ViewPager.OnPageChangeListener {
42 | /**
43 | * Bind the indicator to a ViewPager.
44 | *
45 | * @param view
46 | */
47 | void setViewPager(ViewPager view);
48 |
49 | /**
50 | * Bind the indicator to a ViewPager.
51 | *
52 | * @param view
53 | * @param initialPosition
54 | */
55 | void setViewPager(ViewPager view, int initialPosition);
56 |
57 | /**
58 | * Set the current page of both the ViewPager and indicator.
59 | *
60 | * This must be used if you need to set the page before
61 | * the views are drawn on screen (e.g., default start page).
62 | *
63 | * @param item
64 | */
65 | void setCurrentItem(int item);
66 |
67 | /**
68 | * Set a page change listener which will receive forwarded events.
69 | *
70 | * @param listener
71 | */
72 | void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
73 |
74 | /**
75 | * Notify the indicator that the fragment list has changed.
76 | */
77 | void notifyDataSetChanged();
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/ui/widget/StoryHeaderView.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 |
13 | import com.aspsine.zhihu.daily.R;
14 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
15 | import com.nostra13.universalimageloader.core.ImageLoader;
16 |
17 | import butterknife.ButterKnife;
18 | import butterknife.InjectView;
19 |
20 | /**
21 | * Created by Aspsine on 2015/3/24.
22 | */
23 | public class StoryHeaderView extends RelativeLayout {
24 | @InjectView(R.id.image)
25 | ImageView image;
26 | @InjectView(R.id.title)
27 | TextView title;
28 | @InjectView(R.id.tvAuthor)
29 | TextView author;
30 |
31 | public StoryHeaderView(Context context) {
32 | this(context, null);
33 | }
34 |
35 | public StoryHeaderView(Context context, AttributeSet attrs) {
36 | this(context, attrs, 0);
37 | }
38 |
39 | public StoryHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
40 | super(context, attrs, defStyleAttr);
41 | init();
42 | }
43 |
44 | private void init() {
45 | setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getResources().getDimensionPixelSize(R.dimen.view_header_story_height)));
46 | LayoutInflater.from(this.getContext()).inflate(R.layout.view_header_story, this, true);
47 | ButterKnife.inject(this);
48 | }
49 |
50 | public void bindData(String title, String author, String url) {
51 | DisplayImageOptions options = new DisplayImageOptions.Builder()
52 | .cacheInMemory(true)
53 | .cacheOnDisk(true)
54 | .considerExifParams(true)
55 | .build();
56 | this.bindData(title, author, url, options);
57 | }
58 |
59 | public void bindData(String title, String author, String url, DisplayImageOptions options) {
60 | this.title.setText(title);
61 | if (TextUtils.isEmpty(author)) {
62 | this.author.setVisibility(View.GONE);
63 | } else {
64 | this.author.setVisibility(View.VISIBLE);
65 | this.author.setText(author);
66 | }
67 | ImageLoader.getInstance().displayImage(url, image, options);
68 | }
69 |
70 | public static StoryHeaderView newInstance(ViewGroup container) {
71 | return new StoryHeaderView(container.getContext());
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import java.text.DateFormat;
4 | import java.text.ParseException;
5 | import java.text.SimpleDateFormat;
6 | import java.util.Calendar;
7 | import java.util.Date;
8 | import java.util.concurrent.CancellationException;
9 |
10 | /**
11 | * Created by Aspsine on 2015/2/28.
12 | */
13 | public class DateUtils {
14 |
15 | public static String getDate(Date date, String format) {
16 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
17 | return String.valueOf(simpleDateFormat.format(date));
18 | }
19 |
20 | public static boolean isToday(String date) {
21 | String today = new SimpleDateFormat("yyyyMMdd").format(Calendar.getInstance().getTime());
22 | if (date.equals(today)) {
23 | return true;
24 | }
25 | return false;
26 | }
27 |
28 | public static String getMainPageDate(String date) {
29 | String mData = "";
30 | try {
31 | Date tmpDate = new SimpleDateFormat("yyyyMMdd").parse(date);
32 | mData = DateFormat.getDateInstance(DateFormat.FULL).format(tmpDate);
33 | } catch (ParseException e) {
34 | e.printStackTrace();
35 | }
36 |
37 | String thisYear = Calendar.getInstance().get(Calendar.YEAR) + "年";
38 | if (mData.startsWith(thisYear)) {
39 | return mData.replace(thisYear, "");
40 | }
41 | return mData;
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.hardware.display.DisplayManager;
6 | import android.util.DisplayMetrics;
7 | import android.view.Display;
8 | import android.view.WindowManager;
9 |
10 | import java.lang.reflect.InvocationTargetException;
11 |
12 | /**
13 | * Created by aspsine on 15-3-13.
14 | */
15 | public class DensityUtil {
16 |
17 | public static int getScreenWidth(Context context) {
18 | DisplayMetrics dm = new DisplayMetrics();
19 | ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
20 | return dm.widthPixels;
21 | }
22 |
23 | public static int getScreenHeight(Context context) {
24 | DisplayMetrics dm = new DisplayMetrics();
25 | ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
26 | return dm.heightPixels;
27 | }
28 |
29 | public static int getScreenHeightWithDecorations(Context context) {
30 | int heightPixels;
31 | WindowManager w = ((Activity) context).getWindowManager();
32 | Display d = w.getDefaultDisplay();
33 | android.graphics.Point realSize = new android.graphics.Point();
34 | try {
35 | Display.class.getMethod("getRealSize", android.graphics.Point.class).invoke(d, realSize);
36 | } catch (IllegalAccessException e) {
37 | e.printStackTrace();
38 | } catch (InvocationTargetException e) {
39 | e.printStackTrace();
40 | } catch (NoSuchMethodException e) {
41 | e.printStackTrace();
42 | }
43 | heightPixels = realSize.y;
44 | return heightPixels;
45 | }
46 |
47 |
48 | public static int dip2px(Context context, float dpValue) {
49 |
50 | final float scale = context.getResources().getDisplayMetrics().density;
51 | return (int) (dpValue * scale + 0.5f);
52 |
53 | }
54 |
55 | public static int px2dip(Context context, float pxValue) {
56 | final float scale = context.getResources().getDisplayMetrics().density;
57 | return (int) (pxValue / scale + 0.5f);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 |
6 | import java.io.File;
7 |
8 | /**
9 | * Created by Aspsine on 2015/3/31.
10 | */
11 | public class FileUtils {
12 |
13 | private static final String HTTP_CACHE_DIR = "http";
14 |
15 | public static final File getHttpCacheDir(Context context) {
16 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
17 | return new File(context.getExternalCacheDir(), HTTP_CACHE_DIR);
18 | }
19 | return new File(context.getCacheDir(), HTTP_CACHE_DIR);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/IntentUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 |
6 | import com.aspsine.zhihu.daily.R;
7 | import com.aspsine.zhihu.daily.model.Story;
8 | import com.aspsine.zhihu.daily.ui.activity.NavigationDrawerActivity;
9 | import com.aspsine.zhihu.daily.ui.activity.StoryActivity;
10 |
11 | /**
12 | * Created by Aspsine on 2015/3/20.
13 | */
14 | public class IntentUtils {
15 | public static final String EXTRA_STORY_ID = "extra_story_id";
16 |
17 | public static final void intentToMainActivity(Activity activity) {
18 | Intent intent = new Intent(activity, NavigationDrawerActivity.class);
19 | activity.startActivity(intent);
20 | activity.finish();
21 | activity.overridePendingTransition(android.support.v7.appcompat.R.anim.abc_fade_in, android.support.v7.appcompat.R.anim.abc_fade_out);
22 | }
23 |
24 | public static final void intentToStoryActivity(Activity activity, Story story) {
25 | Intent intent = new Intent(activity, StoryActivity.class);
26 | intent.putExtra(EXTRA_STORY_ID, String.valueOf(story.getId()));
27 | activity.startActivity(intent);
28 | }
29 |
30 | public static final void share(Activity activity, Story story) {
31 | StringBuilder sb = new StringBuilder();
32 | sb.append(story.getTitle()).append(" ")
33 | .append(activity.getString(R.string.share_link))
34 | .append(story.getShareUrl())
35 | .append(" ")
36 | .append(activity.getString(R.string.share_from));
37 | Intent intent = new Intent(Intent.ACTION_SEND);
38 | intent.setType("text/plain");
39 | intent.putExtra(Intent.EXTRA_TITLE, story.getTitle());
40 | intent.putExtra(Intent.EXTRA_TEXT, sb.toString());
41 | activity.startActivity(intent);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/L.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.util.Log;
4 |
5 | import com.aspsine.zhihu.daily.BuildConfig;
6 |
7 | /**
8 | * Created by aspsine on 15-3-13.
9 | */
10 | public class L{
11 |
12 | public static int i(String tag, String msg){
13 | if (BuildConfig.DEBUG) {
14 | return Log.i(tag, msg);
15 | }
16 | return -1;
17 | }
18 |
19 | public static int e(String tag, String msg){
20 | if (BuildConfig.DEBUG) {
21 | return Log.e(tag, msg);
22 | }
23 | return -1;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/ListUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by aspsine on 15-4-6.
7 | */
8 | public class ListUtils {
9 |
10 | public static final boolean isEmpty(List list) {
11 | if (list != null && list.size() > 0) {
12 | return false;
13 | }
14 | return true;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/NetWorkUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | /**
8 | * Created by Aspsine on 2015/3/13.
9 | */
10 | public class NetWorkUtils {
11 | public static final boolean isNetWorkAvailable(Context context) {
12 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
13 | if (cm != null) {
14 | NetworkInfo[] info = cm.getAllNetworkInfo();
15 | if (info != null) {
16 | for (int i = 0; i < info.length; i++) {
17 | if (info[i].getState() == NetworkInfo.State.CONNECTED) {
18 | return true;
19 | }
20 | }
21 | }
22 | }
23 | return false;
24 | }
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/ScrollPullDownHelper.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 |
4 | import java.util.LinkedList;
5 | import java.util.Queue;
6 |
7 | /**
8 | * Created by aspsine on 15-3-24. thanks chentian.
9 | * Detect several latest moves to ensure a smooth showing-hiding toolbar effect
10 | *
11 | * @author chentian
12 | */
13 | public class ScrollPullDownHelper {
14 |
15 | private static final int PULLING_DOWN_TIME_MAX = 8;
16 | private static final int PULLING_DOWN_TIME_THRESHOLD = 6;
17 |
18 | private int lastScrollY;
19 | private Queue latestPullingDown;
20 |
21 | public ScrollPullDownHelper() {
22 | lastScrollY = 0;
23 | latestPullingDown = new LinkedList<>();
24 | }
25 |
26 | /**
27 | * Call this when scroll changed
28 | *
29 | * @return true if user is pulling down
30 | */
31 | public boolean onScrollChanged(int scrollY) {
32 | boolean isPullingDownNow = scrollY < lastScrollY;
33 | latestPullingDown.offer(isPullingDownNow);
34 | if (latestPullingDown.size() > PULLING_DOWN_TIME_MAX) {
35 | latestPullingDown.poll();
36 | }
37 | lastScrollY = scrollY;
38 |
39 | return getPullingDownTime() >= PULLING_DOWN_TIME_THRESHOLD;
40 | }
41 |
42 | private int getPullingDownTime() {
43 | int result = 0;
44 | for (Boolean isPullingDown : latestPullingDown) {
45 | if (isPullingDown) {
46 | result++;
47 | }
48 | }
49 | return result;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/SharedPrefUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 |
7 | /**
8 | * Created by sf on 2015/1/13.
9 | */
10 | public class SharedPrefUtils {
11 | public static final String TAG = SharedPrefUtils.class.getSimpleName();
12 |
13 | /**
14 | * Boolean indicating whether launch the app first time
15 | */
16 | public static final String SHARED_PREF_IS_FIRST_LAUNCH = "shared_pref_is_first_launch";
17 |
18 | /**
19 | * Boolean indicating whether user learned the drawer
20 | *
21 | * Per the design guidelines, you should show the drawer on launch until the user manually
22 | * expands it. This shared preference tracks this.
23 | */
24 | public static final String SHARED_PREF_IS_USER_LEARNED_DRAWER = "shared_pref_is_user_learned_drawer";
25 |
26 |
27 | public static final String SHARED_PREF_SPLASH_JSON = "shared_pref-splash_json";
28 |
29 | public static SharedPreferences getDefaultSharedPreferences(Context context) {
30 | return PreferenceManager.getDefaultSharedPreferences(context);
31 | }
32 |
33 | /**
34 | * whether launch the app first time
35 | *
36 | * @param context
37 | * @return
38 | */
39 | public static boolean isFirstLaunch(final Context context) {
40 | SharedPreferences sp = getDefaultSharedPreferences(context);
41 | return sp.getBoolean(SHARED_PREF_IS_FIRST_LAUNCH, true);
42 | }
43 |
44 | /**
45 | * mark app launched
46 | *
47 | * @param context
48 | */
49 | public static void markFirstLaunch(final Context context) {
50 | SharedPreferences sp = getDefaultSharedPreferences(context);
51 | sp.edit().putBoolean(SHARED_PREF_IS_FIRST_LAUNCH, false).apply();
52 | }
53 |
54 | public static boolean isUserLearnedDrawer(final Context context) {
55 | SharedPreferences sp = getDefaultSharedPreferences(context);
56 | return sp.getBoolean(SHARED_PREF_IS_USER_LEARNED_DRAWER, false);
57 | }
58 |
59 | public static void markUserLearnedDrawer(Context context) {
60 | SharedPreferences sp = getDefaultSharedPreferences(context);
61 | sp.edit().putBoolean(SHARED_PREF_IS_USER_LEARNED_DRAWER, true).commit();
62 | }
63 |
64 | public static String getSplashJson(Context context){
65 | SharedPreferences sp = getDefaultSharedPreferences(context);
66 | return sp.getString(SHARED_PREF_SPLASH_JSON, null);
67 | }
68 |
69 | public static void setSplashJson(Context context, String jsonString){
70 | SharedPreferences sp = getDefaultSharedPreferences(context);
71 | sp.edit().putString(SHARED_PREF_SPLASH_JSON, jsonString).commit();
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/UIUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.os.Build;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import java.lang.reflect.Method;
12 |
13 | /**
14 | * Created by Aspsine on 2015/2/25.
15 | */
16 | public class UIUtils {
17 | public static void setAccessibilityIgnore(View view) {
18 | view.setClickable(false);
19 | view.setFocusable(false);
20 | view.setContentDescription("");
21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
22 | view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
23 | }
24 | }
25 |
26 | public static final View inflate(int resId, ViewGroup parent) {
27 | return LayoutInflater.from(parent.getContext()).inflate(resId, parent, false);
28 | }
29 |
30 | public static int getStatusBarHeight(Context context) {
31 | Resources resources = context.getResources();
32 | int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
33 | int height = resources.getDimensionPixelSize(resourceId);
34 | return height;
35 | }
36 |
37 | public static int getNavigationBarHeight(Context context) {
38 | Resources resources = context.getResources();
39 | int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
40 | int height = resources.getDimensionPixelSize(resourceId);
41 | return height;
42 | }
43 |
44 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
45 | public static boolean hasNavigationBar(Context activity) {
46 | boolean hasNavigationBar = false;
47 | Resources rs = activity.getResources();
48 | int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
49 | if (id > 0) {
50 | hasNavigationBar = rs.getBoolean(id);
51 | }
52 | try {
53 | Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
54 | Method m = systemPropertiesClass.getMethod("get", String.class);
55 | String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
56 | if ("1".equals(navBarOverride)) {
57 | hasNavigationBar = false;
58 | } else if ("0".equals(navBarOverride)) {
59 | hasNavigationBar = true;
60 | }
61 | } catch (Exception e) {
62 | L.e("UIUtils", e.toString());
63 | }
64 |
65 | return hasNavigationBar;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/zhihu/daily/util/WebUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.zhihu.daily.util;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by aspsine on 15-3-24.
7 | */
8 | public class WebUtils {
9 | public static final String BASE_URL = "file:///android_asset/";
10 | public static final String MIME_TYPE = "text/html";
11 | public static final String ENCODING = "utf-8";
12 | public static final String FAIL_URL = "http//:daily.zhihu.com/";
13 |
14 | private static final String CSS_LINK_PATTERN = " ";
15 | private static final String NIGHT_DIV_TAG_START = "";
16 | private static final String NIGHT_DIV_TAG_END = "
";
17 |
18 | private static final String DIV_IMAGE_PLACE_HOLDER="class=\"img-place-holder\"";
19 | private static final String DIV_IMAGE_PLACE_HOLDER_IGNORED = "class=\"img-place-holder-ignored\"";
20 | public static String BuildHtmlWithCss(String html, List cssUrls, boolean isNightMode) {
21 | StringBuilder result = new StringBuilder();
22 | for (String cssUrl: cssUrls){
23 | result.append(String.format(CSS_LINK_PATTERN,cssUrl));
24 | }
25 |
26 | if(isNightMode){
27 | result.append(NIGHT_DIV_TAG_START);
28 | }
29 | result.append(html.replace(DIV_IMAGE_PLACE_HOLDER, DIV_IMAGE_PLACE_HOLDER_IGNORED));
30 | if (isNightMode){
31 | result.append(NIGHT_DIV_TAG_END);
32 | }
33 |
34 | return result.toString();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
13 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/dark_comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/dark_comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/home_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/home_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/menu_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/splash_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-hdpi/splash_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/dark_comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/dark_comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/home_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/home_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/menu_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/menu_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/splash_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-mdpi/splash_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/dark_comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/dark_comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/home_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/home_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/menu_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/splash_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xhdpi/splash_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/dark_comment_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/dark_comment_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/home_pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/home_pic.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/ic_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/menu_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/menu_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/splash_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxhdpi/splash_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_splash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable/bg_splash.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_mask.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dark_image_small_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable/dark_image_small_default.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/image_small_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/app/src/main/res/drawable/image_small_default.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/mask.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selected_navdrawer_item_background.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_guider.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
18 |
19 |
21 |
25 |
26 |
31 |
33 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_story.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_daily_stories.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_guide.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
16 |
21 |
22 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_navigation.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
26 |
27 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_story.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
17 |
18 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_theme_stories.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_actionbar_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_avatars.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_drawer_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_drawer_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
31 |
32 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_drawer_separator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_header_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
15 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_item_date.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_item_story.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
23 |
24 |
29 |
30 |
37 |
38 |
49 |
50 |
51 |
58 |
59 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_avatars.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_header_story.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
35 |
36 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/global.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_guider.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_story.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v19/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 日报
4 | 设置
5 | 分享
6 | 关闭导航
7 | 打开导航
8 |
9 | 引导
10 | 首页
11 | 设置
12 | 详情页
13 | 艺术家:@littlexi
14 | 今日热文
15 | 选自
16 | -来自日报的分享
17 | 链接:
18 | 推荐人
19 | 主编
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffffff
4 | #ff000000
5 | #00000000
6 |
7 |
8 | #2196F3
9 | #1976D2
10 | #BBDEFB
11 | #FF4081
12 | #ffffffff
13 | #ffffffff
14 | #B6B6B6
15 | #ffffffff
16 |
17 | #000000
18 |
19 |
20 | #12000000
21 |
22 | #ffffffff
23 | @color/black
24 | @color/style_color_primary
25 | #888
26 | @color/style_color_primary
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values/default.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | true
15 | #FFFFFFFF
16 | #00000000
17 | 0
18 | 3dp
19 | false
20 | #FFDDDDDD
21 | 1dp
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 16dp
6 | 16dp
7 | 260dp
8 |
9 | 8dp
10 |
11 | 224dp
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Daily
5 |
6 | Settings
7 | Share
8 |
9 | Guider
10 | Main
11 | StoryActivity
12 |
13 | Open navigation drawer
14 | Close navigation drawer
15 |
16 | Artist: @littlexi
17 |
18 | Today Hottest
19 | Selected from
20 |
21 | Referee
22 | Editor
23 |
24 | link:
25 | -shared from Daily
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings_activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 | Settings
3 |
4 |
5 |
6 |
7 | General
8 |
9 | Enable social recommendations
10 | Recommendations for people to contact
11 | based on your message history
12 |
13 |
14 | Display name
15 | John Smith
16 |
17 | Add friends to messages
18 |
19 | - Always
20 | - When possible
21 | - Never
22 |
23 |
24 | - 1
25 | - 0
26 | - -1
27 |
28 |
29 |
30 | Data & sync
31 |
32 | Sync frequency
33 |
34 | - 15 minutes
35 | - 30 minutes
36 | - 1 hour
37 | - 3 hours
38 | - 6 hours
39 | - Never
40 |
41 |
42 | - 15
43 | - 30
44 | - 60
45 | - 180
46 | - 360
47 | - -1
48 |
49 |
50 | System sync settings
51 |
52 |
53 | Notifications
54 |
55 | New message notifications
56 |
57 | Ringtone
58 | Silent
59 |
60 | Vibrate
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
21 |
25 |
26 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_data_sync.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_general.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
20 |
21 |
23 |
24 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_headers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_notification.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/art/daily.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/daily.apk
--------------------------------------------------------------------------------
/art/detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/detail.png
--------------------------------------------------------------------------------
/art/drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/drawer.png
--------------------------------------------------------------------------------
/art/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/main.png
--------------------------------------------------------------------------------
/art/section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/section.png
--------------------------------------------------------------------------------
/art/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/art/splash.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/Daily/94a470bc37aa0a6b5663a7f5f473c99de3d0d73e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------