diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afbdab3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..7aed292 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +CNBlog \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..736c7b5 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..59436c9 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..59a60d1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..def6a6a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CNBlog.iml b/CNBlog.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/CNBlog.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..c0d80d5 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..454708c --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.yjx.cnblog" + minSdkVersion 15 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.1.0' + compile 'com.android.support:recyclerview-v7:22.1.0' + compile 'com.android.support:cardview-v7:22.1.0' + compile 'com.squareup.picasso:picasso:2.3.2' + compile 'eu.the4thfloor.volley:com.android.volley:2015.01.06' + compile 'com.jakewharton:butterknife:6.1.0' + compile 'com.snappydb:snappydb-lib:0.5.0' + compile 'com.esotericsoftware.kryo:kryo:2.24.0' + compile 'com.github.liuguangqiang.swipeback:library:0.3.0@aar' + compile files('libs/eventbus-2.4.0.jar') + compile 'com.orhanobut:logger:1.8' + compile 'pl.tajchert:waitingdots:0.1.0' + compile files('libs/jsoup-1.8.2.jar') + compile files('libs/fastjson-1.1.33.jar') + compile 'com.github.d-max:spots-dialog:0.2@aar' +} diff --git a/app/libs/eventbus-2.4.0.jar b/app/libs/eventbus-2.4.0.jar new file mode 100644 index 0000000..fd5ae26 Binary files /dev/null and b/app/libs/eventbus-2.4.0.jar differ diff --git a/app/libs/fastjson-1.1.33.jar b/app/libs/fastjson-1.1.33.jar new file mode 100644 index 0000000..4a20f4e Binary files /dev/null and b/app/libs/fastjson-1.1.33.jar differ diff --git a/app/libs/jsoup-1.8.2.jar b/app/libs/jsoup-1.8.2.jar new file mode 100644 index 0000000..74ea084 Binary files /dev/null and b/app/libs/jsoup-1.8.2.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..cba2b3e --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Soft/android-sdk-macosx/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/yjx/cnblog/ApplicationTest.java b/app/src/androidTest/java/com/yjx/cnblog/ApplicationTest.java new file mode 100644 index 0000000..81ea87b --- /dev/null +++ b/app/src/androidTest/java/com/yjx/cnblog/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.yjx.cnblog; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4513959 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/content.html b/app/src/main/assets/content.html new file mode 100755 index 0000000..3468ac5 --- /dev/null +++ b/app/src/main/assets/content.html @@ -0,0 +1,14 @@ + + + CNBLOG + + + + + +
+ {html} +
+ + \ No newline at end of file diff --git a/app/src/main/assets/font.css b/app/src/main/assets/font.css new file mode 100755 index 0000000..0e37956 --- /dev/null +++ b/app/src/main/assets/font.css @@ -0,0 +1,4 @@ + +#content{ line-height:2.0; font-size:14pt;} +pre{font-size:8pt;} + diff --git a/app/src/main/assets/style.css b/app/src/main/assets/style.css new file mode 100755 index 0000000..b40ab22 --- /dev/null +++ b/app/src/main/assets/style.css @@ -0,0 +1,10 @@ +body{font-family:Helvetica,"Microsoft Yahei",Verdana,Helvetica,SimSun,Arial,"Arial Unicode MS",MingLiu,PMingLiu,"MS Gothic",sans-serief;margin:0;padding:0 8px;background-color:#efeff0;color:#333;word-wrap:break-word;} +p{margin-top:0;margin-bottom:5pt;line-height: 1.6em;} +img{max-width:90%;height:auto;} +div.bimg{text-align:center;padding:0;} +audio{width:100%} +*{-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */ + /*-webkit-text-size-adjust: none;*/ /* prevent webkit from resizing text to fit */ + -webkit-tap-highlight-color: rgba(0,0,0,0.15); /* make transparent link selection, adjust last value opacity 0 to 1.0 */ + /*-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */ +} diff --git a/app/src/main/java/com/yjx/cnblog/CNBlogApplication.java b/app/src/main/java/com/yjx/cnblog/CNBlogApplication.java new file mode 100644 index 0000000..633915d --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/CNBlogApplication.java @@ -0,0 +1,28 @@ +package com.yjx.cnblog;/** + * Created by yjx on 15/4/28. + */ + +import android.app.Application; + +import com.orhanobut.logger.LogLevel; +import com.orhanobut.logger.Logger; + + +/** + * User: YJX + * Date: 2015-04-28 + * Time: 22:54 + */ +public class CNBlogApplication extends Application { + + @Override + public void onCreate() { + super.onCreate(); + //初始化日志 + Logger + .init(Constant.LOGTAG) + .setMethodCount(3) + .hideThreadInfo() + .setLogLevel(LogLevel.NONE); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/Constant.java b/app/src/main/java/com/yjx/cnblog/Constant.java new file mode 100644 index 0000000..227ead0 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/Constant.java @@ -0,0 +1,28 @@ +package com.yjx.cnblog; + +/** + * User: YJX + * Date: 2015-04-28 + * Time: 22:55 + * 常量 + */ +public class Constant { + public static final String URL="http://wcf.open.cnblogs.com/blog/";//网络请求接口 + public static final String NEWSURL="http://wcf.open.cnblogs.com/news/";//新闻接口 + + //博客详情请求 + public static final String BLOGDETAILURL="http://cnblogs.davismy.com/Handler.ashx?op=GetBlogContent&blog_id="; + + //新闻详情 + public static final String NEWSURLDETAIL="http://cnblogs.davismy.com/Handler.ashx?op=GetNewContent&news_id="; + + public static final String SEARCHUSER="http://cnblogs.davismy.com/Handler.ashx?op=AuthorSearch&key=";//搜索作者 + + + + public static final String PUBLICKEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB";//博客园登录公钥 + + public static final int PAFESIZE=10;//默认每页请求的个数 + public static final String LOGTAG="CNBLOG";//日志TAG + public static final String DBNAME="cnblog_db";//数据库名称 +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/AboutActivity.java b/app/src/main/java/com/yjx/cnblog/activity/AboutActivity.java new file mode 100644 index 0000000..78857ce --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/AboutActivity.java @@ -0,0 +1,81 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/4. + */ + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.LinearLayout; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; + +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-04 + * Time: 20:24 + * 关于页面 + */ +public class AboutActivity extends BaseActivity { + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + @InjectView(value = R.id.ll) + LinearLayout ll; + int screenWidht, screenHeight; + + @Override + protected void initData() { + super.initData(); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("关于"); + WindowManager manager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(metrics); + screenWidht = metrics.widthPixels; + screenHeight = metrics.heightPixels; + } + + @Override + public int getLayoutId() { + return R.layout.activity_about; + } + + @Override + public void onClick(View v) { + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + ll.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + return true; + } + + @Override + public void onBackPressed() { + ll.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/AuthorActivity.java b/app/src/main/java/com/yjx/cnblog/activity/AuthorActivity.java new file mode 100644 index 0000000..baf706c --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/AuthorActivity.java @@ -0,0 +1,222 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/3. + */ + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.AlertDialog; +import android.content.Intent; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.text.util.Linkify; +import android.util.DisplayMetrics; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.squareup.picasso.Picasso; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.adapter.AuthorBlogAdapter; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.bean.AuthorBean; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.net.XMLRequest; +import com.yjx.cnblog.utils.XMLUtils; +import com.yjx.cnblog.view.CustomListView; +import com.yjx.cnblog.view.SwipeLoadRefreshLayout; + +import org.xmlpull.v1.XmlPullParser; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.InjectView; +import dmax.dialog.SpotsDialog; + +/** + * User: YJX + * Date: 2015-05-03 + * Time: 00:31 + */ +public class AuthorActivity extends BaseActivity { + @InjectView(value = R.id.iv_header) + ImageView iv_header; + @InjectView(value = R.id.tv_name) + TextView tv_name; + @InjectView(value = R.id.tv_suibi) + TextView tv_suibi; + @InjectView(value = R.id.tv_address) + TextView tv_address; + @InjectView(value = R.id.lv_blogs) + CustomListView lv_blogs; + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + AuthorBean info; + AlertDialog dialog; + int page = 1; + + List infos; + + AuthorBlogAdapter adapter; + @InjectView(value = R.id.sl) + SwipeLoadRefreshLayout sl; + int screenHeight; + + @Override + protected void initData() { + super.initData(); + info = (AuthorBean) getIntent().getSerializableExtra("INFO"); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle(info.getName()); + tv_address.setText("http://www.cnblogs.com/" + info.getBlogapp()); + tv_address.setAutoLinkMask(Linkify.ALL); + tv_name.setText(info.getName()); + if (!TextUtils.isEmpty(info.getAvatar())) { + Picasso.with(ctx).load(info.getAvatar()).error(R.drawable.ic_launcher).into(iv_header); + } else { + iv_header.setImageResource(R.drawable.ic_launcher); + } + tv_suibi.setText("随笔: " + info.getPostcount()); + dialog = new SpotsDialog(ctx, R.style.Custom); + infos = new ArrayList(); + adapter = new AuthorBlogAdapter(infos, ctx); + lv_blogs.setAdapter(adapter); + + WindowManager manager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(metrics); + screenHeight = metrics.heightPixels; + + dialog.show(); + getBlogs(); + + } + + @Override + protected void setListener() { + super.setListener(); + sl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + page = 1; + getBlogs(); + } + }); + sl.setOnLoadListener(new SwipeLoadRefreshLayout.OnLoadListener() { + @Override + public void onLoad() { + page++; + getBlogs(); + } + }); + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + return true; + } + }); + lv_blogs.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(ctx, BlogDetailActivity.class); + intent.putExtra("INFO", infos.get(position)); + ActivityCompat.startActivity(AuthorActivity.this, intent, optionsCompat.toBundle()); + } + }); + } + + @Override + public void onBackPressed() { + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + + } + + @Override + public int getLayoutId() { + return R.layout.activity_author; + } + + @Override + public void onClick(View v) { + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("getblogs"); + dialog.cancel(); + } + + /** + * 得到指定用户的博客 + */ + private void getBlogs() { + //u/{BLOGAPP}/posts/{PAGEINDEX}/{PAGESIZE} + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.URL + "u/" + info.getBlogapp() + "/posts/" + page + "/" + Constant.PAFESIZE, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + dialog.dismiss(); + Toast.makeText(ctx, "数据获取失败", Toast.LENGTH_SHORT).show(); + page--; + if (page < 1) { + page = 1; + } + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + dialog.dismiss(); + if (page == 1) { + infos.clear(); + infos.addAll(XMLUtils.getInfos(response)); + adapter.notifyDataSetChanged(); + sl.setRefreshing(false); + } else { + infos.addAll(XMLUtils.getInfos(response)); + adapter.notifyDataSetChanged(); + sl.setLoading(false); + } + + + } + }); + request.setTag("getblogs"); + client.addTask(request); + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/BlogDetailActivity.java b/app/src/main/java/com/yjx/cnblog/activity/BlogDetailActivity.java new file mode 100644 index 0000000..60735b0 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/BlogDetailActivity.java @@ -0,0 +1,292 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/2. + */ + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.StringRequest; +import com.snappydb.DB; +import com.snappydb.DBFactory; +import com.snappydb.SnappydbException; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.utils.HTMLUtils; +import com.yjx.cnblog.utils.NetUtils; +import com.yjx.cnblog.utils.StringUtils; +import com.yjx.cnblog.utils.TimeUtils; +import com.yjx.cnblog.view.CustomScrollView; + +import org.json.JSONObject; + +import butterknife.InjectView; +import dmax.dialog.SpotsDialog; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 01:53 + * 博客详情页面 + */ +public class BlogDetailActivity extends BaseActivity { + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + @InjectView(value = R.id.wv_blogdetail) + WebView wv_blogdetail; + @InjectView(value = R.id.sl) + CustomScrollView sl; + @InjectView(value = R.id.tv_author) + TextView tv_author; + @InjectView(value = R.id.tv_title) + TextView tv_title; + @InjectView(value = R.id.ll_bottommenu) + LinearLayout ll_bottommenu; + int screenWidht, screenHeight; + int bottomheight; + final int MAX_DIS = 15; + boolean isshow = true; + + InfoBean info;//博客基础信息 + AlertDialog dialog; + DB snappydb; + + @Override + public int getLayoutId() { + return R.layout.activity_blogdetail; + } + + @Override + protected void initData() { + super.initData(); + info = (InfoBean) getIntent().getSerializableExtra("INFO"); + tv_author.setText(info.getAuthor().getName() + " 发表于" + TimeUtils.parseTime(info.getPublishedtime())); + tv_title.setText(info.getTitle()); + initToolbar(); + this.wv_blogdetail.getSettings().setDefaultTextEncodingName("utf-8"); + WebSettings localWebSettings = this.wv_blogdetail.getSettings(); + localWebSettings.setJavaScriptEnabled(true); + localWebSettings.setDefaultFontSize(10); + localWebSettings.setCacheMode(-1); + WindowManager manager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(metrics); + screenWidht = metrics.widthPixels; + screenHeight = metrics.heightPixels; + ll_bottommenu.post(new Runnable() { + @Override + public void run() { + bottomheight = ll_bottommenu.getMeasuredHeight(); + } + }); + try { + snappydb = DBFactory.open(ctx, "books"); + } catch (SnappydbException e) { + e.printStackTrace(); + } + dialog = new SpotsDialog(this, R.style.Custom); + if (NetUtils.isNet(ctx)) { + dialog.setTitle("数据加载中..."); + dialog.show(); + getBlogDetail(); + } else { + try { + wv_blogdetail.loadDataWithBaseURL("file:///android_asset/", snappydb.get(info.getId()), "text/html", "utf-8", null); + } catch (SnappydbException e) { + e.printStackTrace(); + } + + } + + + } + + @Override + protected void setListener() { + super.setListener(); + sl.setOnCusScrollChanged(new CustomScrollView.onCusScrollChanged() { + @Override + public void onCusScrollChanged(int l, int t, int oldl, int oldt) { + if (t - oldt > MAX_DIS && isshow) { + isshow = false; + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + } + if (t - oldt < -MAX_DIS && !isshow) { + isshow = true; + ll_bottommenu.animate().translationY(0).setDuration(200).start(); + } + } + }); + wv_blogdetail.setWebChromeClient(new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + if (newProgress == 100) { + dialog.cancel(); + } + } + }); +// wv_blogdetail.addJavascriptInterface(new JavaScriptInterface()); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + return true; + } + + @Override + public void onBackPressed() { + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + + } + + @Override + public void onClick(View v) { + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("getblogdetail"); + dialog.cancel(); + if (snappydb != null) { + try { + snappydb.close(); + } catch (SnappydbException e) { + e.printStackTrace(); + } + } + } + + /** + * 初始化Toolbar + */ + private void initToolbar() { + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("博客正文"); + } + + /** + * 获取博客详情 + */ + private void getBlogDetail() { + StringRequest request = new StringRequest(Request.Method.GET, Constant.BLOGDETAILURL + info.getId(), new Response.Listener() { + @Override + public void onResponse(String response) { + try { + JSONObject object = new JSONObject(response); + if (object.has("data")) { + String main = StringUtils.readIn(getAssets().open("content.html")); + String content = object.getString("data"); +// content=content.replaceAll("\n",""); + content = content.replace("
", "\n").replace("
", "\n").replace("  ", + "\t").replace(" ", " ").replace("'", "\\").replace(""", "\\"). + replace(">", ">"). + replace("<", "<").replace("&", "&"); + content = content.replace("background-color: #F5F5F5;", "background-color: #4e4e4e;").replace("color: #000000;", "color: #8590A2;").replace("color: #0000ff;", "color: #1799ff;").replace("color: #008000;", "color: #00b200;").replace("color: #800000;", "color: #ca0000;"); +// content=HTMLUtils.replaceFont(content); + if (NetUtils.isWifi(ctx)) { + content = main.replace("{html}", content); + wv_blogdetail.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf-8", null); + snappydb.del(info.getId()); + snappydb.put(info.getId(), content); + } else { + content = HTMLUtils.replaceImgTag(content); + content = main.replace("{html}", content); + wv_blogdetail.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf-8", null); + snappydb.del(info.getId()); + snappydb.put(info.getId(), content); + } + + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + dialog.dismiss(); + Toast.makeText(ctx, "请求数据失败", Toast.LENGTH_SHORT).show(); + } + }); + + request.setTag("getblogdetail"); + client.addTask(request); + } + + public class JavaScriptInterface + { + Context mContext; + String url; + + public JavaScriptInterface(String url, Context paramContext) + { + this.mContext = paramContext; + this.url=url; + } + + public void openURL() + { + Intent localIntent = new Intent(); + localIntent.setAction("android.intent.action.VIEW"); + localIntent.setData(Uri.parse(this.url)); + mContext.startActivity(localIntent); + } + + public void showImg() + { + Intent localIntent = new Intent(); +// localIntent.setClass(this.mContext, ImageShowActivity.class); + localIntent.putExtra("imageurl", url); + this.mContext.startActivity(localIntent); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/MainActivity.java b/app/src/main/java/com/yjx/cnblog/activity/MainActivity.java new file mode 100644 index 0000000..feae3d3 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/MainActivity.java @@ -0,0 +1,220 @@ +package com.yjx.cnblog.activity; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.fragment.ExploreFragment; +import com.yjx.cnblog.fragment.HomeFragment; +import com.yjx.cnblog.utils.APPUtils; + +import butterknife.InjectView; +import de.greenrobot.event.EventBus; + +/** + * User: YJX + * Date: 2015-04-28 + * Time: 23:15 + * 主体页面 + */ +public class MainActivity extends BaseActivity { + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + @InjectView(value = R.id.drawerlayout) + DrawerLayout drawerlayout; + @InjectView(value = R.id.tv_version) + TextView tv_version; + @InjectView(value = R.id.rl_menu) + RelativeLayout rl_menu; + + @InjectView(value = R.id.tv_home) + TextView tv_home; + @InjectView(value = R.id.tv_blog) + TextView tv_blog; + @InjectView(value = R.id.tv_news) + TextView tv_news; + @InjectView(value = R.id.tv_explore) + TextView tv_explore; + @InjectView(value = R.id.tv_collect) + TextView tv_collect; + + @InjectView(value = R.id.tv_setting) + TextView tv_setting; + + ActionBarDrawerToggle actionBarDrawerToggle; + HomeFragment blogFragment; + Fragment curfragment; + ExploreFragment exploreFragment; + int state=0; + + + @Override + public int getLayoutId() { + return R.layout.activity_main; + } + + @Override + protected void initData() { + super.initData(); + initToolbar(); + tv_version.setText("版本 " + APPUtils.getVersionName(ctx, getPackageName())); + blogFragment = new HomeFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable("INFO", getIntent().getSerializableExtra("INFO")); + blogFragment.setArguments(bundle); + curfragment = blogFragment; + jumpFrm(null, blogFragment, R.id.frm_content, "首页"); + } + + @Override + protected void setListener() { + super.setListener(); + tv_blog.setOnClickListener(this); + tv_collect.setOnClickListener(this); + tv_explore.setOnClickListener(this); + tv_home.setOnClickListener(this); + tv_news.setOnClickListener(this); + tv_setting.setOnClickListener(this); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.ab_search) { + jumpAct(SearchActivity.class, false); + } + return true; + } + + @Override + public void onBackPressed() { + if (drawerlayout.isDrawerOpen(rl_menu)) { + drawerlayout.closeDrawer(rl_menu); + } else { + super.onBackPressed(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_home: + if (tv_news.getVisibility() == View.GONE) { + tv_news.setVisibility(View.VISIBLE); + tv_blog.setVisibility(View.VISIBLE); + } else { + tv_news.setVisibility(View.GONE); + tv_blog.setVisibility(View.GONE); + } + break; + case R.id.tv_blog: + //博客页面 + if (blogFragment == null) { + blogFragment = new HomeFragment(); + } + if (curfragment instanceof HomeFragment) { + + } else { + jumpFrm(curfragment, blogFragment, R.id.frm_content, "首页"); + } + curfragment = blogFragment; + state=1; + drawerlayout.closeDrawer(rl_menu); + EventBus.getDefault().post("true"); + getSupportActionBar().setTitle(R.string.home); + break; + case R.id.tv_news: + //新闻页面 + if (blogFragment == null) { + blogFragment = new HomeFragment(); + } + if (curfragment instanceof HomeFragment) { + + } else { + jumpFrm(curfragment, blogFragment, R.id.frm_content, "首页"); + } + curfragment = blogFragment; + state=2; + drawerlayout.closeDrawer(rl_menu); + EventBus.getDefault().post("false"); + getSupportActionBar().setTitle(R.string.news); + break; + case R.id.tv_explore: + //发现 + state=3; + drawerlayout.closeDrawer(rl_menu); + if (exploreFragment == null) { + exploreFragment = new ExploreFragment(); + } + if (curfragment instanceof ExploreFragment) { + + } else { + jumpFrm(curfragment, exploreFragment, R.id.frm_content, "发现"); + } + curfragment = exploreFragment; + getSupportActionBar().setTitle(R.string.explore); + break; + case R.id.tv_collect: + drawerlayout.closeDrawer(rl_menu); + //收藏页面 + break; + case R.id.tv_setting: + //设置页面 + drawerlayout.closeDrawer(rl_menu); + jumpAct(SettingActivity.class,false); + break; + + } + } + + /** + * 初始化Toolbar + */ + private void initToolbar() { + setSupportActionBar(toolbar); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerlayout, toolbar, R.string.app_name, R.string.home) { + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + getSupportActionBar().setTitle(R.string.app_name); + } + + @Override + public void onDrawerClosed(View drawerView) { + super.onDrawerClosed(drawerView); + switch (state){ + case 1: getSupportActionBar().setTitle(R.string.home); + break; + case 2: getSupportActionBar().setTitle(R.string.news); + break; + case 3: + getSupportActionBar().setTitle(R.string.explore); + break; + } + tv_blog.setVisibility(View.GONE); + tv_news.setVisibility(View.GONE); + } + }; + actionBarDrawerToggle.syncState(); + drawerlayout.setDrawerListener(actionBarDrawerToggle); + getSupportActionBar().setTitle(R.string.home); + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/NewsDetailActivity.java b/app/src/main/java/com/yjx/cnblog/activity/NewsDetailActivity.java new file mode 100644 index 0000000..5aa483e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/NewsDetailActivity.java @@ -0,0 +1,240 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/2. + */ + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.StringRequest; +import com.snappydb.DB; +import com.snappydb.DBFactory; +import com.snappydb.SnappydbException; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.utils.HTMLUtils; +import com.yjx.cnblog.utils.NetUtils; +import com.yjx.cnblog.utils.StringUtils; +import com.yjx.cnblog.utils.TimeUtils; +import com.yjx.cnblog.view.CustomScrollView; + +import org.json.JSONObject; + +import butterknife.InjectView; +import dmax.dialog.SpotsDialog; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 21:31 + */ +public class NewsDetailActivity extends BaseActivity { + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + @InjectView(value = R.id.wv_blogdetail) + WebView wv_blogdetail; + @InjectView(value = R.id.sl) + CustomScrollView sl; + @InjectView(value = R.id.tv_author) + TextView tv_author; + @InjectView(value = R.id.tv_title) + TextView tv_title; + @InjectView(value = R.id.ll_bottommenu) + LinearLayout ll_bottommenu; + int screenWidht, screenHeight; + int bottomheight; + final int MAX_DIS = 15; + boolean isshow = true; + + InfoBean info;//新闻基础信息 + AlertDialog dialog; + DB snappydb; + @Override + public int getLayoutId() { + return R.layout.activity_newsdetail; + } + + @Override + protected void initData() { + super.initData(); + info = (InfoBean) getIntent().getSerializableExtra("INFO"); + tv_author.setText(info.getSourceName() + " 发表于" + TimeUtils.parseTime(info.getPublishedtime())); + tv_title.setText(info.getTitle()); + initToolbar(); + this.wv_blogdetail.getSettings().setDefaultTextEncodingName("utf-8"); + WebSettings localWebSettings = this.wv_blogdetail.getSettings(); + localWebSettings.setJavaScriptEnabled(true); + localWebSettings.setDefaultFontSize(10); + localWebSettings.setCacheMode(-1); + WindowManager manager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(metrics); + screenWidht = metrics.widthPixels; + screenHeight = metrics.heightPixels; + ll_bottommenu.post(new Runnable() { + @Override + public void run() { + bottomheight = ll_bottommenu.getMeasuredHeight(); + } + }); + try { + snappydb = DBFactory.open(ctx, "books"); + } catch (SnappydbException e) { + e.printStackTrace(); + } + if (NetUtils.isNet(ctx)) { + dialog = new SpotsDialog(this, R.style.Custom); + dialog.setTitle("数据加载中..."); + dialog.show(); + getNewsDetail(); + }else{ + try { + wv_blogdetail.loadDataWithBaseURL("file:///android_asset/", snappydb.get(info.getId()), "text/html", "utf-8", null); + } catch (SnappydbException e) { + e.printStackTrace(); + } + } + } + + @Override + protected void setListener() { + super.setListener(); sl.setOnCusScrollChanged(new CustomScrollView.onCusScrollChanged() { + @Override + public void onCusScrollChanged(int l, int t, int oldl, int oldt) { + if (t - oldt > MAX_DIS && isshow) { + isshow = false; + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + } + if (t - oldt < -MAX_DIS && !isshow) { + isshow = true; + ll_bottommenu.animate().translationY(0).setDuration(200).start(); + } + } + }); + wv_blogdetail.setWebChromeClient(new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + if (newProgress == 100) { + dialog.cancel(); + } + } + }); + } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + return true; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("getnewsdetail"); + dialog.cancel(); + if (snappydb != null) { + try { + snappydb.close(); + } catch (SnappydbException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onBackPressed() { + ll_bottommenu.animate().translationY(bottomheight).setDuration(200).start(); + sl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + + } + + /** + * 得到新闻详情 + */ + private void getNewsDetail() { + StringRequest request = new StringRequest(Request.Method.GET, Constant.NEWSURLDETAIL + info.getId(), new Response.Listener() { + @Override + public void onResponse(String response) { + try { + JSONObject object = new JSONObject(response); + if (object.has("data")) { + String main= StringUtils.readIn(getAssets().open("content.html")); + String content = object.getString("data"); +// content = content.replace("
", "\n").replace("
", "\n").replace("  ", "\t").replace(" ", " ").replace("'", "\\").replace(""", "\\").replace(">", ">").replace("<", "<").replace("&", "&"); + content = content.replace("background-color: #F5F5F5;", "background-color: #4e4e4e;").replace("color: #000000;", "color: #8590A2;").replace("color: #0000ff;", "color: #1799ff;").replace("color: #008000;", "color: #00b200;").replace("color: #800000;", "color: #ca0000;"); + content= HTMLUtils.replaceFont(content); + content=main.replace("{html}", content); + wv_blogdetail.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf-8", null); + snappydb.del(info.getId()); + snappydb.put(info.getId(), content); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + dialog.dismiss(); + Toast.makeText(ctx, "请求数据失败", Toast.LENGTH_SHORT).show(); + + } + }); + + request.setTag("getnewsdetail"); + client.addTask(request); + } + + @Override + public void onClick(View v) { + + } + /** + * 初始化Toolbar + */ + private void initToolbar() { + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("新闻正文"); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/SearchActivity.java b/app/src/main/java/com/yjx/cnblog/activity/SearchActivity.java new file mode 100644 index 0000000..38dbf1e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/SearchActivity.java @@ -0,0 +1,171 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/2. + */ + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.AlertDialog; +import android.content.Intent; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.WindowManager; +import android.widget.SearchView; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.adapter.AuthorAdapter; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.bean.AuthorBean; +import com.yjx.cnblog.bean.AuthorsBean; +import com.yjx.cnblog.listener.onAdapterTouch; +import com.yjx.cnblog.net.JSONRequest; +import com.yjx.cnblog.utils.APPUtils; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.InjectView; +import dmax.dialog.SpotsDialog; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 23:23 + * 搜索页面 + */ +public class SearchActivity extends BaseActivity { + @InjectView(value = R.id.rv_author) + RecyclerView rv_author; + @InjectView(value = R.id.search_view) + SearchView search_view; + AuthorAdapter adapter; + List authors; + int screenHeight; + AlertDialog dialog; + + @Override + public int getLayoutId() { + return R.layout.activity_search; + } + + + @Override + protected void initData() { + super.initData(); + + WindowManager windowManager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + screenHeight = metrics.heightPixels; + + authors = new ArrayList(); + adapter = new AuthorAdapter(ctx, authors); + RecyclerView.LayoutManager manager = new LinearLayoutManager(ctx, LinearLayoutManager.VERTICAL, false); + rv_author.setLayoutManager(manager); + rv_author.setHasFixedSize(true); + rv_author.setItemAnimator(new DefaultItemAnimator()); + rv_author.setAdapter(adapter); + dialog = new SpotsDialog(ctx, R.style.Search); + } + + @Override + protected void setListener() { + super.setListener(); + search_view.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + if (!TextUtils.isEmpty(query)) { + APPUtils.hideSoftInput(ctx, SearchActivity.this); + dialog.show(); + search(query); + + } else + Toast.makeText(ctx, "请输入关键字", Toast.LENGTH_SHORT).show(); + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + return false; + } + }); + adapter.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(ctx, AuthorActivity.class); + intent.putExtra("INFO", authors.get(pos)); + ActivityCompat.startActivity(SearchActivity.this, intent, optionsCompat.toBundle()); + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + } + + @Override + public void onClick(View v) { + + } + + @Override + public void onBackPressed() { + rv_author.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("search"); + dialog.cancel(); + } + + private void search(String keys) { + JSONRequest request = new JSONRequest(Request.Method.GET, Constant.SEARCHUSER + keys, AuthorsBean.class, new Response.Listener() { + @Override + public void onResponse(AuthorsBean response) { + dialog.dismiss(); + if (response.getData() != null) { + + authors.clear(); + authors.addAll(response.getData()); + adapter.notifyDataSetChanged(); + } else { + Toast.makeText(ctx, "没有该用户请重新输入!!", Toast.LENGTH_SHORT).show(); + } + + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Toast.makeText(ctx, "搜索失败", Toast.LENGTH_SHORT).show(); + } + }); + request.setTag("search"); + client.addTask(request); + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/SettingActivity.java b/app/src/main/java/com/yjx/cnblog/activity/SettingActivity.java new file mode 100644 index 0000000..ccfa9f7 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/SettingActivity.java @@ -0,0 +1,88 @@ +package com.yjx.cnblog.activity; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.fragment.SetttingFragment; + +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-03 + * Time: 20:16 + * 设置页面 + */ +public class SettingActivity extends BaseActivity { + @InjectView(value = R.id.toolbar) + Toolbar toolbar; + @InjectView(value = R.id.fl) + FrameLayout fl; + int screenWidht, screenHeight; + + @Override + public int getLayoutId() { + return R.layout.activity_setting; + } + + @Override + protected void initData() { + super.initData(); + setSupportActionBar(toolbar); + getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("设置"); + getFragmentManager().beginTransaction().replace(R.id.fl,new SetttingFragment(),"设置").commit(); + WindowManager manager = getWindowManager(); + DisplayMetrics metrics = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(metrics); + screenWidht = metrics.widthPixels; + screenHeight = metrics.heightPixels; + } + + @Override + protected void setListener() { + super.setListener(); + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId()==android.R.id.home){ + fl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + return true; + } + }); + } + + @Override + public void onBackPressed() { + fl.animate().translationY(screenHeight).setDuration(500).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + finish(); + overridePendingTransition(0, 0); + } + }).start(); + } + + @Override + public void onClick(View v) { + + } +} diff --git a/app/src/main/java/com/yjx/cnblog/activity/SplashActivity.java b/app/src/main/java/com/yjx/cnblog/activity/SplashActivity.java new file mode 100644 index 0000000..8882b94 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/activity/SplashActivity.java @@ -0,0 +1,87 @@ +package com.yjx.cnblog.activity;/** + * Created by yjx on 15/5/1. + */ + +import android.content.Intent; +import android.os.Handler; +import android.view.View; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.orhanobut.logger.Logger; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.BaseActivity; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.net.XMLRequest; +import com.yjx.cnblog.utils.XMLUtils; + +import org.xmlpull.v1.XmlPullParser; + +import java.io.Serializable; +import java.util.List; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:44 + * 欢迎页 + */ +public class SplashActivity extends BaseActivity { + private Handler handler; + @Override + public int getLayoutId() { + return R.layout.activity_splash; + } + + @Override + protected void initData() { + super.initData(); + handler=new Handler(); + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.URL + "sitehome/paged/1/" + Constant.PAFESIZE, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Logger.e("请求失败"); + handler.postDelayed(new Runnable() { + @Override + public void run() { + jumpAct(MainActivity.class, true); + } + },1500); + + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + final List infos = XMLUtils.getInfos(response); + handler.postDelayed(new Runnable() { + @Override + public void run() { + Intent intent = new Intent(ctx, MainActivity.class); + intent.putExtra("INFO",(Serializable)infos); + startActivity(intent); + finish(); + overridePendingTransition(0, 0); + } + },1500); + + + + } + }); + request.setTag("splash"); + client.addTask(request); + } + + @Override + public void onClick(View v) { + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("splash"); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/adapter/AuthorAdapter.java b/app/src/main/java/com/yjx/cnblog/adapter/AuthorAdapter.java new file mode 100644 index 0000000..ee0ef0f --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/adapter/AuthorAdapter.java @@ -0,0 +1,96 @@ +package com.yjx.cnblog.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; +import com.yjx.cnblog.R; +import com.yjx.cnblog.bean.AuthorBean; +import com.yjx.cnblog.listener.onAdapterTouch; + +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 18:34 + * 博客列表适配器 + */ +public class AuthorAdapter extends RecyclerView.Adapter { + private List mLists; + private Context context; + private onAdapterTouch listen; + + public onAdapterTouch getListen() { + return listen; + } + + public void setListen(onAdapterTouch listen) { + this.listen = listen; + } + + public AuthorAdapter(Context context, List mLists) { + this.mLists = mLists; + this.context = context; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_author, parent, false); + ViewHolder holder = new ViewHolder(view); + return holder; + } + + @Override + public void onBindViewHolder(final ViewHolder holder, final int position) { + + holder.tv_time.setText(mLists.get(position).getUpdated()); + holder.tv_name.setText(mLists.get(position).getName()); + if (!TextUtils.isEmpty(mLists.get(position).getAvatar())) + Picasso.with(context).load(mLists.get(position).getAvatar()).error(R.drawable.ic_launcher).into(holder.iv_header); + else + holder.iv_header.setImageResource(R.drawable.ic_launcher); + holder.tv_counts.setText("( " + mLists.get(position).getPostcount() + " ) 博文"); + holder.rl_menu.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listen != null) { + listen.onAdapterClick(holder.rl_menu, position); + } + } + }); + } + + @Override + public int getItemCount() { + return mLists.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @InjectView(value = R.id.iv_header) + ImageView iv_header; + @InjectView(value = R.id.tv_name) + TextView tv_name; + @InjectView(value = R.id.tv_time) + TextView tv_time; + @InjectView(value = R.id.rl_menu) + RelativeLayout rl_menu; + @InjectView(value = R.id.tv_counts) + TextView tv_counts; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.inject(this, itemView); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/adapter/AuthorBlogAdapter.java b/app/src/main/java/com/yjx/cnblog/adapter/AuthorBlogAdapter.java new file mode 100644 index 0000000..c84b86e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/adapter/AuthorBlogAdapter.java @@ -0,0 +1,62 @@ +package com.yjx.cnblog.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.base.MBaseAdapter; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.utils.TimeUtils; + +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 18:34 + * 博客列表适配器 + */ +public class AuthorBlogAdapter extends MBaseAdapter{ + + + public AuthorBlogAdapter(List mLists, Context context) { + super(mLists, context); + } + + @Override + public View getXView(int position, View convertView, ViewGroup parent) { + AuthorBlogAdapter.ViewHolder holder; + if (convertView==null){ + convertView=inflater.inflate(R.layout.item_authorblog, parent, false); + holder=new AuthorBlogAdapter.ViewHolder(convertView); + convertView.setTag(holder); + }else{ + holder= (AuthorBlogAdapter.ViewHolder) convertView.getTag(); + } + holder.tv_title.setText(mLists.get(position).getTitle()); + holder.tv_detail.setText(mLists.get(position).getSummary()); + holder.tv_time.setText(TimeUtils.parseTime(mLists.get(position).getPublishedtime())); + return convertView; + } + + public static class ViewHolder { + @InjectView(value = R.id.tv_title) + TextView tv_title; + @InjectView(value = R.id.tv_detail) + TextView tv_detail; + @InjectView(value = R.id.tv_time) + TextView tv_time; + @InjectView(value = R.id.ll_item) + LinearLayout ll_item; + + public ViewHolder(View itemView) { + ButterKnife.inject(this, itemView); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/adapter/BlogAdapter.java b/app/src/main/java/com/yjx/cnblog/adapter/BlogAdapter.java new file mode 100644 index 0000000..f2a6b8e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/adapter/BlogAdapter.java @@ -0,0 +1,109 @@ +package com.yjx.cnblog.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; +import com.yjx.cnblog.R; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.listener.onAdapterTouch; +import com.yjx.cnblog.utils.TimeUtils; + +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 18:34 + * 博客列表适配器 + */ +public class BlogAdapter extends RecyclerView.Adapter { + private List mLists; + private Context context; + private onAdapterTouch listen; + + public onAdapterTouch getListen() { + return listen; + } + + public void setListen(onAdapterTouch listen) { + this.listen = listen; + } + + public BlogAdapter(Context context, List mLists) { + this.mLists = mLists; + this.context = context; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_blog, parent, false); + ViewHolder holder = new ViewHolder(view); + return holder; + } + + @Override + public void onBindViewHolder(final ViewHolder holder, final int position) { + holder.tv_title.setText(mLists.get(position).getTitle()); + holder.tv_detail.setText(mLists.get(position).getSummary()); + holder.tv_time.setText(TimeUtils.parseTime(mLists.get(position).getPublishedtime())+" 发布"); + holder.tv_name.setText(mLists.get(position).getAuthor().getName()); + if (!TextUtils.isEmpty(mLists.get(position).getAuthor().getAvatar())) + Picasso.with(context).load(mLists.get(position).getAuthor().getAvatar()).error(R.drawable.ic_launcher).into(holder.iv_header); + else + holder.iv_header.setImageResource(R.drawable.ic_launcher); + + holder.ll_item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listen != null) { + listen.onAdapterClick(holder.ll_item, position); + } + } + }); + holder.tv_comments.setText(mLists.get(position).getComments() + "评论"); + holder.tv_read.setText(mLists.get(position).getViews() + "阅读"); + } + + @Override + public int getItemCount() { + return mLists.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @InjectView(value = R.id.iv_header) + ImageView iv_header; + @InjectView(value = R.id.tv_name) + TextView tv_name; + @InjectView(value = R.id.tv_title) + TextView tv_title; + @InjectView(value = R.id.tv_detail) + TextView tv_detail; + @InjectView(value = R.id.tv_time) + TextView tv_time; + @InjectView(value = R.id.ll_item) + LinearLayout ll_item; + + @InjectView(value = R.id.tv_read) + TextView tv_read; + + @InjectView(value = R.id.tv_comments) + TextView tv_comments; + + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.inject(this, itemView); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/adapter/NewsAdapter.java b/app/src/main/java/com/yjx/cnblog/adapter/NewsAdapter.java new file mode 100644 index 0000000..4cd45d4 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/adapter/NewsAdapter.java @@ -0,0 +1,101 @@ +package com.yjx.cnblog.adapter; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.listener.onAdapterTouch; +import com.yjx.cnblog.utils.TimeUtils; + +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 18:34 + * 博客列表适配器 + */ +public class NewsAdapter extends RecyclerView.Adapter { + private List mLists; + private Context context; + private onAdapterTouch listen; + + public onAdapterTouch getListen() { + return listen; + } + + public void setListen(onAdapterTouch listen) { + this.listen = listen; + } + + public NewsAdapter(Context context, List mLists) { + this.mLists = mLists; + this.context = context; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_blog, parent, false); + ViewHolder holder = new ViewHolder(view); + return holder; + } + + @Override + public void onBindViewHolder(final ViewHolder holder, final int position) { + holder.tv_title.setText(mLists.get(position).getTitle()); + holder.tv_detail.setText(mLists.get(position).getSummary()); + holder.tv_time.setText(TimeUtils.parseTime(mLists.get(position).getPublishedtime())+" 发布"); + holder.tv_name.setText(mLists.get(position).getSourceName()); + holder.iv_header.setImageResource(R.drawable.ic_launcher); + holder.ll_item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listen != null) { + listen.onAdapterClick(holder.ll_item, position); + } + } + }); + holder.tv_comments.setText(mLists.get(position).getComments() + "评论"); + holder.tv_read.setText(mLists.get(position).getViews() + "阅读"); + } + + @Override + public int getItemCount() { + return mLists.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + @InjectView(value = R.id.iv_header) + ImageView iv_header; + @InjectView(value = R.id.tv_name) + TextView tv_name; + @InjectView(value = R.id.tv_title) + TextView tv_title; + @InjectView(value = R.id.tv_detail) + TextView tv_detail; + @InjectView(value = R.id.tv_time) + TextView tv_time; + @InjectView(value = R.id.ll_item) + LinearLayout ll_item; + @InjectView(value = R.id.tv_read) + TextView tv_read; + + @InjectView(value = R.id.tv_comments) + TextView tv_comments; + + public ViewHolder(View itemView) { + super(itemView); + ButterKnife.inject(this, itemView); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/adapter/VPAdapter.java b/app/src/main/java/com/yjx/cnblog/adapter/VPAdapter.java new file mode 100644 index 0000000..0f4d0af --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/adapter/VPAdapter.java @@ -0,0 +1,40 @@ +package com.yjx.cnblog.adapter;/** + * Created by yjx on 15/5/2. + */ + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; + +import java.util.List; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 00:19 + */ +public class VPAdapter extends FragmentPagerAdapter { + private String [] items; + private List fragments; + + public VPAdapter(FragmentManager fm, String[] items, List fragments) { + super(fm); + this.items = items; + this.fragments = fragments; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return items[position]; + } +} diff --git a/app/src/main/java/com/yjx/cnblog/base/BaseActivity.java b/app/src/main/java/com/yjx/cnblog/base/BaseActivity.java new file mode 100644 index 0000000..cb828a2 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/base/BaseActivity.java @@ -0,0 +1,104 @@ +package com.yjx.cnblog.base;/** + * Created by yjx on 15/4/28. + */ + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import com.yjx.cnblog.net.AsynHttpClient; + +import butterknife.ButterKnife; + +/** + * User: YJX + * Date: 2015-04-28 + * Time: 23:01 + * 基础activity + */ +public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener { + protected Context ctx; + protected AsynHttpClient client; + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + ctx = this; + client=AsynHttpClient.getInstance(getApplicationContext()); + ButterKnife.inject(this); + initData(); + setListener(); + + } + + /** + * 得到布局文件 + * + * @return + */ + public abstract int getLayoutId(); + + /** + * 初始化数据 + */ + protected void initData() { + + } + + /** + * 设置监听器 + */ + protected void setListener() { + + } + + /** + * activity之间的跳转 + * @param clazz 目标activity + * @param isfinish 是否关闭 + */ + protected void jumpAct(Class clazz, boolean isfinish) { + Intent intent = new Intent(this, clazz); + startActivity(intent); + if (isfinish) { + this.finish(); + } else { + + } + } + + /** + * Fragment之间的切换 + * @param from 当前 + * @param to 目标 + * @param id + * @param tag + */ + protected void jumpFrm(Fragment from,Fragment to,int id,String tag){ + if (to==null){ + return; + } + FragmentManager manager=getSupportFragmentManager(); + FragmentTransaction transaction=manager.beginTransaction(); + if (from==null){ + transaction.add(id,to,tag); + }else{ + transaction.hide(from); + if (to.isAdded()){ + transaction.show(to); + }else{ + transaction.add(id,to,tag); + } + } + transaction.commitAllowingStateLoss(); + } + + + +} diff --git a/app/src/main/java/com/yjx/cnblog/base/BaseFragment.java b/app/src/main/java/com/yjx/cnblog/base/BaseFragment.java new file mode 100644 index 0000000..2c18a35 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/base/BaseFragment.java @@ -0,0 +1,60 @@ +package com.yjx.cnblog.base;/** + * Created by yjx on 15/5/1. + */ + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.yjx.cnblog.net.AsynHttpClient; + +import butterknife.ButterKnife; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:31 + */ +public abstract class BaseFragment extends Fragment implements View.OnClickListener { + protected View rootView; + protected Context frmctx; + protected AsynHttpClient client; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.frmctx = getActivity(); + this.client=AsynHttpClient.getInstance(frmctx.getApplicationContext()); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + rootView = inflater.inflate(getLayoutId(), container, false); + ButterKnife.inject(this,rootView); + initData(); + setListener(); + return rootView; + } + + protected abstract int getLayoutId(); + + /** + * 设置监听器 + */ + protected void setListener(){ + + } + + /** + 初始化数据 + */ + protected void initData(){ + + } + +} diff --git a/app/src/main/java/com/yjx/cnblog/base/MBaseAdapter.java b/app/src/main/java/com/yjx/cnblog/base/MBaseAdapter.java new file mode 100644 index 0000000..3bbef7e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/base/MBaseAdapter.java @@ -0,0 +1,56 @@ +package com.yjx.cnblog.base;/** + * Created by yjx on 15/4/30. + */ + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import java.util.List; + +/** + * User: YJX + * Date: 2015-04-30 + * Time: 20:26 + */ +public abstract class MBaseAdapter extends BaseAdapter { + protected List mLists; + protected Context context; + protected LayoutInflater inflater; + + public MBaseAdapter(List mLists, Context context) { + this.mLists = mLists; + this.context = context; + inflater = LayoutInflater.from(context); + } + + @Override + public int getCount() { + if (mLists != null && mLists.size() > 0) + return mLists.size(); + else + return 0; + } + + @Override + public T getItem(int position) { + if (mLists != null && mLists.size() > 0) + return mLists.get(position); + return null; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return getXView(position, convertView, parent); + } + + public abstract View getXView(int position, View convertView, ViewGroup parent); + +} diff --git a/app/src/main/java/com/yjx/cnblog/bean/AuthorBean.java b/app/src/main/java/com/yjx/cnblog/bean/AuthorBean.java new file mode 100644 index 0000000..c8cec8c --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/bean/AuthorBean.java @@ -0,0 +1,70 @@ +package com.yjx.cnblog.bean;/** + * Created by yjx on 15/5/1. + */ + +import java.io.Serializable; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:42 + * 个人信息 + */ +public class AuthorBean implements Serializable { + private String name; + private String uri; + private String avatar; + private String blogapp; + private String postcount; + private String updated; + + public String getBlogapp() { + return blogapp; + } + + public void setBlogapp(String blogapp) { + this.blogapp = blogapp; + } + + public String getPostcount() { + return postcount; + } + + public void setPostcount(String postcount) { + this.postcount = postcount; + } + + public String getUpdated() { + return updated; + } + + public void setUpdated(String updated) { + this.updated = updated; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/bean/AuthorsBean.java b/app/src/main/java/com/yjx/cnblog/bean/AuthorsBean.java new file mode 100644 index 0000000..2e5b386 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/bean/AuthorsBean.java @@ -0,0 +1,23 @@ +package com.yjx.cnblog.bean;/** + * Created by yjx on 15/5/3. + */ + +import java.util.List; + +/** + * User: YJX + * Date: 2015-05-03 + * Time: 00:05 + */ +public class AuthorsBean { + + private List data; + + public List getData() { + return data; + } + + public void setData(List datas) { + this.data = datas; + } +} diff --git a/app/src/main/java/com/yjx/cnblog/bean/InfoBean.java b/app/src/main/java/com/yjx/cnblog/bean/InfoBean.java new file mode 100644 index 0000000..fde86c5 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/bean/InfoBean.java @@ -0,0 +1,143 @@ +package com.yjx.cnblog.bean;/** + * Created by yjx on 15/5/1. + */ + +import java.io.Serializable; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:38 + * 博客bean + */ +public class InfoBean implements Serializable { + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public String getPublishedtime() { + return publishedtime; + } + + public void setPublishedtime(String publishedtime) { + this.publishedtime = publishedtime; + } + + public String getUpdatedtime() { + return updatedtime; + } + + public void setUpdatedtime(String updatedtime) { + this.updatedtime = updatedtime; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getBlogapp() { + return blogapp; + } + + public void setBlogapp(String blogapp) { + this.blogapp = blogapp; + } + + public int getDiggs() { + return diggs; + } + + public void setDiggs(int diggs) { + this.diggs = diggs; + } + + public int getViews() { + return views; + } + + public void setViews(int views) { + this.views = views; + } + + public int getComments() { + return comments; + } + + public void setComments(int comments) { + this.comments = comments; + } + + public AuthorBean getAuthor() { + return author; + } + + public void setAuthor(AuthorBean author) { + this.author = author; + } + + + private String id; + private String title; + private String summary; + private String publishedtime; + private String updatedtime; + private String url; + private String blogapp; + private int diggs; + private int views; + private int comments; + private AuthorBean author; + private String topic; + private String topicIcon; + private String sourceName; + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getTopicIcon() { + return topicIcon; + } + + public void setTopicIcon(String topicIcon) { + this.topicIcon = topicIcon; + } + + public String getSourceName() { + return sourceName; + } + + public void setSourceName(String sourceName) { + this.sourceName = sourceName; + } +} diff --git a/app/src/main/java/com/yjx/cnblog/bean/NewsBean.java b/app/src/main/java/com/yjx/cnblog/bean/NewsBean.java new file mode 100644 index 0000000..5e654f9 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/bean/NewsBean.java @@ -0,0 +1,15 @@ +package com.yjx.cnblog.bean;/** + * Created by yjx on 15/5/2. + */ + +import java.io.Serializable; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 21:58 + */ +public class NewsBean implements Serializable { + + +} diff --git a/app/src/main/java/com/yjx/cnblog/fragment/ExploreChildFragment.java b/app/src/main/java/com/yjx/cnblog/fragment/ExploreChildFragment.java new file mode 100644 index 0000000..2bbad2e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/fragment/ExploreChildFragment.java @@ -0,0 +1,299 @@ +package com.yjx.cnblog.fragment;/** + * Created by yjx on 15/5/3. + */ + +import android.content.Intent; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.activity.BlogDetailActivity; +import com.yjx.cnblog.activity.NewsDetailActivity; +import com.yjx.cnblog.adapter.BlogAdapter; +import com.yjx.cnblog.adapter.NewsAdapter; +import com.yjx.cnblog.base.BaseFragment; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.listener.onAdapterTouch; +import com.yjx.cnblog.net.XMLRequest; +import com.yjx.cnblog.utils.XMLUtils; +import com.yjx.cnblog.view.SwipeLoadRefreshLayout; + +import org.xmlpull.v1.XmlPullParser; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-03 + * Time: 12:13 + */ +public class ExploreChildFragment extends BaseFragment { + @InjectView(value = R.id.rv_blogs) + RecyclerView rv_blogs; + @InjectView(value = R.id.sl) + SwipeLoadRefreshLayout sl; + int state;// + public static final int READ48 = 1;//48小时阅读 + public static final int HOTBLOG = 2;//热门博客 + public static final int HOTNEWS = 3;//热门新闻 + String read48 = "48HoursTopViewPosts/";//48小时阅读请求地址 + String hotblog = "TenDaysTopDiggPosts/";//推荐博客 + String hotnews = "hot/";//热门新闻地址 + int hotblogpage = 1; + int hotnewspage = 1; + BlogAdapter adapter48; + BlogAdapter hotadapter; + NewsAdapter newsadapter; + + List info48s, hotbloginfos, hotnewsinfos; + + + @Override + protected void initData() { + super.initData(); + RecyclerView.LayoutManager manager = new + LinearLayoutManager(frmctx, LinearLayoutManager.VERTICAL, false); + rv_blogs.setLayoutManager(manager); + rv_blogs.setHasFixedSize(true); + rv_blogs.setItemAnimator(new DefaultItemAnimator()); + + if (getArguments() != null) { + state = getArguments().getInt("STATE"); + } else { + state = READ48; + } + switch (state) { + case READ48: + info48s = new ArrayList(); + adapter48 = new BlogAdapter(frmctx, info48s); + rv_blogs.setAdapter(adapter48); + get48(); + break; + case HOTBLOG: + hotbloginfos = new ArrayList(); + hotadapter = new BlogAdapter(frmctx, hotbloginfos); + rv_blogs.setAdapter(hotadapter); + getHotBlog(); + break; + case HOTNEWS: + hotnewsinfos = new ArrayList(); + newsadapter = new NewsAdapter(frmctx, hotnewsinfos); + rv_blogs.setAdapter(newsadapter); + getHotNews(); + break; + } + } + + @Override + protected void setListener() { + super.setListener(); + sl.setOnLoadListener(new SwipeLoadRefreshLayout.OnLoadListener() { + @Override + public void onLoad() { + switch (state) { + case READ48: + break; + case HOTBLOG: + break; + case HOTNEWS: + break; + } + } + }); + sl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + switch (state) { + case READ48: + get48(); + break; + case HOTBLOG: + hotblogpage = 1; + getHotBlog(); + break; + case HOTNEWS: + getHotNews(); + break; + } + } + }); + + if (adapter48 != null) { + adapter48.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(frmctx, BlogDetailActivity.class); + intent.putExtra("INFO", info48s.get(pos)); + ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle()); + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + } + + if (hotadapter != null) { + hotadapter.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(frmctx, BlogDetailActivity.class); + intent.putExtra("INFO", hotbloginfos.get(pos)); + ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle()); + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + } + if (newsadapter != null) { + newsadapter.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(frmctx, NewsDetailActivity.class); + intent.putExtra("INFO", hotnewsinfos.get(pos)); + ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle()); + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + } + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_explorechild; + } + + @Override + public void onClick(View v) { + + } + + @Override + public void onDestroy() { + super.onDestroy(); + switch (state) { + case READ48: + client.getRequestQueue().cancelAll("get48blog"); + break; + case HOTBLOG: + client.getRequestQueue().cancelAll("getHotBlog"); + break; + case HOTNEWS: + client.getRequestQueue().cancelAll("getHotNews"); + break; + } + } + + /** + * 得到48小时阅读 + */ + private void get48() { + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.URL + read48 + "/" + (Constant.PAFESIZE*3), new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + sl.setRefreshing(false); + Toast.makeText(frmctx, "获取数据失败", Toast.LENGTH_SHORT).show(); + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + info48s.clear(); + info48s.addAll(XMLUtils.getInfos(response)); + adapter48.notifyDataSetChanged(); + sl.setRefreshing(false); + } + }); + request.setTag("get48blog"); + client.addTask(request); + } + + /** + * 得到推荐博客 + */ + private void getHotBlog() { + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.URL + hotblog + (Constant.PAFESIZE * 3), new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + sl.setRefreshing(false); + Toast.makeText(frmctx, "获取数据失败", Toast.LENGTH_SHORT).show(); + hotblogpage--; + if (hotblogpage <= 1) { + hotblogpage = 1; + } + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + if (hotblogpage == 1) { + hotbloginfos.clear(); + hotbloginfos.addAll(XMLUtils.getInfos(response)); + hotadapter.notifyDataSetChanged(); + sl.setRefreshing(false); + } else { + hotbloginfos.addAll(XMLUtils.getInfos(response)); + hotadapter.notifyDataSetChanged(); + sl.setLoading(false); + } + } + }); + request.setTag("getHotBlog"); + client.addTask(request); + } + + /** + * 得到热门新闻 + */ + private void getHotNews() { + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.NEWSURL + hotnews + "/" + (Constant.PAFESIZE * 3), new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + sl.setRefreshing(false); + Toast.makeText(frmctx, "获取数据失败", Toast.LENGTH_SHORT).show(); + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + hotnewsinfos.clear(); + hotnewsinfos.addAll(XMLUtils.getInfos(response)); + newsadapter.notifyDataSetChanged(); + sl.setRefreshing(false); + } + }); + request.setTag("getHotNews"); + client.addTask(request); + } +} + diff --git a/app/src/main/java/com/yjx/cnblog/fragment/ExploreFragment.java b/app/src/main/java/com/yjx/cnblog/fragment/ExploreFragment.java new file mode 100644 index 0000000..97d9f2d --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/fragment/ExploreFragment.java @@ -0,0 +1,65 @@ +package com.yjx.cnblog.fragment;/** + * Created by yjx on 15/5/1. + */ + +import android.graphics.Color; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.view.View; + +import com.yjx.cnblog.R; +import com.yjx.cnblog.adapter.VPAdapter; +import com.yjx.cnblog.base.BaseFragment; +import com.yjx.cnblog.view.SlidingTabLayout; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.InjectView; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:30 + * 发现页面 + */ + +public class ExploreFragment extends BaseFragment { + @InjectView(value = R.id.slid_top) + SlidingTabLayout slid_top; + @InjectView(value = R.id.vp_content) + ViewPager vp_content; + VPAdapter adapter; + List fragments; + private String[] items = new String[]{"48H阅读", "热门博客", "热门新闻"}; + + @Override + protected int getLayoutId() { + return R.layout.fragment_explore; + } + + @Override + protected void initData() { + super.initData(); + slid_top.setSelectedIndicatorColors(Color.WHITE); + slid_top.setDividerColors(Color.TRANSPARENT); + + fragments = new ArrayList(); + for (int i = 0; i < items.length; i++) { + Fragment fragment = new ExploreChildFragment(); + Bundle bundle = new Bundle(); + bundle.putInt("STATE", i + 1); + fragment.setArguments(bundle); + fragments.add(fragment); + } + adapter = new VPAdapter(getChildFragmentManager(), items, fragments); + vp_content.setAdapter(adapter); + slid_top.setViewPager(vp_content); + } + + @Override + public void onClick(View v) { + + } +} diff --git a/app/src/main/java/com/yjx/cnblog/fragment/HomeFragment.java b/app/src/main/java/com/yjx/cnblog/fragment/HomeFragment.java new file mode 100644 index 0000000..b0c2994 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/fragment/HomeFragment.java @@ -0,0 +1,276 @@ +package com.yjx.cnblog.fragment;/** + * Created by yjx on 15/5/1. + */ + +import android.content.Intent; +import android.graphics.Color; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.Toast; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.yjx.cnblog.Constant; +import com.yjx.cnblog.R; +import com.yjx.cnblog.activity.BlogDetailActivity; +import com.yjx.cnblog.activity.NewsDetailActivity; +import com.yjx.cnblog.adapter.BlogAdapter; +import com.yjx.cnblog.adapter.NewsAdapter; +import com.yjx.cnblog.base.BaseFragment; +import com.yjx.cnblog.bean.InfoBean; +import com.yjx.cnblog.listener.onAdapterTouch; +import com.yjx.cnblog.net.XMLRequest; +import com.yjx.cnblog.utils.XMLUtils; +import com.yjx.cnblog.view.SwipeLoadRefreshLayout; + +import org.xmlpull.v1.XmlPullParser; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import butterknife.InjectView; +import de.greenrobot.event.EventBus; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:29 + * 博客页面 + */ +public class HomeFragment extends BaseFragment { + private List blogs; + private List newss; + + @InjectView(value = R.id.rv_blogs) + RecyclerView rv_blogs; + @InjectView(value = R.id.sl) + SwipeLoadRefreshLayout sl; + BlogAdapter adapter; + NewsAdapter newsAdapter; + int blogpage = 1; + int newspage = 1; + boolean isblog = true; + HashMap datas;//用来管理新闻和博客数据 + + @Override + protected int getLayoutId() { + return R.layout.fragment_blog; + } + + @Override + protected void initData() { + super.initData(); + datas = new HashMap(); + sl.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN); + + if (getArguments() != null && getArguments().containsKey("INFO")) { + blogs = (ArrayList) getArguments().getSerializable("INFO"); + if (blogs==null){ + blogs = new ArrayList(); + } + } else { + blogs = new ArrayList(); + } + datas.put("blog", blogs); + isblog = true; + adapter = new BlogAdapter(frmctx, blogs); + RecyclerView.LayoutManager manager = new + LinearLayoutManager(frmctx, LinearLayoutManager.VERTICAL, false); + rv_blogs.setLayoutManager(manager); + rv_blogs.setHasFixedSize(true); + rv_blogs.setItemAnimator(new DefaultItemAnimator()); + rv_blogs.setAdapter(adapter); + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } + newss = new ArrayList(); + newsAdapter = new NewsAdapter(frmctx, newss); + } + + @Override + protected void setListener() { + super.setListener(); + sl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + if (isblog) { + blogpage = 1; + getBlogData(); + } else { + newspage = 1; + getNewsData(); + } + } + }); + sl.setOnLoadListener(new SwipeLoadRefreshLayout.OnLoadListener() { + @Override + public void onLoad() { + if (isblog) { + blogpage++; + getBlogData(); + } else { + newspage++; + getNewsData(); + } + } + }); + adapter.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(frmctx, BlogDetailActivity.class); + intent.putExtra("INFO", blogs.get(pos)); + ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle()); + + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + newsAdapter.setListen(new onAdapterTouch() { + @Override + public void onAdapterClick(View view, int pos) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeScaleUpAnimation(view, location[0], location[1], 0, 0); + Intent intent = null; + intent = new Intent(frmctx, NewsDetailActivity.class); + intent.putExtra("INFO", newss.get(pos)); + ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle()); + } + + @Override + public void onAdapterLongClick(View view, int pos) { + + } + }); + + } + + @Override + public void onClick(View v) { + + } + + @Override + public void onDestroy() { + super.onDestroy(); + client.getRequestQueue().cancelAll("getblog"); + client.getRequestQueue().cancelAll("getnews"); + EventBus.getDefault().unregister(this); + } + + /** + * 从网络获取博客数据 + */ + private void getBlogData() { + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.URL + "sitehome/paged/" + blogpage + "/" + Constant.PAFESIZE, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + sl.setRefreshing(false); + Toast.makeText(frmctx, "获取数据失败", Toast.LENGTH_SHORT).show(); + blogpage--; + if (blogpage <= 1) { + blogpage = 1; + } + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + if (blogpage == 1) { + blogs.clear(); + blogs.addAll(XMLUtils.getInfos(response)); + adapter.notifyDataSetChanged(); + sl.setRefreshing(false); + } else { + blogs.addAll(XMLUtils.getInfos(response)); + adapter.notifyDataSetChanged(); + sl.setLoading(false); + } + datas.remove("blog"); + datas.put("blog", blogs); + } + }); + request.setTag("getblog"); + client.addTask(request); + } + + /** + * 从网络获取新闻数据 + */ + private void getNewsData() { + XMLRequest request = new XMLRequest(Request.Method.GET, Constant.NEWSURL + "recent/paged/" + newspage + "/" + Constant.PAFESIZE, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + sl.setRefreshing(false); + Toast.makeText(frmctx, "获取数据失败", Toast.LENGTH_SHORT).show(); + newspage--; + if (newspage <= 1) { + newspage = 1; + } + } + }, new Response.Listener() { + @Override + public void onResponse(XmlPullParser response) { + if (newspage == 1) { + newss.clear(); + newss.addAll(XMLUtils.getInfos(response)); + newsAdapter.notifyDataSetChanged(); + sl.setRefreshing(false); + } else { + newss.addAll(XMLUtils.getInfos(response)); + newsAdapter.notifyDataSetChanged(); + sl.setLoading(false); + } + datas.remove("news"); + datas.put("news", newss); + } + }); + request.setTag("getnews"); + client.addTask(request); + } + + + /** + * 用来切换RecyclerView中的数据 + * + * @param is + */ + public void onEventMainThread(String is) { + if ("true".equals(is)) + this.isblog = true; + else + this.isblog = false; + if (isblog) { + if (datas.containsKey("blog")) { + rv_blogs.setAdapter(adapter); + } else { + rv_blogs.setAdapter(adapter); + blogpage = 1; + getBlogData(); + } + } else { + if (datas.containsKey("news")) { + rv_blogs.setAdapter(newsAdapter); + } else { + rv_blogs.setAdapter(newsAdapter); + newspage = 1; + getNewsData(); + } + } + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/fragment/NewsFragment.java b/app/src/main/java/com/yjx/cnblog/fragment/NewsFragment.java new file mode 100644 index 0000000..32c1ebb --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/fragment/NewsFragment.java @@ -0,0 +1,12 @@ +package com.yjx.cnblog.fragment;/** + * Created by yjx on 15/5/1. + */ + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 13:29 + * 新闻页面 + */ +public class NewsFragment { +} diff --git a/app/src/main/java/com/yjx/cnblog/fragment/SetttingFragment.java b/app/src/main/java/com/yjx/cnblog/fragment/SetttingFragment.java new file mode 100644 index 0000000..ba50b7c --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/fragment/SetttingFragment.java @@ -0,0 +1,21 @@ +package com.yjx.cnblog.fragment;/** + * Created by yjx on 15/5/4. + */ + +import android.os.Bundle; +import android.preference.PreferenceFragment; + +import com.yjx.cnblog.R; + +/** + * User: YJX + * Date: 2015-05-04 + * Time: 20:27 + */ +public class SetttingFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.settting); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/listener/onAdapterTouch.java b/app/src/main/java/com/yjx/cnblog/listener/onAdapterTouch.java new file mode 100644 index 0000000..c198066 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/listener/onAdapterTouch.java @@ -0,0 +1,14 @@ +package com.yjx.cnblog.listener; + +import android.view.View; + +/** + * Created by yjx on 15/5/1. + * RecyclerView中的触摸事件 + */ +public interface onAdapterTouch { + void onAdapterClick(View view, int pos);//单击事件 + + void onAdapterLongClick(View view, int pos);//长按事件 + +} diff --git a/app/src/main/java/com/yjx/cnblog/net/AsynHttpClient.java b/app/src/main/java/com/yjx/cnblog/net/AsynHttpClient.java new file mode 100644 index 0000000..c8a4c54 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/net/AsynHttpClient.java @@ -0,0 +1,48 @@ +package com.yjx.cnblog.net; + +import android.content.Context; + +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.Volley; + +/** + * User: YJX + * Date: 2015-04-27 + * Time: 16:37 + * 对vollye简单的封装 + */ +public class AsynHttpClient { + private RequestQueue requestQueue; + private static AsynHttpClient instance; + private AsynHttpClient(Context context) { + requestQueue = Volley.newRequestQueue(context); + } + /** + * 单列模式 + * @param context + * @return + */ + public static AsynHttpClient getInstance(Context context) { + if (instance==null){ + synchronized (AsynHttpClient.class){ + if (instance==null){ + instance=new AsynHttpClient(context); + } + } + } + return instance; + } + + /** + * 添加任务 + * @param task + */ + public void addTask(Request task){ + requestQueue.add(task); + } + + public RequestQueue getRequestQueue() { + return requestQueue; + } +} diff --git a/app/src/main/java/com/yjx/cnblog/net/JSONRequest.java b/app/src/main/java/com/yjx/cnblog/net/JSONRequest.java new file mode 100644 index 0000000..cdf6642 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/net/JSONRequest.java @@ -0,0 +1,71 @@ +package com.yjx.cnblog.net; + +import com.alibaba.fastjson.JSON; +import com.android.volley.AuthFailureError; +import com.android.volley.DefaultRetryPolicy; +import com.android.volley.NetworkResponse; +import com.android.volley.ParseError; +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.RetryPolicy; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.HttpHeaderParser; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by 杨佳星 on 2015/1/9. + * 自定义请求 + */ +public class JSONRequest extends Request { + private final Response.Listener mListener; + private Class mClass; + public JSONRequest(int method, String url, Class mClass, Response.Listener listener, Response.ErrorListener errorlistener) { + super(method, url, errorlistener); + this.mListener=listener; + this.mClass=mClass; + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + if(response.statusCode!=200){ + return Response.error(new VolleyError("操作失败")); + }else { + try { + String jsonString = new String(response.data, + HttpHeaderParser.parseCharset(response.headers)); + return Response.success(JSON.parseObject(jsonString, mClass), + HttpHeaderParser.parseCacheHeaders(response,true)); + } catch (Exception e) { + e.printStackTrace(); + return Response.error(new ParseError(e)); + } + } + } + @Override + protected void deliverResponse(T response) { + mListener.onResponse(response); + } + + /* + 设置请求头 Header + */ + @Override + public Map getHeaders() throws AuthFailureError { + Map map=new HashMap(); + map.put("Charset","UTF-8"); + return map; + } + + /* + 设置超时 + */ + @Override + public RetryPolicy getRetryPolicy() { + RetryPolicy retryPolicy= new DefaultRetryPolicy(5000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); + return retryPolicy; + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/net/XMLRequest.java b/app/src/main/java/com/yjx/cnblog/net/XMLRequest.java new file mode 100644 index 0000000..f8d0617 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/net/XMLRequest.java @@ -0,0 +1,66 @@ +package com.yjx.cnblog.net;/** + * Created by yjx on 15/4/28. + */ + +import com.android.volley.DefaultRetryPolicy; +import com.android.volley.NetworkResponse; +import com.android.volley.ParseError; +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.RetryPolicy; +import com.android.volley.toolbox.HttpHeaderParser; +import com.orhanobut.logger.Logger; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.StringReader; +import java.io.UnsupportedEncodingException; + +/** + * User: YJX + * Date: 2015-04-28 + * Time: 21:47 + * XML请求 + */ +public class XMLRequest extends Request { + private Response.Listener mListener; + + public XMLRequest(int method, String url, Response.ErrorListener listener, Response.Listener xmlRequestListener) { + super(method, url, listener); + this.mListener = xmlRequestListener; + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + try { + String xmlString = new String(response.data, + HttpHeaderParser.parseCharset(response.headers)); + Logger.e(xmlString); + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser xmlPullParser = factory.newPullParser(); + xmlPullParser.setInput(new StringReader(xmlString)); + return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response, ignoreNoCache())); + } catch (UnsupportedEncodingException e) { + return Response.error(new ParseError(e)); + } catch (XmlPullParserException e) { + return Response.error(new ParseError(e)); + } + } + + @Override + protected void deliverResponse(XmlPullParser response) { + mListener.onResponse(response); + } + + /** + * 设置超时 + */ + @Override + public RetryPolicy getRetryPolicy() { + RetryPolicy retryPolicy = new DefaultRetryPolicy(5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); + return retryPolicy; + } + +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/APPUtils.java b/app/src/main/java/com/yjx/cnblog/utils/APPUtils.java new file mode 100644 index 0000000..229d8bd --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/APPUtils.java @@ -0,0 +1,74 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/4/30. + */ + +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +/** + * User: YJX + * Date: 2015-04-30 + * Time: 23:07 + * APP信息相关工具类 + */ +public final class APPUtils { + + /** + * 得到APP的数字版本号 + * @param context 上下文 + * @param packname 包名 + * @return + */ + public static int getVersionCode(Context context,String packname){ + PackageManager packageManager=context.getPackageManager(); + try { + PackageInfo packageInfo=packageManager.getPackageInfo(packname,0); + return packageInfo.versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return 1; + } + } + + /** + * 得到APP的版本号 + * @param context 上下文 + * @param packname 包名 + * @return + */ + public static String getVersionName(Context context,String packname){ + PackageManager packageManager=context.getPackageManager(); + try { + PackageInfo packageInfo=packageManager.getPackageInfo(packname,0); + return packageInfo.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return "1.0"; + } + } + + + + + + + + public static void hideSoftInput(Context context,Activity activity) { + InputMethodManager inputMethodManager; + inputMethodManager = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + View v = activity.getCurrentFocus(); + if (v == null) { + return; + } + + inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), + InputMethodManager.HIDE_NOT_ALWAYS); +// activity.clearFocus(); + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/HTMLUtils.java b/app/src/main/java/com/yjx/cnblog/utils/HTMLUtils.java new file mode 100644 index 0000000..9c67170 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/HTMLUtils.java @@ -0,0 +1,66 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/5/2. + */ + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 20:07 + * html工具 + */ +public final class HTMLUtils { + + public static String changeHtmlImgSize(String html, int widht, int height) { + Document document = Jsoup.parse(html); + Elements pngs = document.select("img"); + for (Element element : pngs) { + element.attr("widht", "400px"); + element.attr("height", "500px"); + } + return document.outerHtml(); + + } + + public static String replaceFont(String paramString) { + String returnString = paramString; + // 过滤style标签 + Pattern patternStyle = Pattern.compile( + "<\\s*style\\s*[^>]*?\\s*>\\s*[\\s\\S]*?\\s*<\\s*/\\s*style\\s*?>", + Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + Matcher matcher = patternStyle.matcher(returnString); + while (matcher.find()) { + String group = matcher.group(); + if (group == null) { + continue; + } + // System.out.println(group); + returnString = returnString.replace(group, "$$"); + } + return returnString; + } + + /** + * 替换img中src的内容 + * @param htmlcontent + * @return + */ + public static String replaceImgTag(String htmlcontent) { + Pattern pattern = Pattern.compile(""); + Matcher matcher = pattern.matcher(htmlcontent); + while (true) { + if (!(matcher.find())) + return htmlcontent; + htmlcontent = matcher.replaceAll("【点击查看图片】"); + } + } + + +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/NetUtils.java b/app/src/main/java/com/yjx/cnblog/utils/NetUtils.java new file mode 100644 index 0000000..c85601e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/NetUtils.java @@ -0,0 +1,39 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/5/7. + */ + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * User: YJX + * Date: 2015-05-07 + * Time: 20:47 + */ +public final class NetUtils { + + + public static boolean isNet(Context context) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo infp = manager.getActiveNetworkInfo(); + if (infp == null) { + return false; + } + return infp.isAvailable(); + } + + + public static boolean isWifi(Context context) { + ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo infp = manager.getActiveNetworkInfo(); + if (infp == null) { + return false; + } + if (infp.getType()==ConnectivityManager.TYPE_WIFI){ + return true; + }else{ + return false; + } + } +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/StringUtils.java b/app/src/main/java/com/yjx/cnblog/utils/StringUtils.java new file mode 100644 index 0000000..7bbe447 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/StringUtils.java @@ -0,0 +1,30 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/5/2. + */ + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 20:44 + */ +public final class StringUtils { + public static String readIn(InputStream in) { + String content = ""; + StringBuilder sb = new StringBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + byte[] bytes = new byte[1024]; + try { + while ((content = reader.readLine()) != null) { + sb.append(content); + } + } catch (Exception e) { + e.printStackTrace(); + } + return sb + .toString(); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/TimeUtils.java b/app/src/main/java/com/yjx/cnblog/utils/TimeUtils.java new file mode 100644 index 0000000..02e971e --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/TimeUtils.java @@ -0,0 +1,29 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/5/2. + */ + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 15:39 + */ +public final class TimeUtils { + + + public static String parseTime(String time) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+ss:ss"); + SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date date = sdf.parse(time); + return sdf1.format(date); + } catch (ParseException e) { + e.printStackTrace(); + return time; + } + } + +} diff --git a/app/src/main/java/com/yjx/cnblog/utils/XMLUtils.java b/app/src/main/java/com/yjx/cnblog/utils/XMLUtils.java new file mode 100644 index 0000000..0e38e21 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/utils/XMLUtils.java @@ -0,0 +1,162 @@ +package com.yjx.cnblog.utils;/** + * Created by yjx on 15/5/1. + */ + +import com.yjx.cnblog.bean.AuthorBean; +import com.yjx.cnblog.bean.InfoBean; + +import org.xmlpull.v1.XmlPullParser; + +import java.util.ArrayList; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 17:40 + * xml解析 + */ +public final class XMLUtils { + + /** + * 解析博客信息 + * + * @param parser 解析器 + * @return + */ + public static ArrayList getInfos(XmlPullParser parser) { + ArrayList blogs = null; + InfoBean blog = null; + AuthorBean author = null; + int type = 0; + try { + type = parser.getEventType(); + while (type != XmlPullParser.END_DOCUMENT) { + switch (type) { + case XmlPullParser.START_DOCUMENT: + + break; + case XmlPullParser.START_TAG: + String name = parser.getName(); + if ("feed".equals(name)) { + blogs = new ArrayList(); + } else if ("entry".equals(name)) { + blog = new InfoBean(); + } else if ("id".equals(name)) { + if (blog != null) + blog.setId(parser.nextText()); + } else if ("title".equals(name)) { + if (blog != null) + + blog.setTitle(parser.nextText()); + } else if ("summary".equals(name)) { + if (blog != null) + + blog.setSummary(parser.nextText()); + } else if ("published".equals(name)) { + if (blog != null) + + blog.setPublishedtime(parser.nextText()); + } else if ("updated".equals(name)) { + if (blog != null) + + blog.setUpdatedtime(parser.nextText()); + } else if ("author".equals(name)) { + author = new AuthorBean(); + } else if ("link".equals(name)) { + if (blog != null) { + blog.setUrl(parser.getAttributeValue(1)); + } + parser.nextText(); + } else if ("blogapp".equals(name)) { + if (blog != null) + + blog.setBlogapp(parser.nextText()); + } else if ("diggs".equals(name)) { + if (blog != null) + + blog.setDiggs(Integer.valueOf(parser.nextText())); + } else if ("views".equals(name)) { + if (blog != null) + + blog.setViews(Integer.valueOf(parser.nextText())); + } else if ("comments".equals(name)) { + if (blog != null) + + blog.setComments(Integer.valueOf(parser.nextText())); + } else if ("name".equals(name)) { + if (author != null) + author.setName(parser.nextText()); + + } else if ("avatar".equals(name)) { + if (author != null) + author.setAvatar(parser.nextText()); + + } else if ("uri".equals(name)) { + if (author != null) + author.setUri(parser.nextText()); + + } else if ("topic".equals(name)) { + if (blog != null) + + blog.setTopic(parser.nextText()); + } else if ("topicIcon".equals(name)) { + if (blog != null) + + blog.setTopicIcon(parser.nextText()); + } else if ("sourceName".equals(name)) { + if (blog != null) + blog.setSourceName(parser.nextText()); + } + break; + case XmlPullParser.END_TAG: + if ("entry".equals(parser.getName())) { + blogs.add(blog); + blog = null; + } + if ("author".equals(parser.getName())) { + if (blog != null && author != null) { + blog.setAuthor(author); + } + + } + break; + } + type = parser.next(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return blogs; + } + + + /** + * 得到博客详细内容 + * + * @param parser 解析器 + * @return + */ + public static String getBlogContent(XmlPullParser parser) { + String content = ""; + int type = 0; + try { + type = parser.getEventType(); + while (type != XmlPullParser.END_DOCUMENT) { + switch (type) { + case XmlPullParser.START_TAG: + if ("string".equals(parser.getName())) { + content = parser.nextText(); + } + break; + case XmlPullParser.END_TAG: + break; + } + type = parser.next(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + return content; + } +} diff --git a/app/src/main/java/com/yjx/cnblog/view/CustomListView.java b/app/src/main/java/com/yjx/cnblog/view/CustomListView.java new file mode 100644 index 0000000..ca705be --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/view/CustomListView.java @@ -0,0 +1,34 @@ +package com.yjx.cnblog.view;/** + * Created by yjx on 15/5/3. + */ + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ListView; + +/** + * User: YJX + * Date: 2015-05-03 + * Time: 13:21 + */ +public class CustomListView extends ListView { + public CustomListView(Context context) { + super(context); + } + + public CustomListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = View.MeasureSpec.makeMeasureSpec( + Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/view/CustomScrollView.java b/app/src/main/java/com/yjx/cnblog/view/CustomScrollView.java new file mode 100644 index 0000000..295d0ae --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/view/CustomScrollView.java @@ -0,0 +1,49 @@ +package com.yjx.cnblog.view;/** + * Created by yjx on 15/5/2. + */ + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ScrollView; + +/** + * User: YJX + * Date: 2015-05-02 + * Time: 16:26 + */ +public class CustomScrollView extends ScrollView { + private onCusScrollChanged onCusScrollChanged; + + public CustomScrollView.onCusScrollChanged getOnCusScrollChanged() { + return onCusScrollChanged; + } + + public void setOnCusScrollChanged(CustomScrollView.onCusScrollChanged onCusScrollChanged) { + this.onCusScrollChanged = onCusScrollChanged; + } + + public CustomScrollView(Context context) { + super(context); + } + + public CustomScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + if (onCusScrollChanged!=null){ + onCusScrollChanged.onCusScrollChanged(l, t, oldl, oldt); + } + } + + public interface onCusScrollChanged{ + void onCusScrollChanged(int l, int t, int oldl, int oldt); + } +} diff --git a/app/src/main/java/com/yjx/cnblog/view/SlidingTabLayout.java b/app/src/main/java/com/yjx/cnblog/view/SlidingTabLayout.java new file mode 100644 index 0000000..4f0acdd --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/view/SlidingTabLayout.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.yjx.cnblog.view; + +import android.content.Context; +import android.graphics.Typeface; +import android.os.Build; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.HorizontalScrollView; +import android.widget.TextView; + +/** + * To be used with ViewPager to provide a tab indicator component which give constant feedback as to + * the user's scroll progress. + *

+ * To use the component, simply add it to your view hierarchy. Then in your + * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call + * {@link #setViewPager(android.support.v4.view.ViewPager)} providing it the ViewPager this layout is being used for. + *

+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors + * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The + * alternative is via the {@link com.yjx.cnblog.view.SlidingTabLayout.TabColorizer} interface which provides you complete control over + * which color is used for any individual position. + *

+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)}, + * providing the layout ID of your custom layout. + */ +public class SlidingTabLayout extends HorizontalScrollView { + + /** + * Allows complete control over the colors drawn in the tab layout. Set with + * {@link #setCustomTabColorizer(com.yjx.cnblog.view.SlidingTabLayout.TabColorizer)}. + */ + public interface TabColorizer { + + /** + * @return return the color of the indicator used when {@code position} is selected. + */ + int getIndicatorColor(int position); + + /** + * @return return the color of the divider drawn to the right of {@code position}. + */ + int getDividerColor(int position); + + } + + private static final int TITLE_OFFSET_DIPS = 24; + private static final int TAB_VIEW_PADDING_DIPS = 20; + private static final int TAB_VIEW_TEXT_SIZE_SP = 16; + + private int mTitleOffset; + + private int mTabViewLayoutId; + private int mTabViewTextViewId; + + private ViewPager mViewPager; + private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; + + private final SlidingTabStrip mTabStrip; + + public SlidingTabLayout(Context context) { + this(context, null); + } + + public SlidingTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + // Disable the Scroll Bar + setHorizontalScrollBarEnabled(false); + // Make sure that the Tab Strips fills this View + setFillViewport(true); + + mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); + + mTabStrip = new SlidingTabStrip(context); + addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + mTabStrip.setGravity(Gravity.CENTER_HORIZONTAL); + } + + /** + * Set the custom {@link com.yjx.cnblog.view.SlidingTabLayout.TabColorizer} to be used. + * + * If you only require simple custmisation then you can use + * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve + * similar effects. + */ + public void setCustomTabColorizer(TabColorizer tabColorizer) { + mTabStrip.setCustomTabColorizer(tabColorizer); + } + + /** + * Sets the colors to be used for indicating the selected tab. These colors are treated as a + * circular array. Providing one color will mean that all tabs are indicated with the same color. + */ + public void setSelectedIndicatorColors(int... colors) { + mTabStrip.setSelectedIndicatorColors(colors); + } + + /** + * Sets the colors to be used for tab dividers. These colors are treated as a circular array. + * Providing one color will mean that all tabs are indicated with the same color. + */ + public void setDividerColors(int... colors) { + mTabStrip.setDividerColors(colors); + } + + /** + * Set the {@link android.support.v4.view.ViewPager.OnPageChangeListener}. When using {@link com.yjx.cnblog.view.SlidingTabLayout} you are + * required to set any {@link android.support.v4.view.ViewPager.OnPageChangeListener} through this method. This is so + * that the layout can update it's scroll position correctly. + * + * @see android.support.v4.view.ViewPager#setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener) + */ + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mViewPagerPageChangeListener = listener; + } + + /** + * Set the custom layout to be inflated for the tab views. + * + * @param layoutResId Layout id to be inflated + * @param textViewId id of the {@link android.widget.TextView} in the inflated view + */ + public void setCustomTabView(int layoutResId, int textViewId) { + mTabViewLayoutId = layoutResId; + mTabViewTextViewId = textViewId; + } + + /** + * Sets the associated view pager. Note that the assumption here is that the pager content + * (number of tabs and tab titles) does not change after this call has been made. + */ + public void setViewPager(ViewPager viewPager) { + mTabStrip.removeAllViews(); + + mViewPager = viewPager; + if (viewPager != null) { + viewPager.setOnPageChangeListener(new InternalViewPagerListener()); + populateTabStrip(); + } + } + + /** + * Create a default view to be used for tabs. This is called if a custom tab view is not set via + * {@link #setCustomTabView(int, int)}. + */ + protected TextView createDefaultTabView(Context context) { + TextView textView = new TextView(context); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); + textView.setTypeface(Typeface.DEFAULT_BOLD); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // If we're running on Honeycomb or newer, then we can use the Theme's + // selectableItemBackground to ensure that the View has a pressed state + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, + outValue, true); + textView.setBackgroundResource(outValue.resourceId); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style + textView.setAllCaps(true); + } + + int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); + textView.setPadding(padding, padding, padding, padding); + + return textView; + } + + private void populateTabStrip() { + final PagerAdapter adapter = mViewPager.getAdapter(); + final OnClickListener tabClickListener = new TabClickListener(); + + for (int i = 0; i < adapter.getCount(); i++) { + View tabView = null; + TextView tabTitleView = null; + + if (mTabViewLayoutId != 0) { + // If there is a custom tab view layout id set, try and inflate it + tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, + false); + tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); + } + + if (tabView == null) { + tabView = createDefaultTabView(getContext()); + } + + if (tabTitleView == null && TextView.class.isInstance(tabView)) { + tabTitleView = (TextView) tabView; + } + + tabTitleView.setText(adapter.getPageTitle(i)); + tabView.setOnClickListener(tabClickListener); + + mTabStrip.addView(tabView); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (mViewPager != null) { + scrollToTab(mViewPager.getCurrentItem(), 0); + } + } + + private void scrollToTab(int tabIndex, int positionOffset) { + final int tabStripChildCount = mTabStrip.getChildCount(); + if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { + return; + } + + View selectedChild = mTabStrip.getChildAt(tabIndex); + if (selectedChild != null) { + int targetScrollX = selectedChild.getLeft() + positionOffset; + + if (tabIndex > 0 || positionOffset > 0) { + // If we're not at the first child and are mid-scroll, make sure we obey the offset + targetScrollX -= mTitleOffset; + } + + scrollTo(targetScrollX, 0); + } + } + + private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { + private int mScrollState; + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + int tabStripChildCount = mTabStrip.getChildCount(); + if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { + return; + } + + mTabStrip.onViewPagerPageChanged(position, positionOffset); + + View selectedTitle = mTabStrip.getChildAt(position); + int extraOffset = (selectedTitle != null) + ? (int) (positionOffset * selectedTitle.getWidth()) + : 0; + scrollToTab(position, extraOffset); + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, + positionOffsetPixels); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + mScrollState = state; + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageScrollStateChanged(state); + } + } + + @Override + public void onPageSelected(int position) { + if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { + mTabStrip.onViewPagerPageChanged(position, 0f); + scrollToTab(position, 0); + } + + if (mViewPagerPageChangeListener != null) { + mViewPagerPageChangeListener.onPageSelected(position); + } + } + + } + + private class TabClickListener implements OnClickListener { + @Override + public void onClick(View v) { + for (int i = 0; i < mTabStrip.getChildCount(); i++) { + if (v == mTabStrip.getChildAt(i)) { + mViewPager.setCurrentItem(i); + return; + } + } + } + } + +} diff --git a/app/src/main/java/com/yjx/cnblog/view/SlidingTabStrip.java b/app/src/main/java/com/yjx/cnblog/view/SlidingTabStrip.java new file mode 100644 index 0000000..28d6177 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/view/SlidingTabStrip.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.yjx.cnblog.view; + +import android.R; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.widget.LinearLayout; + +class SlidingTabStrip extends LinearLayout { + + private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; + private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; + private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; + private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; + + private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; + private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; + private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; + + private final int mBottomBorderThickness; + private final Paint mBottomBorderPaint; + + private final int mSelectedIndicatorThickness; + private final Paint mSelectedIndicatorPaint; + + private final int mDefaultBottomBorderColor; + + private final Paint mDividerPaint; + private final float mDividerHeight; + + private int mSelectedPosition; + private float mSelectionOffset; + + private SlidingTabLayout.TabColorizer mCustomTabColorizer; + private final SimpleTabColorizer mDefaultTabColorizer; + + SlidingTabStrip(Context context) { + this(context, null); + } + + SlidingTabStrip(Context context, AttributeSet attrs) { + super(context, attrs); + setWillNotDraw(false); + + final float density = getResources().getDisplayMetrics().density; + + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true); + final int themeForegroundColor = outValue.data; + + mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, + DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); + + mDefaultTabColorizer = new SimpleTabColorizer(); + mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); + mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, + DEFAULT_DIVIDER_COLOR_ALPHA)); + + mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); + mBottomBorderPaint = new Paint(); + mBottomBorderPaint.setColor(mDefaultBottomBorderColor); + + mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); + mSelectedIndicatorPaint = new Paint(); + + mDividerHeight = DEFAULT_DIVIDER_HEIGHT; + mDividerPaint = new Paint(); + mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density)); + } + + void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { + mCustomTabColorizer = customTabColorizer; + invalidate(); + } + + void setSelectedIndicatorColors(int... colors) { + // Make sure that the custom colorizer is removed + mCustomTabColorizer = null; + mDefaultTabColorizer.setIndicatorColors(colors); + invalidate(); + } + + void setDividerColors(int... colors) { + // Make sure that the custom colorizer is removed + mCustomTabColorizer = null; + mDefaultTabColorizer.setDividerColors(colors); + invalidate(); + } + + void onViewPagerPageChanged(int position, float positionOffset) { + mSelectedPosition = position; + mSelectionOffset = positionOffset; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + final int height = getHeight(); + final int childCount = getChildCount(); + final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); + final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null + ? mCustomTabColorizer + : mDefaultTabColorizer; + + // Thick colored underline below the current selection + if (childCount > 0) { + View selectedTitle = getChildAt(mSelectedPosition); + int left = selectedTitle.getLeft(); + int right = selectedTitle.getRight(); + int color = tabColorizer.getIndicatorColor(mSelectedPosition); + + if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { + int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); + if (color != nextColor) { + color = blendColors(nextColor, color, mSelectionOffset); + } + + // Draw the selection partway between the tabs + View nextTitle = getChildAt(mSelectedPosition + 1); + left = (int) (mSelectionOffset * nextTitle.getLeft() + + (1.0f - mSelectionOffset) * left); + right = (int) (mSelectionOffset * nextTitle.getRight() + + (1.0f - mSelectionOffset) * right); + } + + mSelectedIndicatorPaint.setColor(color); + + canvas.drawRect(left, height - mSelectedIndicatorThickness+10, right, + height, mSelectedIndicatorPaint); + } + + // Thin underline along the entire bottom edge + canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); + + // Vertical separators between the titles + int separatorTop = (height - dividerHeightPx) / 2; + for (int i = 0; i < childCount - 1; i++) { + View child = getChildAt(i); + mDividerPaint.setColor(tabColorizer.getDividerColor(i)); + canvas.drawLine(child.getRight(), separatorTop, child.getRight(), + separatorTop + dividerHeightPx, mDividerPaint); + } + } + + /** + * Set the alpha value of the {@code color} to be the given {@code alpha} value. + */ + private static int setColorAlpha(int color, byte alpha) { + return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); + } + + /** + * Blend {@code color1} and {@code color2} using the given ratio. + * + * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, + * 0.0 will return {@code color2}. + */ + private static int blendColors(int color1, int color2, float ratio) { + final float inverseRation = 1f - ratio; + float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); + float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); + float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); + return Color.rgb((int) r, (int) g, (int) b); + } + + private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { + private int[] mIndicatorColors; + private int[] mDividerColors; + + @Override + public final int getIndicatorColor(int position) { + return mIndicatorColors[position % mIndicatorColors.length]; + } + + @Override + public final int getDividerColor(int position) { + return mDividerColors[position % mDividerColors.length]; + } + + void setIndicatorColors(int... colors) { + mIndicatorColors = colors; + } + + void setDividerColors(int... colors) { + mDividerColors = colors; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yjx/cnblog/view/SwipeLoadRefreshLayout.java b/app/src/main/java/com/yjx/cnblog/view/SwipeLoadRefreshLayout.java new file mode 100644 index 0000000..acc4394 --- /dev/null +++ b/app/src/main/java/com/yjx/cnblog/view/SwipeLoadRefreshLayout.java @@ -0,0 +1,170 @@ +package com.yjx.cnblog.view;/** + * Created by yjx on 15/5/1. + */ + +import android.content.Context; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +/** + * User: YJX + * Date: 2015-05-01 + * Time: 22:57 + */ +public class SwipeLoadRefreshLayout extends SwipeRefreshLayout { + private RecyclerView recyclerView; + //按下去的时候位置 + private int mLastY, mYDown; + //加载更多的监听器 + private OnLoadListener mOnLoadListener; + //最小出发距离 + private int mTouchSlop; + /** + * 是否在加载中 ( 上拉加载更多 ) + */ + private boolean isLoading = false; + + public SwipeLoadRefreshLayout(Context context) { + this(context, null); + } + + public SwipeLoadRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + // RecyclerView初始化 + if (recyclerView == null) { + int childs = getChildCount(); + if (childs > 0) { + for (int i = 0; i < childs; i++) { + View childView = getChildAt(i); + if (childView instanceof RecyclerView) { + recyclerView = (RecyclerView) childView; + recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + if (canLoad()) { +// loadData(); + } + } + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + } + }); + break; + } + } + } + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + + switch (action) { + case MotionEvent.ACTION_DOWN: + // 按下 + mYDown = (int) event.getRawY(); + break; + + case MotionEvent.ACTION_MOVE: + // 移动 + mLastY = (int) event.getRawY(); + if (canLoad()) { +//添加View + } else { + + } + break; + + case MotionEvent.ACTION_UP: + // 抬起 + if (canLoad()) { + loadData(); + } + break; + default: + break; + } + return super.dispatchTouchEvent(event); + } + + + /** + * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作. + * + * @return + */ + private boolean canLoad() { + return isBottom() && !isLoading && isPullUp(); + } + + /** + * 判断是否到了最底部 + */ + private boolean isBottom() { + if (recyclerView != null && recyclerView.getAdapter() != null) { + return ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition() == (recyclerView.getAdapter().getItemCount() - 1); + } + return false; + } + + public void setOnLoadListener(OnLoadListener mOnLoadListener) { + this.mOnLoadListener = mOnLoadListener; + } + + /** + * 是否是上拉操作 + * + * @return + */ + private boolean isPullUp() { + return (mYDown - mLastY) >= mTouchSlop; + } + + /** + * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 + */ + private void loadData() { + if (mOnLoadListener != null) { + // 设置状态 + setLoading(true); + // + mOnLoadListener.onLoad(); + } + } + + /** + * 加载更多的监听器 + * + * @author mrsimple + */ + public static interface OnLoadListener { + public void onLoad(); + } + + /** + * @param loading + */ + public void setLoading(boolean loading) { + isLoading = loading; + if (isLoading) { + } else { + mYDown = 0; + mLastY = 0; + } + } +} diff --git a/app/src/main/res/color/item_color.xml b/app/src/main/res/color/item_color.xml new file mode 100755 index 0000000..e41bde1 --- /dev/null +++ b/app/src/main/res/color/item_color.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..908a5e9 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..fd16c67 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-v21/menuitem_selector.xml b/app/src/main/res/drawable-v21/menuitem_selector.xml new file mode 100644 index 0000000..84dcb89 --- /dev/null +++ b/app/src/main/res/drawable-v21/menuitem_selector.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/abc_ic_search_api_mtrl_alpha.png b/app/src/main/res/drawable-xhdpi/abc_ic_search_api_mtrl_alpha.png new file mode 100755 index 0000000..0958c74 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/abc_ic_search_api_mtrl_alpha.png differ diff --git a/app/src/main/res/drawable-xhdpi/collect.png b/app/src/main/res/drawable-xhdpi/collect.png new file mode 100644 index 0000000..4c31429 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/collect.png differ diff --git a/app/src/main/res/drawable-xhdpi/comments.png b/app/src/main/res/drawable-xhdpi/comments.png new file mode 100644 index 0000000..2179292 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/comments.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer_collect_normal.png b/app/src/main/res/drawable-xhdpi/ic_drawer_collect_normal.png new file mode 100755 index 0000000..755e4b8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drawer_collect_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer_explore_normal.png b/app/src/main/res/drawable-xhdpi/ic_drawer_explore_normal.png new file mode 100755 index 0000000..deb008d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drawer_explore_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer_follow_normal.png b/app/src/main/res/drawable-xhdpi/ic_drawer_follow_normal.png new file mode 100755 index 0000000..806dc77 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drawer_follow_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer_home_normal.png b/app/src/main/res/drawable-xhdpi/ic_drawer_home_normal.png new file mode 100755 index 0000000..b870cf1 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drawer_home_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..20632a8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-xhdpi/read.png b/app/src/main/res/drawable-xhdpi/read.png new file mode 100644 index 0000000..9dc1043 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/read.png differ diff --git a/app/src/main/res/drawable-xhdpi/settting.png b/app/src/main/res/drawable-xhdpi/settting.png new file mode 100644 index 0000000..36ef675 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/settting.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..e77934d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable/bg_listview_item.xml b/app/src/main/res/drawable/bg_listview_item.xml new file mode 100755 index 0000000..5a74ace --- /dev/null +++ b/app/src/main/res/drawable/bg_listview_item.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/menuitem_selector.xml b/app/src/main/res/drawable/menuitem_selector.xml new file mode 100644 index 0000000..29c2524 --- /dev/null +++ b/app/src/main/res/drawable/menuitem_selector.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..83d8da3 --- /dev/null +++ b/app/src/main/res/layout/activity_about.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_author.xml b/app/src/main/res/layout/activity_author.xml new file mode 100644 index 0000000..8683822 --- /dev/null +++ b/app/src/main/res/layout/activity_author.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_blogdetail.xml b/app/src/main/res/layout/activity_blogdetail.xml new file mode 100644 index 0000000..2be4396 --- /dev/null +++ b/app/src/main/res/layout/activity_blogdetail.xml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..053b842 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_newsdetail.xml b/app/src/main/res/layout/activity_newsdetail.xml new file mode 100644 index 0000000..2be4396 --- /dev/null +++ b/app/src/main/res/layout/activity_newsdetail.xml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 0000000..fc1d84b --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml new file mode 100644 index 0000000..75f219d --- /dev/null +++ b/app/src/main/res/layout/activity_setting.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..ca2de0f --- /dev/null +++ b/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_blog.xml b/app/src/main/res/layout/fragment_blog.xml new file mode 100644 index 0000000..3109034 --- /dev/null +++ b/app/src/main/res/layout/fragment_blog.xml @@ -0,0 +1,20 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_explore.xml b/app/src/main/res/layout/fragment_explore.xml new file mode 100644 index 0000000..a149cb8 --- /dev/null +++ b/app/src/main/res/layout/fragment_explore.xml @@ -0,0 +1,21 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_explorechild.xml b/app/src/main/res/layout/fragment_explorechild.xml new file mode 100644 index 0000000..8f53877 --- /dev/null +++ b/app/src/main/res/layout/fragment_explorechild.xml @@ -0,0 +1,20 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_author.xml b/app/src/main/res/layout/item_author.xml new file mode 100644 index 0000000..23ef073 --- /dev/null +++ b/app/src/main/res/layout/item_author.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_authorblog.xml b/app/src/main/res/layout/item_authorblog.xml new file mode 100644 index 0000000..31d0ffa --- /dev/null +++ b/app/src/main/res/layout/item_authorblog.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_blog.xml b/app/src/main/res/layout/item_blog.xml new file mode 100644 index 0000000..43ba1ba --- /dev/null +++ b/app/src/main/res/layout/item_blog.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_footer.xml b/app/src/main/res/layout/layout_footer.xml new file mode 100644 index 0000000..af99459 --- /dev/null +++ b/app/src/main/res/layout/layout_footer.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_menu.xml b/app/src/main/res/layout/layout_menu.xml new file mode 100644 index 0000000..2a55ce8 --- /dev/null +++ b/app/src/main/res/layout/layout_menu.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_top.xml b/app/src/main/res/layout/layout_top.xml new file mode 100644 index 0000000..d2eae8d --- /dev/null +++ b/app/src/main/res/layout/layout_top.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/preference_category_widget.xml b/app/src/main/res/layout/preference_category_widget.xml new file mode 100755 index 0000000..5532cba --- /dev/null +++ b/app/src/main/res/layout/preference_category_widget.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/preference_item.xml b/app/src/main/res/layout/preference_item.xml new file mode 100755 index 0000000..ab9c5e0 --- /dev/null +++ b/app/src/main/res/layout/preference_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..d2f9284 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,11 @@ +

+ + + diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml new file mode 100644 index 0000000..c28926a --- /dev/null +++ b/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..8486c30 --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..a9c1c22 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,12 @@ + + + #4CAF50 + #388E3C + #ffffff + #666666 + #216b74ff + + #4387F0 + #ff2b4d90 + #18b000 + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..5b39eec --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ + + + 16dp + 16dp + 48dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..bb1d6a2 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + 博客园 + + Hello world! + Settings + 博客 + 新闻 + 发现 + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..c65a7d2 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/xml/settting.xml b/app/src/main/res/xml/settting.xml new file mode 100644 index 0000000..7d56b09 --- /dev/null +++ b/app/src/main/res/xml/settting.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d3ff69d --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8c0fb64 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c71e76 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app'