├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── universal-image-loader-1.9.3-SNAPSHOT.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── tk │ │ └── wlemuel │ │ └── cotable │ │ ├── ApplicationTest.java │ │ ├── ExampleTest.java │ │ └── utils │ │ └── TLogTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── content-template.html │ ├── content.html │ ├── font-big.css │ ├── font-middle.css │ ├── font-small.css │ ├── style-day.css │ └── style-night.css │ ├── java │ ├── android │ │ └── support │ │ │ └── v4 │ │ │ └── widget │ │ │ └── MySwipeRefreshLayout.java │ └── tk │ │ └── wlemuel │ │ └── cotable │ │ ├── activity │ │ ├── MainActivity.java │ │ ├── News │ │ │ ├── adapter │ │ │ │ └── NewsAdapter.java │ │ │ └── fragment │ │ │ │ └── NewsFragment.java │ │ ├── SplashActivity.java │ │ ├── blog │ │ │ ├── BlogTab.java │ │ │ ├── adapter │ │ │ │ ├── BlogAdapter.java │ │ │ │ └── BlogTabPagerAdapter.java │ │ │ ├── fragment │ │ │ │ ├── BlogDetailFragment.java │ │ │ │ ├── BlogListFragment.java │ │ │ │ └── BlogViewPagerFragment.java │ │ │ └── view │ │ │ │ └── DetailActivity.java │ │ ├── common │ │ │ └── SimpleBackActivity.java │ │ ├── image │ │ │ └── ImagePreviewActivity.java │ │ ├── settings │ │ │ └── fragment │ │ │ │ ├── AboutFragment.java │ │ │ │ └── SettingFragment.java │ │ └── view │ │ │ ├── CoScrollView.java │ │ │ ├── ReaderWebView.java │ │ │ └── ScrollDirectionListener.java │ │ ├── api │ │ ├── ApiClientHelper.java │ │ ├── ApiHttpClient.java │ │ ├── BaseApi.java │ │ ├── BlogApi.java │ │ └── NewsApi.java │ │ ├── base │ │ ├── BaseActivity.java │ │ ├── BaseApplication.java │ │ ├── BaseDetailFragment.java │ │ ├── BaseFragment.java │ │ ├── BaseListAdapter.java │ │ ├── BaseRecycleAdapter.java │ │ ├── BaseRecycleViewFragment.java │ │ └── BaseTabFragment.java │ │ ├── cache │ │ └── CacheManager.java │ │ ├── core │ │ ├── AppConfig.java │ │ ├── AppContext.java │ │ ├── AppException.java │ │ └── AppManager.java │ │ ├── model │ │ ├── Base.java │ │ ├── Blog.java │ │ ├── BlogDetail.java │ │ ├── BlogList.java │ │ ├── DrawerMenu.java │ │ ├── Entity.java │ │ ├── ListEntity.java │ │ ├── News.java │ │ └── SimpleBackPage.java │ │ ├── ui │ │ ├── customWidget │ │ │ └── CircleImageView.java │ │ ├── decorator │ │ │ └── DividerItemDecoration.java │ │ ├── dialog │ │ │ ├── DialogControl.java │ │ │ └── WaitDialog.java │ │ ├── drawer │ │ │ ├── DrawerMenuAdapter.java │ │ │ └── DrawerMenuHolder.java │ │ ├── empty │ │ │ └── EmptyLayout.java │ │ ├── pagertab │ │ │ ├── PagerSlidingTabStrip.java │ │ │ ├── SlidingTabPagerAdapter.java │ │ │ ├── q.java │ │ │ └── r.java │ │ └── widget │ │ │ └── FixedRecyclerView.java │ │ └── utils │ │ ├── BlogReaderAnim.java │ │ ├── CircleBitmapDisplayer.java │ │ ├── CyptoUtils.java │ │ ├── HtmlUtils.java │ │ ├── OnWebViewImageListener.java │ │ ├── StringUtils.java │ │ ├── TDevice.java │ │ ├── TLog.java │ │ ├── TimeZoneUtil.java │ │ ├── UIHelper.java │ │ └── ViewUtils.java │ └── res │ ├── anim │ └── progressbar_loading.xml │ ├── drawable-hdpi │ ├── ic_add_white_24dp.png │ ├── ic_comment.png │ ├── ic_comment_active.png │ ├── ic_dianzan.png │ ├── ic_dianzan_active.png │ ├── ic_launcher.png │ ├── ic_pullrefresh.png │ ├── ic_reply.png │ ├── ic_reply_active.png │ ├── ic_scrolltoup_24dp.png │ ├── main_bottombtn_down.9.png │ ├── main_bottombtn_up.9.png │ ├── main_icon_zoomin.png │ ├── main_icon_zoomin_dis.png │ ├── main_icon_zoomout.png │ ├── main_icon_zoomout_dis.png │ ├── main_topbtn_down.9.png │ ├── main_topbtn_up.9.png │ ├── main_zoomin.xml │ ├── main_zoomout.xml │ ├── spinner_48_inner_holo.png │ └── spinner_48_outer_holo.png │ ├── drawable-mdpi │ ├── ic_avatar_author.png │ └── ic_launcher.png │ ├── drawable-xhdpi │ ├── actionbar_back_icon_normal.png │ ├── animdraw.xml │ ├── bg_splash_bg.png │ ├── btn_menu_about_normal.png │ ├── btn_menu_about_pressed.png │ ├── btn_menu_close_normal.png │ ├── btn_menu_close_pressed.png │ ├── btn_menu_day_pressed.png │ ├── btn_menu_daymode_normal.png │ ├── btn_menu_night_normal.png │ ├── btn_menu_night_pressed.png │ ├── btn_menu_options_normal.png │ ├── btn_menu_options_pressed.png │ ├── drawer_left_header.jpg │ ├── ic_avatar_author.png │ ├── ic_blog_item_avatar.png │ ├── ic_default_avatar.png │ ├── ic_launcher.png │ ├── loadingpage_bg.png │ ├── loadingpage_light.png │ ├── page_icon_network.png │ ├── pagefailed_bg.png │ └── tab_notification_bg.9.png │ ├── drawable-xxhdpi │ ├── ic_avatar_author.png │ └── ic_launcher.png │ ├── drawable │ ├── bg_drawer_left_list_item.xml │ ├── list_cell_background_selector.xml │ ├── main_bottombutton.xml │ ├── main_topbutton.xml │ ├── progress_medium_holo.xml │ └── tab_strip_background.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_main_blog_list.xml │ ├── activity_main_blog_list_item.xml │ ├── activity_main_drawer_left.xml │ ├── activity_main_drawer_left_divider.xml │ ├── activity_main_drawer_left_list_group.xml │ ├── activity_main_drawer_left_list_item.xml │ ├── activity_main_drawer_left_setting_bar.xml │ ├── aty_detail.xml │ ├── aty_simple_fragment.xml │ ├── aty_splash_background.xml │ ├── fragment_blog_detail.xml │ ├── fragment_swipe_refresh_recycleview.xml │ ├── fragment_viewpager.xml │ ├── list_cell_blog.xml │ ├── list_cell_footer.xml │ ├── tab_layout_main.xml │ ├── view_error_layout.xml │ ├── view_toast.xml │ └── view_toolbar.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-en-rUS │ └── strings.xml │ ├── values-ja-rJP │ └── strings.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot └── screenshot.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | 9 | # built application files 10 | *.apk 11 | *.ap_ 12 | 13 | # files for the dex VM 14 | *.dex 15 | 16 | # Java class files 17 | *.class 18 | 19 | # generated files 20 | bin/ 21 | gen/ 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Eclipse project files 27 | .classpath 28 | .project 29 | 30 | # Proguard folder generated by Eclipse 31 | proguard/ 32 | 33 | # Intellij project files 34 | *.iml 35 | *.ipr 36 | *.iws 37 | .idea/ 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cotable - Yet Another Cnblogs Client for Android 2 | 3 | [![Join the chat at https://gitter.im/Lemueler/Cotable](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Lemueler/Cotable?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | ## Description 6 | Cotable = Code + Stable (The Paradise of Coder) 7 | 8 | The Android client of Cnblogs that named as "Cotable", the reason why I decided to make this baby is that I want to learn Android development and I like read the blogs at "www.cnblogs.com" as well. I do hope u could join me to make this application better. 9 | 10 | 11 | ## ScreenShot 12 | 13 | ![pic_03](http://git.oschina.net/wlemuel/Cotable/raw/master/screenshot/screenshot.png) 14 | 15 | ## Features 16 | It can store the cache into you device automatically, so that if you have viewed a blog before, you could view it without the internet connection next time. 17 | 18 | 19 | ## Upgrade Notes 20 | ### v1.0 21 | Provide the basic functions like read the lastest blog and latest news and the recommend blogs. 22 | 23 | 24 | ## TODO (wish list) 25 | 1. Add the login functions. 26 | 2. Make the blogs read by catalogs. (Need web api support, Maybe I will write it depending on Python+Django). 27 | 3. View the comment of current blog or news. 28 | 4. Post a new blog to the Cnblogs. 29 | 5. Add the night read mode. 30 | 6. ... 31 | 32 | 33 | ## Thanks 34 | 1. [android-app](http://git.oschina.net/tonlin/android-app): 35 | A lot of codes were borrowed from this project. 36 | 2. [android-async-http](https://github.com/loopj/android-async-http): An Asynchronous HTTP Library for Android. 37 | 3. [floatingactionbutton](https://github.com/makovkastar/FloatingActionButton): Android floating action button. 38 | 39 | ## License 40 | 41 | Copyright 2015 Steve Lemuel 42 | 43 | Licensed under the Apache License, Version 2.0 (the "License"); 44 | you may not use this file except in compliance with the License. 45 | You may obtain a copy of the License at 46 | 47 | http://www.apache.org/licenses/LICENSE-2.0 48 | 49 | Unless required by applicable law or agreed to in writing, software 50 | distributed under the License is distributed on an "AS IS" BASIS, 51 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 52 | See the License for the specific language governing permissions and 53 | limitations under the License. 54 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "tk.wlemuel.cotable" 9 | minSdkVersion 9 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0-Alpha" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', exclude: ['x.jar'], include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:21.0.3' 25 | compile 'com.android.support:recyclerview-v7:21.0.3' 26 | compile 'com.joanzapata.android:android-iconify:1.0.8' 27 | compile 'de.hdodenhof:circleimageview:1.2.2' 28 | compile 'com.loopj.android:android-async-http:1.4.6' 29 | compile 'com.melnykov:floatingactionbutton:1.3.0' 30 | 31 | // compile 'com.github.johnpersano:supertoasts:1.3.4@aar' 32 | // compile 'com.github.johnkil.android-appmsg:appmsg:1.2.0' 33 | // compile 'com.balysv.materialmenu:material-menu-abc:1.5.1' 34 | // compile 'in.srain.cube:ultra-ptr:1.0.9@aar' 35 | // compile 'be.webelite:ion-iconview:1.0.+@aar' 36 | // compile 'com.github.traex.calendarlistview:library:1.2.2' 37 | // compile 'com.github.navasmdc:MaterialDesign:1.+@aar' 38 | // compile 'com.balysv.materialmenu:material-menu:1.5.1' 39 | // compile 'com.github.manuelpeinado.fadingactionbar:fadingactionbar:3.1.2' 40 | // compile 'com.getbase:floatingactionbutton:1.9.0' 41 | // compile 'com.oguzdev:CircularFloatingActionMenu:1.0.2' 42 | // compile 'com.specyci:residemenu:1.6+' 43 | // compile 'com.arasthel:gnavdrawer-library:+' 44 | } 45 | 46 | -------------------------------------------------------------------------------- /app/libs/universal-image-loader-1.9.3-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/libs/universal-image-loader-1.9.3-SNAPSHOT.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Volumes/Extend/Development/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/tk/wlemuel/cotable/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/tk/wlemuel/cotable/ExampleTest.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable; 2 | 3 | /** 4 | * ExampleTest 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc ExampleTest 9 | * @created 2015/05/19 10 | * @updated 2015/05/19 11 | */ 12 | public class ExampleTest { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/androidTest/java/tk/wlemuel/cotable/utils/TLogTest.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import junit.framework.TestCase; 4 | 5 | /** 6 | * TLogTest 7 | * 8 | * @author Steve Lemuel 9 | * @version 0.1 10 | * @desc TLogTest 11 | * @created 2015/05/19 12 | * @updated 2015/05/19 13 | */ 14 | public class TLogTest extends TestCase { 15 | 16 | public void setUp() throws Exception { 17 | super.setUp(); 18 | 19 | } 20 | 21 | public void tearDown() throws Exception { 22 | 23 | } 24 | 25 | public void testAnalytics() throws Exception { 26 | 27 | } 28 | 29 | public void testError() throws Exception { 30 | 31 | } 32 | 33 | public void testLog() throws Exception { 34 | 35 | } 36 | 37 | public void testLog1() throws Exception { 38 | 39 | } 40 | 41 | public void testLogv() throws Exception { 42 | 43 | } 44 | 45 | public void testWarning() throws Exception { 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/assets/content-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Cnblogs 8 | 9 | 10 | 11 |
12 | 13 |
14 |
15 |

{%title%}

16 | 17 |

{%posted%} | 作者 : {%author%} | {%reads%} 次阅读

18 |
19 | 20 |
21 | {%Content%} 22 |
23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/assets/content.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | cnblogs 4 | 6 | 7 | 8 | 9 | 10 |
{%Content%}
11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/assets/font-big.css: -------------------------------------------------------------------------------- 1 | #content{ line-height:1.8; font-size:12pt;} 2 | pre{font-size:9pt;} 3 | -------------------------------------------------------------------------------- /app/src/main/assets/font-middle.css: -------------------------------------------------------------------------------- 1 | #content{ line-height:1.8; font-size:9pt;} 2 | pre{font-size:7pt;} 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/assets/font-small.css: -------------------------------------------------------------------------------- 1 | #content{ line-height:1.8; font-size:7pt;} 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/assets/style-day.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #777; 3 | font-family: Helvetica,"Microsoft Yahei",Verdana,Helvetica,SimSun,Arial,"Arial Unicode MS", MingLiu,PMingLiu,"MS Gothic",sans-serief; 4 | margin: 0 auto; 5 | } 6 | 7 | .pure-img-responsive { 8 | max-width: 100%; 9 | height: auto; 10 | } 11 | 12 | #layout { 13 | position: relative; 14 | padding-left: 0; 15 | } 16 | 17 | .content { 18 | margin: 0 auto; 19 | padding: 0 1em; 20 | max-width: 800px; 21 | margin-bottom: 50px; 22 | line-height: 1.6em; 23 | } 24 | 25 | .header { 26 | margin: 0 auto; 27 | color: #333; 28 | text-align: center; 29 | padding: 1em 1em 0; 30 | border-bottom: 1px solid #eee; 31 | background-color: #2196F3; 32 | color: #FFFFFF; 33 | } 34 | 35 | .header h1 { 36 | text-align: left; 37 | margin: 0.2em 0; 38 | font-size: 1.5em; 39 | font-weight: 300; 40 | } 41 | .header h2 { 42 | text-align: left; 43 | font-weight: 300; 44 | padding: 0; 45 | font-size: 0.8em; 46 | margin-top: 0; 47 | } 48 | 49 | p { 50 | margin-top: 0; 51 | margin-bottom: 5pt; 52 | line-height: 1.6em; 53 | } 54 | 55 | img { 56 | max-width: 90%; 57 | height: auto; 58 | } 59 | 60 | div.bimg { 61 | text-align: center; 62 | padding: 0; 63 | } 64 | 65 | audio { 66 | width: 100% 67 | } 68 | 69 | * { 70 | -webkit-touch-callout: none; 71 | /* prevent callout to copy image, etc when tap to hold */ 72 | /*-webkit-text-size-adjust: none;*/ /* prevent webkit from resizing text to fit */ 73 | -webkit-tap-highlight-color: rgba(0,0,0,0.15); 74 | /* make transparent link selection, adjust last value opacity 0 to 1.0 */ 75 | /*-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */ 76 | } -------------------------------------------------------------------------------- /app/src/main/assets/style-night.css: -------------------------------------------------------------------------------- 1 | body{font-family:Helvetica,"Microsoft Yahei",Verdana,Helvetica,SimSun,Arial,"Arial Unicode MS",MingLiu,PMingLiu,"MS Gothic",sans-serief;margin:0;padding:8px; background-color:#25262b; color:#8590A2;word-wrap:break-word;} 2 | a{ color:#1799ff;} 3 | p{margin-top:0;margin-bottom:5pt;line-height: 1.6em;} 4 | img{max-width:90%;height:auto;} 5 | div.bimg{text-align:center;padding:0;} 6 | audio{width:100%} 7 | *{-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */ 8 | /*-webkit-text-size-adjust: none;*/ /* prevent webkit from resizing text to fit */ 9 | -webkit-tap-highlight-color: rgba(0,0,0,0.0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */ 10 | /*-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */ 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.widget.DrawerLayout; 5 | import android.support.v7.app.ActionBarDrawerToggle; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.KeyEvent; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.widget.AdapterView; 12 | import android.widget.LinearLayout; 13 | import android.widget.ListView; 14 | 15 | import com.joanzapata.android.iconify.IconDrawable; 16 | import com.joanzapata.android.iconify.Iconify; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import tk.wlemuel.cotable.R; 22 | import tk.wlemuel.cotable.base.BaseActivity; 23 | import tk.wlemuel.cotable.core.AppConfig; 24 | import tk.wlemuel.cotable.model.DrawerMenu; 25 | import tk.wlemuel.cotable.ui.drawer.DrawerMenuAdapter; 26 | 27 | 28 | public class MainActivity extends BaseActivity { 29 | 30 | private Toolbar mActionBar; 31 | private DrawerLayout mDrawerLayout; 32 | private ActionBarDrawerToggle mDrawerToggle; 33 | 34 | private String[] mMenuTitles; 35 | private ListView mMenuListView; 36 | private LinearLayout mDrawerLeft; 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_main); 42 | 43 | initView(savedInstanceState); 44 | 45 | } 46 | 47 | private void initView(Bundle savedInstanceState) { 48 | initActionBar(); 49 | initSlidingMenu(); 50 | } 51 | 52 | /** 53 | * init the action bar. 54 | */ 55 | private void initActionBar() { 56 | 57 | mActionBar = (Toolbar) findViewById(R.id.actionBar); 58 | mActionBar.setTitle(R.string.app_name); 59 | setSupportActionBar(mActionBar); 60 | 61 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 62 | 63 | } 64 | 65 | private void initSlidingMenu() { 66 | List listMenuData = new ArrayList<>(); 67 | 68 | mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer); 69 | mDrawerLeft = (LinearLayout) findViewById(R.id.drawer_left); 70 | mDrawerToggle = new ActionBarDrawerToggle( 71 | this, mDrawerLayout, mActionBar, R.string.drawer_open, 72 | R.string.drawer_close); 73 | mDrawerToggle.syncState(); 74 | mDrawerLayout.setDrawerListener(mDrawerToggle); 75 | 76 | mMenuTitles = getResources().getStringArray(R.array.menu_array); 77 | mMenuListView = (ListView) findViewById(R.id.drawer_left_list); 78 | 79 | for (String data : mMenuTitles) { 80 | DrawerMenu itemData = new DrawerMenu(); 81 | itemData.setIcon("{fa-rss}"); 82 | itemData.setText(data); 83 | listMenuData.add(itemData); 84 | } 85 | 86 | mMenuListView.setAdapter(new DrawerMenuAdapter(this, listMenuData)); 87 | mMenuListView.setOnItemClickListener(new DrawerItemClickListener()); 88 | } 89 | 90 | 91 | @Override 92 | public boolean onCreateOptionsMenu(Menu menu) { 93 | // Inflate the menu; this adds items to the action bar if it is present. 94 | getMenuInflater().inflate(R.menu.menu_main, menu); 95 | 96 | menu.findItem(R.id.action_menu_search).setIcon( 97 | new IconDrawable(this, Iconify.IconValue.fa_search) 98 | .colorRes(R.color.toolbar_text_color) 99 | .sizeDp(AppConfig.SEARCH_ICON_SIZE_PATCH) 100 | ); 101 | 102 | menu.findItem(R.id.action_menu_favor).setIcon( 103 | new IconDrawable(this, Iconify.IconValue.fa_star) 104 | .colorRes(R.color.toolbar_text_color) 105 | .actionBarSize() 106 | ); 107 | 108 | return super.onCreateOptionsMenu(menu); 109 | } 110 | 111 | @Override 112 | public boolean onOptionsItemSelected(MenuItem item) { 113 | // Handle action bar item clicks here. The action bar will 114 | // automatically handle clicks on the Home/Up button, so long 115 | // as you specify a parent activity in AndroidManifest.xml. 116 | int id = item.getItemId(); 117 | 118 | //noinspection SimplifiableIfStatement 119 | switch (id) { 120 | case (R.id.action_menu_search): 121 | 122 | 123 | return true; 124 | case (R.id.action_menu_exit): 125 | if (!this.isFinishing()) 126 | this.finish(); 127 | } 128 | 129 | return super.onOptionsItemSelected(item); 130 | 131 | } 132 | 133 | @Override 134 | public boolean onKeyDown(int keyCode, KeyEvent event) { 135 | if ((keyCode == KeyEvent.KEYCODE_BACK)) { 136 | if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) { 137 | mDrawerLayout.closeDrawer(mDrawerLeft); 138 | return true; 139 | } 140 | } else if ((keyCode == KeyEvent.KEYCODE_MENU)) { 141 | if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) { 142 | mDrawerLayout.closeDrawer(mDrawerLeft); 143 | } else { 144 | mDrawerLayout.openDrawer(mDrawerLeft); 145 | } 146 | return true; 147 | } 148 | return super.onKeyDown(keyCode, event); 149 | } 150 | 151 | private void selectItem(int position) { 152 | // mMenuListView.setItemChecked(position, true); 153 | mDrawerLayout.closeDrawer(mDrawerLeft); 154 | } 155 | 156 | private class DrawerItemClickListener implements 157 | ListView.OnItemClickListener { 158 | @Override 159 | public void onItemClick(AdapterView parent, View view, int position, 160 | long id) { 161 | selectItem(position); 162 | } 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/News/adapter/NewsAdapter.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.News.adapter; 2 | 3 | /** 4 | * NewsAdapter 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc NewsAdapter 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public class NewsAdapter { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/News/fragment/NewsFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.News.fragment; 2 | 3 | /** 4 | * NewsFragment 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc NewsFragment 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public class NewsFragment { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.animation.AlphaAnimation; 7 | import android.view.animation.Animation; 8 | 9 | import tk.wlemuel.cotable.R; 10 | import tk.wlemuel.cotable.base.BaseActivity; 11 | import tk.wlemuel.cotable.utils.TDevice; 12 | 13 | 14 | public class SplashActivity extends BaseActivity { 15 | 16 | public static final int MAX_WAITING_TIME = 3000; // Wait for 3 seconds 17 | private static final String SPLASH_SCREEN = "SplashScreen"; 18 | protected boolean mShouldGoTo = true; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | 24 | TDevice.setFullScreen(this); 25 | 26 | final View view = View.inflate(this, R.layout.aty_splash_background, null); 27 | setContentView(view); 28 | 29 | 30 | AlphaAnimation aa = new AlphaAnimation(0.3f, 1.0f); 31 | aa.setDuration(MAX_WAITING_TIME); 32 | view.startAnimation(aa); 33 | aa.setAnimationListener(new Animation.AnimationListener() { 34 | 35 | @Override 36 | public void onAnimationEnd(Animation arg0) { 37 | if (mShouldGoTo) { 38 | redirectTo(); 39 | } 40 | } 41 | 42 | @Override 43 | public void onAnimationRepeat(Animation animation) { 44 | } 45 | 46 | @Override 47 | public void onAnimationStart(Animation animation) { 48 | } 49 | }); 50 | 51 | 52 | } 53 | 54 | private void redirectTo() { 55 | Intent intent = new Intent(this, MainActivity.class); 56 | 57 | startActivity(intent); 58 | finish(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/BlogTab.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog; 2 | 3 | import tk.wlemuel.cotable.R; 4 | import tk.wlemuel.cotable.activity.blog.fragment.BlogListFragment; 5 | import tk.wlemuel.cotable.model.BlogList; 6 | 7 | /** 8 | * BlogTab 9 | * 10 | * @author Steve Lemuel 11 | * @version 0.1 12 | * @desc BlogTab 13 | * @created 2015/05/10 14 | * @updated 2015/05/10 15 | */ 16 | public enum BlogTab { 17 | LASTEST(0, BlogList.CATALOG_LASTEST, R.string.tab_title_blog_latest, BlogListFragment.class), 18 | // RECOMMEND(1, BlogList.CATALOG_RECOMMEND, R.string.tab_title_blog_recommend, 19 | // BlogListFragment.class), 20 | NEWS(1, BlogList.CATALOG_RECOMMEND, R.string.tab_title_news_latest, BlogListFragment.class); 21 | 22 | private Class clz; 23 | private int idx; 24 | private int title; 25 | private int catalog; 26 | 27 | BlogTab(int idx, int catalog, int title, Class clz) { 28 | this.idx = idx; 29 | this.clz = clz; 30 | this.setCatalog(catalog); 31 | this.setTitle(title); 32 | } 33 | 34 | public static BlogTab getTabByIdx(int idx) { 35 | for (BlogTab t : values()) { 36 | if (t.getIdx() == idx) 37 | return t; 38 | } 39 | return LASTEST; 40 | } 41 | 42 | public Class getClz() { 43 | return clz; 44 | } 45 | 46 | public void setClz(Class clz) { 47 | this.clz = clz; 48 | } 49 | 50 | public int getIdx() { 51 | return idx; 52 | } 53 | 54 | public void setIdx(int idx) { 55 | this.idx = idx; 56 | } 57 | 58 | public int getTitle() { 59 | return title; 60 | } 61 | 62 | public void setTitle(int title) { 63 | this.title = title; 64 | } 65 | 66 | public int getCatalog() { 67 | return catalog; 68 | } 69 | 70 | public void setCatalog(int catalog) { 71 | this.catalog = catalog; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/adapter/BlogAdapter.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog.adapter; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.TextView; 6 | 7 | import de.hdodenhof.circleimageview.CircleImageView; 8 | import tk.wlemuel.cotable.R; 9 | import tk.wlemuel.cotable.base.BaseRecycleAdapter; 10 | import tk.wlemuel.cotable.model.Blog; 11 | import tk.wlemuel.cotable.utils.HtmlUtils; 12 | 13 | /** 14 | * BlogAdapter 15 | * 16 | * @author Steve Lemuel 17 | * @version 0.1 18 | * @desc BlogAdapter 19 | * @created 2015/05/08 20 | * @updated 2015/05/08 21 | */ 22 | public class BlogAdapter extends BaseRecycleAdapter { 23 | 24 | @Override 25 | protected View onCreateItemView(ViewGroup parent, int viewType) { 26 | return getLayoutInflater(parent.getContext()).inflate(R.layout.list_cell_blog, null); 27 | } 28 | 29 | @Override 30 | protected ViewHolder onCreateItemViewHolder(View view, int viewType) { 31 | return new ViewHolder(viewType, view); 32 | } 33 | 34 | @Override 35 | protected void onBindItemViewHolder(BaseRecycleAdapter.ViewHolder holder, int position) { 36 | ViewHolder vh = (ViewHolder) holder; 37 | 38 | Blog item = (Blog) mData.get(position); 39 | vh.mTitle.setText(HtmlUtils.filter(item.getTitle())); 40 | vh.mSummary.setText(HtmlUtils.filter(item.getSummary())); 41 | vh.mAuthorName.setText(item.getAuthor_name()); 42 | vh.mUpdated.setText(item.getUpdated()); 43 | vh.mComments.setText( 44 | vh.mComments.getContext().getString( 45 | R.string.blog_item_comments_default, item.getComments()) 46 | ); 47 | vh.mReads.setText( 48 | vh.mComments.getContext().getString( 49 | R.string.blog_item_reading_default, item.getReads()) 50 | ); 51 | setAuthorAvatar(item.getBlogapp(), vh.mAuthorAvatar); 52 | 53 | 54 | } 55 | 56 | private void setAuthorAvatar(String blogapp, final CircleImageView imageView) { 57 | // BlogApi.getAuthorAvatar(blogapp, new JsonHttpResponseHandler() { 58 | // @Override 59 | // public void onSuccess(int statusCode, Header[] headers, JSONObject response) { 60 | // try { 61 | // JSONObject info = (JSONObject) response.get("data"); 62 | // String avatar = info.getString("avatar"); 63 | // if (avatar != null && !avatar.equals("")) 64 | // ImageLoader.getInstance().displayImage(avatar, imageView); 65 | // 66 | // } catch (JSONException e) { 67 | // e.printStackTrace(); 68 | // } 69 | // } 70 | // 71 | // @Override 72 | // public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) { 73 | // super.onFailure(statusCode, headers, throwable, errorResponse); 74 | // } 75 | // }); 76 | // 77 | 78 | } 79 | 80 | static class ViewHolder extends BaseRecycleAdapter.ViewHolder { 81 | public TextView mTitle, mSummary, mAuthorName, mUpdated, mComments, mReads; 82 | public CircleImageView mAuthorAvatar; 83 | 84 | public ViewHolder(int viewType, View view) { 85 | super(viewType, view); 86 | 87 | mTitle = (TextView) view.findViewById(R.id.blog_title); 88 | mSummary = (TextView) view.findViewById(R.id.blog_summary); 89 | mAuthorName = (TextView) view.findViewById(R.id.blog_author_name); 90 | mUpdated = (TextView) view.findViewById(R.id.blog_updated); 91 | mComments = (TextView) view.findViewById(R.id.blog_comments); 92 | mReads = (TextView) view.findViewById(R.id.blog_reads); 93 | mAuthorAvatar = (CircleImageView) view.findViewById(R.id.blog_author_avatar); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/adapter/BlogTabPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog.adapter; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.view.ViewPager; 8 | 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | import tk.wlemuel.cotable.activity.blog.BlogTab; 13 | import tk.wlemuel.cotable.activity.blog.fragment.BlogListFragment; 14 | import tk.wlemuel.cotable.base.BaseTabFragment; 15 | import tk.wlemuel.cotable.ui.pagertab.SlidingTabPagerAdapter; 16 | 17 | /** 18 | * BlogTabPagerAdapter 19 | * 20 | * @author Steve Lemuel 21 | * @version 0.1 22 | * @desc BlogTabPagerAdapter 23 | * @created 2015/05/10 24 | * @updated 2015/05/10 25 | */ 26 | public final class BlogTabPagerAdapter extends SlidingTabPagerAdapter { 27 | public BlogTabPagerAdapter(FragmentManager mgr, Context context, 28 | ViewPager viewPager) { 29 | super(mgr, BlogTab.values().length, context.getApplicationContext(), 30 | viewPager); 31 | 32 | BlogTab[] tabs = BlogTab.values(); 33 | 34 | for (BlogTab tab : tabs) { 35 | Fragment fragment = null; 36 | List list = mgr.getFragments(); 37 | if (list != null) { 38 | Iterator iter = list.iterator(); 39 | while (iter.hasNext()) { 40 | fragment = iter.next(); 41 | if (fragment.getClass() == tab.getClz()) 42 | break; 43 | } 44 | } 45 | 46 | BaseTabFragment tabFragment = (BaseTabFragment) fragment; 47 | if (tabFragment == null) { 48 | try { 49 | tabFragment = (BaseTabFragment) tab.getClz().newInstance(); 50 | tabFragment.setCatalog(tab.getCatalog()); 51 | } catch (InstantiationException e) { 52 | e.printStackTrace(); 53 | } catch (IllegalAccessException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | tabFragment.addListener(this); 59 | if (!tabFragment.isAdded()) { 60 | Bundle args = new Bundle(); 61 | args.putInt(BlogListFragment.BUNDLE_KEY_CATALOG, 62 | tab.getCatalog()); 63 | tabFragment.setArguments(args); 64 | } 65 | fragments[tab.getIdx()] = tabFragment; 66 | } 67 | } 68 | 69 | public final int getCacheCount() { 70 | return 2; 71 | } 72 | 73 | public final int getCount() { 74 | return BlogTab.values().length; 75 | } 76 | 77 | public final CharSequence getPageTitle(int i) { 78 | BlogTab tab = BlogTab.getTabByIdx(i); 79 | int idx = 0; 80 | CharSequence title = ""; 81 | if (tab != null) 82 | idx = tab.getTitle(); 83 | if (idx != 0) 84 | title = context.getText(idx); 85 | return title; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/fragment/BlogListFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog.fragment; 2 | 3 | import android.view.View; 4 | 5 | import java.io.Serializable; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import tk.wlemuel.cotable.activity.blog.adapter.BlogAdapter; 10 | import tk.wlemuel.cotable.api.BlogApi; 11 | import tk.wlemuel.cotable.base.BaseRecycleAdapter; 12 | import tk.wlemuel.cotable.base.BaseRecycleViewFragment; 13 | import tk.wlemuel.cotable.core.AppContext; 14 | import tk.wlemuel.cotable.model.Blog; 15 | import tk.wlemuel.cotable.model.BlogList; 16 | import tk.wlemuel.cotable.model.ListEntity; 17 | import tk.wlemuel.cotable.utils.TLog; 18 | import tk.wlemuel.cotable.utils.UIHelper; 19 | 20 | /** 21 | * BlogListFragment 22 | * 23 | * @author Steve Lemuel 24 | * @version 0.1 25 | * @desc BlogListFragment 26 | * @created 2015/05/08 27 | * @updated 2015/05/08 28 | */ 29 | public class BlogListFragment extends BaseRecycleViewFragment { 30 | 31 | protected static final String TAG = BlogListFragment.class.getSimpleName(); 32 | 33 | private static final String CACHE_KEY_PREFIX = "BLOG_LIST"; 34 | 35 | // The max cache time set to be 12 hours 36 | private static final long MAX_CACAHE_TIME = 12 * 3600 * 1000; 37 | 38 | @Override 39 | protected boolean requestDataFromNetWork() { 40 | TLog.log(TAG, "requestDataFromNetwork"); 41 | return System.currentTimeMillis() 42 | - AppContext.getRefreshTime(getCacheKey()) > MAX_CACAHE_TIME; 43 | } 44 | 45 | @Override 46 | protected BaseRecycleAdapter getListAdapter() { 47 | return new BlogAdapter(); 48 | } 49 | 50 | @Override 51 | protected String getCacheKeyPrefix() { 52 | return CACHE_KEY_PREFIX; 53 | } 54 | 55 | @Override 56 | protected ListEntity parseList(String data) throws Exception { 57 | return BlogList.parse(data); 58 | } 59 | 60 | @Override 61 | protected ListEntity readList(Serializable seri) { 62 | return ((BlogList) seri); 63 | } 64 | 65 | @Override 66 | protected void sendRequestData() { 67 | if (mCatalog == BlogList.CATALOG_RECOMMEND) { 68 | BlogApi.getRecommendBlogList(mCurrentPage + 1, getResponseHandler()); 69 | } else { 70 | BlogApi.getBlogList(mCurrentPage + 1, getResponseHandler()); 71 | } 72 | } 73 | 74 | @Override 75 | public void onItemClick(View v, int position) { 76 | Blog blog = (Blog) mAdapter.getItem(position); 77 | 78 | Map blogInfo = new HashMap<>(); 79 | blogInfo.put(BlogDetailFragment.BUNDLE_KEY_BLOG_AUTHOR, blog.getAuthor_name()); 80 | blogInfo.put(BlogDetailFragment.BUNDLE_KEY_BLOG_TITLE, blog.getTitle()); 81 | blogInfo.put(BlogDetailFragment.BUNDLE_KEY_BLOG_POSTED, blog.getUpdated()); 82 | blogInfo.put(BlogDetailFragment.BUNDLE_KEY_BLOG_READS, blog.getReads() == 0 ? "0" : Integer 83 | .toString(blog.getReads())); 84 | blogInfo.put(BlogDetailFragment.BUNDLE_KEY_BLOG_ID, blog.getPostId()); 85 | 86 | 87 | if (blog != null) { 88 | UIHelper.showBlogDetail(getActivity(), blogInfo); 89 | } 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/fragment/BlogViewPagerFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.view.ViewPager; 7 | import android.support.v4.view.ViewPager.OnPageChangeListener; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import tk.wlemuel.cotable.R; 13 | import tk.wlemuel.cotable.activity.blog.adapter.BlogTabPagerAdapter; 14 | import tk.wlemuel.cotable.ui.pagertab.PagerSlidingTabStrip; 15 | 16 | /** 17 | * BlogViewPagerFragment 18 | * 19 | * @author Steve Lemuel 20 | * @version 0.1 21 | * @desc BlogViewPagerFragment 22 | * @created 2015/05/10 23 | * @updated 2015/05/10 24 | */ 25 | public class BlogViewPagerFragment extends Fragment implements 26 | OnPageChangeListener { 27 | 28 | private PagerSlidingTabStrip mTabStrip; 29 | private ViewPager mViewPager; 30 | private BlogTabPagerAdapter mTabAdapter; 31 | 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, 34 | @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 35 | View view = inflater.inflate(R.layout.fragment_viewpager, container, 36 | false); 37 | mTabStrip = (PagerSlidingTabStrip) view.findViewById(R.id.tabs); 38 | mViewPager = (ViewPager) view.findViewById(R.id.main_tab_pager); 39 | 40 | if (mViewPager.getAdapter() == null && 41 | mTabAdapter == null) { 42 | mTabAdapter = new BlogTabPagerAdapter(getChildFragmentManager(), 43 | getActivity(), mViewPager); 44 | } 45 | mViewPager.setOffscreenPageLimit(mTabAdapter.getCacheCount()); 46 | mViewPager.setAdapter(mTabAdapter); 47 | mViewPager.setOnPageChangeListener(this); 48 | mTabStrip.setViewPager(mViewPager); 49 | 50 | return view; 51 | } 52 | 53 | @Override 54 | public void onPageScrollStateChanged(int arg0) { 55 | mTabStrip.onPageScrollStateChanged(arg0); 56 | } 57 | 58 | @Override 59 | public void onPageScrolled(int arg0, float arg1, int arg2) { 60 | mTabStrip.onPageScrolled(arg0, arg1, arg2); 61 | mTabAdapter.onPageScrolled(arg0); 62 | } 63 | 64 | @Override 65 | public void onPageSelected(int arg0) { 66 | mTabStrip.onPageSelected(arg0); 67 | mTabAdapter.onPageSelected(arg0); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/blog/view/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.blog.view; 2 | 3 | import java.lang.ref.WeakReference; 4 | 5 | import tk.wlemuel.cotable.activity.common.SimpleBackActivity; 6 | import tk.wlemuel.cotable.base.BaseFragment; 7 | 8 | /** 9 | * DetailActivity 10 | * 11 | * @author Steve Lemuel 12 | * @version 0.1 13 | * @desc DetailActivity 14 | * @created 2015/05/11 15 | * @updated 2015/05/11 16 | */ 17 | public class DetailActivity extends SimpleBackActivity { 18 | 19 | public static final int DISPLAY_BLOG = 0; 20 | public static final int DIESPLAY_NEWS = 1; 21 | public static final String BUNDLE_KEY_DISPLAY_TYPE = "BUNDLE_KEY_DISPLAY_TYPE"; 22 | 23 | private WeakReference mFragment; 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/common/SimpleBackActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.common; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentTransaction; 7 | 8 | import java.lang.ref.WeakReference; 9 | 10 | import tk.wlemuel.cotable.R; 11 | import tk.wlemuel.cotable.base.BaseActivity; 12 | import tk.wlemuel.cotable.base.BaseFragment; 13 | import tk.wlemuel.cotable.model.SimpleBackPage; 14 | 15 | /** 16 | * SimpleBackActivity 17 | * 18 | * @author Steve Lemuel 19 | * @version 0.1 20 | * @desc SimpleBackActivity 21 | * @created 2015/05/11 22 | * @updated 2015/05/11 23 | */ 24 | public class SimpleBackActivity extends BaseActivity { 25 | 26 | public final static String BUNDLE_KEY_PAGE = "BUNDLE_KEY_PAGE"; 27 | public final static String BUNDLE_KEY_ARGS = "BUNDLE_KEY_ARGS"; 28 | private static final String TAG = SimpleBackActivity.class.getSimpleName(); 29 | private WeakReference mFragment; 30 | 31 | @Override 32 | protected int getLayoutRes() { 33 | return R.layout.aty_simple_fragment; 34 | } 35 | 36 | @Override 37 | protected boolean hasBackButton() { 38 | return true; 39 | } 40 | 41 | @Override 42 | protected boolean hasActionBar() { 43 | return true; 44 | } 45 | 46 | @Override 47 | protected void init(Bundle savedInstanceState) { 48 | super.init(savedInstanceState); 49 | 50 | Intent data = getIntent(); 51 | 52 | if (data == null) { 53 | throw new RuntimeException("You must specify a page info to display."); 54 | } 55 | 56 | int pageValue = data.getIntExtra(BUNDLE_KEY_PAGE, 0); 57 | SimpleBackPage page = SimpleBackPage.getPageByValue(pageValue); 58 | if (page == null) { 59 | throw new IllegalArgumentException("Can not find page by value: " + pageValue); 60 | } 61 | 62 | setActionBarTitle(page.getTitle()); 63 | 64 | try { 65 | Fragment fragment = (Fragment) page.getClz().newInstance(); 66 | 67 | Bundle args = data.getBundleExtra(BUNDLE_KEY_ARGS); 68 | if (args != null) { 69 | fragment.setArguments(args); 70 | } 71 | 72 | 73 | FragmentTransaction trans = getSupportFragmentManager() 74 | .beginTransaction(); 75 | trans.replace(R.id.container, fragment, TAG); 76 | trans.commit(); 77 | 78 | mFragment = new WeakReference(fragment); 79 | 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | throw new IllegalArgumentException( 83 | "generate fragment error. by value:" + pageValue); 84 | } 85 | } 86 | 87 | @Override 88 | public void onBackPressed() { 89 | if (mFragment != null && mFragment.get() != null 90 | && mFragment.get() instanceof BaseFragment) { 91 | BaseFragment bf = (BaseFragment) mFragment.get(); 92 | if (!bf.onBackPressed()) { 93 | super.onBackPressed(); 94 | } 95 | } else { 96 | super.onBackPressed(); 97 | } 98 | } 99 | 100 | @Override 101 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 102 | super.onActivityResult(requestCode, resultCode, data); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/image/ImagePreviewActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.image; 2 | 3 | /** 4 | * ImagePreviewActivity 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc ImagePreviewActivity 9 | * @created 2015/05/14 10 | * @updated 2015/05/14 11 | */ 12 | public class ImagePreviewActivity { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/settings/fragment/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.settings.fragment; 2 | 3 | import tk.wlemuel.cotable.base.BaseFragment; 4 | 5 | /** 6 | * AboutFragment 7 | * 8 | * @author Steve Lemuel 9 | * @version 0.1 10 | * @desc AboutFragment 11 | * @created 2015/05/12 12 | * @updated 2015/05/12 13 | */ 14 | public class AboutFragment extends BaseFragment { 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/settings/fragment/SettingFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.settings.fragment; 2 | 3 | /** 4 | * SettingFragment 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc SettingFragment 9 | * @created 2015/05/12 10 | * @updated 2015/05/12 11 | */ 12 | public class SettingFragment { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/view/CoScrollView.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.view; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.widget.ScrollView; 8 | 9 | /** 10 | * Created by Johnnyz Zhang on 2015/6/26. 11 | */ 12 | public class CoScrollView extends ScrollView { 13 | private float mLastMotionY; 14 | private int mInitialScrollCheckY; 15 | private boolean mIsMoving; 16 | private static final int SCROLL_CHECK_DELAY = 100; 17 | 18 | private ScrollDirectionListener mScrollDirectionListener; 19 | 20 | public CoScrollView(Context context) { 21 | super(context); 22 | } 23 | 24 | public CoScrollView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | } 27 | 28 | public CoScrollView(Context context, AttributeSet attrs, int defStyle) { 29 | super(context, attrs, defStyle); 30 | } 31 | 32 | public void setScrollDirectionListener(ScrollDirectionListener listener) { 33 | mScrollDirectionListener = listener; 34 | } 35 | 36 | @Override 37 | public boolean onTouchEvent(MotionEvent event) { 38 | if (mScrollDirectionListener != null) { 39 | int action = event.getAction() & MotionEvent.ACTION_MASK; 40 | 41 | switch (action) { 42 | case MotionEvent.ACTION_MOVE : 43 | if (mIsMoving) { 44 | int yDiff = (int) (event.getY() - mLastMotionY); 45 | if (yDiff < 0) { 46 | mScrollDirectionListener.onScrollDown(); 47 | } else if (yDiff > 0) { 48 | mScrollDirectionListener.onScrollUp(); 49 | } 50 | mLastMotionY = event.getY(); 51 | } else { 52 | mIsMoving = true; 53 | mLastMotionY = event.getY(); 54 | } 55 | break; 56 | 57 | case MotionEvent.ACTION_UP: 58 | if (mIsMoving) { 59 | mIsMoving = false; 60 | startScrollCheck(); 61 | } 62 | break; 63 | 64 | default : 65 | mIsMoving = false; 66 | break; 67 | } 68 | } 69 | 70 | return super.onTouchEvent(event); 71 | } 72 | 73 | private void startScrollCheck() { 74 | mInitialScrollCheckY = getScrollY(); 75 | post(mScrollTask); 76 | } 77 | 78 | private final Runnable mScrollTask = new Runnable() { 79 | @Override 80 | public void run() { 81 | if (mInitialScrollCheckY == getScrollY()) { 82 | if (mScrollDirectionListener != null) { 83 | mScrollDirectionListener.onScrollCompleted(); 84 | } 85 | } else { 86 | mInitialScrollCheckY = getScrollY(); 87 | postDelayed(mScrollTask, SCROLL_CHECK_DELAY); 88 | } 89 | } 90 | }; 91 | 92 | 93 | public boolean canScrollUp() { 94 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && canScrollVertically(-1); 95 | } 96 | public boolean canScrollDown() { 97 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && canScrollVertically(1); 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/activity/view/ScrollDirectionListener.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.activity.view; 2 | 3 | /** 4 | * Created by Administrator on 2015/6/26. 5 | */ 6 | public interface ScrollDirectionListener { 7 | public void onScrollUp(); 8 | public void onScrollDown(); 9 | public void onScrollCompleted(); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/api/ApiClientHelper.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.api; 2 | 3 | /** 4 | * ApiClientHelper 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc ApiClientHelper 9 | * @created 2015/05/08 10 | * @updated 2015/05/08 11 | */ 12 | public class ApiClientHelper { 13 | 14 | /** 15 | * Returns the user agent. 16 | * 17 | * @return User-agent 18 | */ 19 | public static String getUserAgent() { 20 | return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like " + 21 | "Gecko) Chrome/42.0.2311.135 Safari/537.36"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/api/BaseApi.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.api; 2 | 3 | import tk.wlemuel.cotable.core.AppConfig; 4 | 5 | /** 6 | * BaseApi 7 | * 8 | * @author Steve Lemuel 9 | * @version 0.1 10 | * @desc BaseApi 11 | * @created 2015/05/08 12 | * @updated 2015/05/08 13 | */ 14 | public class BaseApi { 15 | 16 | public static final String TAG = BaseApi.class.getSimpleName(); 17 | 18 | public static final String HOST = "cnblogs.davismy.com"; 19 | public static final String DEFAULT_API_URL = "cnblogs.davismy.com/Handler.ashx?op=%s"; 20 | 21 | protected static final String UTF8 = AppConfig.UTF8; 22 | protected final static String FLAG_ITEMCOUNT = "{ITEMCOUNT}"; 23 | protected final static String FLAG_CONTENTID = "{CONTENTID}"; 24 | protected final static String FLAG_PAGEINDEX = "{PAGEINDEX}"; 25 | protected final static String FLAG_PAGESIZE = "{PAGESIZE}"; 26 | protected final static String FLAG_BLOGAPP = "{BLOGAPP}"; 27 | protected final static String FLAG_POSTID = "{POSTID}"; 28 | protected final static String FLAG_TERM = "{TERM}"; 29 | // Api (NEWS) 30 | 31 | 32 | // Api (BLOG) 33 | protected final static String RECOMMEND_BLOGS_PAGED = "GetTimeLine&page={PAGEINDEX}"; 34 | protected final static String RECENT_BLOGS_PAGED = "GetTimeLine&page={PAGEINDEX}"; 35 | protected final static String BLOG_CONTENTS = "GetBlogContent&blog_id={POSTID}"; 36 | 37 | protected final static String GET_USER_INFO = "GetUserInfo&blogapp={BLOGAPP}"; 38 | 39 | protected static String API_URL = DEFAULT_API_URL; 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/api/BlogApi.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.api; 2 | 3 | import com.loopj.android.http.AsyncHttpResponseHandler; 4 | 5 | import tk.wlemuel.cotable.core.AppConfig; 6 | import tk.wlemuel.cotable.utils.TLog; 7 | 8 | /** 9 | * BlogApi 10 | * 11 | * @author Steve Lemuel 12 | * @version 0.1 13 | * @desc BlogApi 14 | * @created 2015/05/09 15 | * @updated 2015/05/09 16 | */ 17 | public class BlogApi extends BaseApi { 18 | 19 | public static final String TAG = BlogApi.class.getSimpleName(); 20 | 21 | public static void getBlogList(int page, AsyncHttpResponseHandler handler) { 22 | 23 | String relativeUrl = RECENT_BLOGS_PAGED.replace(FLAG_PAGEINDEX, Integer.toString(page)) 24 | .replace(FLAG_PAGESIZE, Integer.toString(AppConfig.DEFAULT_PAGE_SIZE)); 25 | 26 | TLog.log("Start request data with the method of getBlogList"); 27 | 28 | ApiHttpClient.get(relativeUrl, handler); 29 | } 30 | 31 | public static void getRecommendBlogList(int page, AsyncHttpResponseHandler handler) { 32 | 33 | String partUrl = RECOMMEND_BLOGS_PAGED.replace(FLAG_PAGEINDEX, Integer.toString(page)) 34 | .replace(FLAG_PAGESIZE, Integer.toString(AppConfig.DEFAULT_PAGE_SIZE)); 35 | 36 | ApiHttpClient.get(partUrl, handler); 37 | } 38 | 39 | public static void getBlogDetail(String postId, AsyncHttpResponseHandler handler) { 40 | String partUrl = BLOG_CONTENTS.replace(FLAG_POSTID, postId); 41 | 42 | ApiHttpClient.get(partUrl, handler); 43 | } 44 | 45 | public static void getAuthorAvatar(String blogapp, AsyncHttpResponseHandler handler) { 46 | String partUrl = GET_USER_INFO.replace(FLAG_BLOGAPP, blogapp); 47 | 48 | ApiHttpClient.get(partUrl, handler); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/api/NewsApi.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.api; 2 | 3 | /** 4 | * NewsApi 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc NewsApi 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public class NewsApi extends BaseApi{ 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBarActivity; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.LayoutInflater; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.view.Window; 11 | 12 | import tk.wlemuel.cotable.R; 13 | import tk.wlemuel.cotable.utils.TDevice; 14 | 15 | /** 16 | * BaseActivity 17 | * 18 | * @author Steve Lemuel 19 | * @version 0.1 20 | * @desc BaseActivity 21 | * @created 2015/05/11 22 | * @updated 2015/05/11 23 | */ 24 | public abstract class BaseActivity extends ActionBarActivity { 25 | 26 | protected LayoutInflater mInflater; 27 | private Toolbar mActionBar; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | 33 | if (!hasActionBar()) { 34 | supportRequestWindowFeature(Window.FEATURE_NO_TITLE); 35 | } 36 | 37 | onBeforeSetContentLayout(); 38 | 39 | if (getLayoutRes() != 0) 40 | setContentView(getLayoutRes()); 41 | 42 | mActionBar = (Toolbar) findViewById(R.id.actionBar); 43 | mInflater = getLayoutInflater(); 44 | 45 | if (hasActionBar()) 46 | initActionBar(mActionBar); 47 | 48 | init(savedInstanceState); 49 | 50 | } 51 | 52 | @Override 53 | protected void onDestroy() { 54 | super.onDestroy(); 55 | } 56 | 57 | protected void onBeforeSetContentLayout() { 58 | 59 | } 60 | 61 | protected boolean hasActionBar() { 62 | return true; 63 | } 64 | 65 | protected int getLayoutRes() { 66 | return 0; 67 | } 68 | 69 | protected View inflateView(int resId) { 70 | return mInflater.inflate(resId, null); 71 | } 72 | 73 | protected int getActionBarTitle() { 74 | return R.string.app_name; 75 | } 76 | 77 | public void setActionBarTitle(String title) { 78 | if (hasActionBar()) { 79 | if (mActionBar != null) 80 | mActionBar.setTitle(title); 81 | } 82 | 83 | if (getSupportActionBar() != null) 84 | getSupportActionBar().setTitle(title); 85 | } 86 | 87 | protected boolean hasBackButton() { 88 | return false; 89 | } 90 | 91 | protected int getActionBarCustomView() { 92 | return 0; 93 | } 94 | 95 | protected void init(Bundle savedInstanceState) { 96 | 97 | } 98 | 99 | protected void initActionBar(Toolbar actionBar) { 100 | if (actionBar == null) return; 101 | 102 | setSupportActionBar(actionBar); 103 | 104 | if (hasBackButton()) { 105 | int layoutRes = getActionBarCustomView(); 106 | if (layoutRes != 0) { 107 | View view = inflateView(layoutRes); 108 | Toolbar.LayoutParams params = new Toolbar.LayoutParams(ViewGroup.LayoutParams 109 | .MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 110 | } 111 | 112 | int titleRes = getActionBarTitle(); 113 | 114 | if (titleRes != 0) { 115 | actionBar.setTitle(titleRes); 116 | } 117 | 118 | actionBar.setNavigationIcon(R.drawable.actionbar_back_icon_normal); 119 | actionBar.setNavigationOnClickListener(new View.OnClickListener() { 120 | @Override 121 | public void onClick(View v) { 122 | onBackPressed(); 123 | } 124 | }); 125 | 126 | actionBar.setPadding(0, 0, 0, 0); 127 | } else { 128 | int titleRes = getActionBarTitle(); 129 | if (titleRes != 0) { 130 | actionBar.setTitle(titleRes); 131 | } 132 | 133 | actionBar.setPadding((int) TDevice.dpToPixel(16), 0, 0, 0); 134 | 135 | } 136 | } 137 | 138 | public void setActionBarTitle(int resId) { 139 | if (resId != 0) 140 | setActionBarTitle(getString(resId)); 141 | } 142 | 143 | @Override 144 | public boolean onOptionsItemSelected(MenuItem item) { 145 | switch (item.getItemId()) { 146 | case android.R.id.home: 147 | onBackPressed(); 148 | break; 149 | 150 | default: 151 | break; 152 | } 153 | return super.onOptionsItemSelected(item); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.base; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.view.View; 5 | 6 | 7 | public abstract class BaseFragment extends Fragment implements View.OnClickListener { 8 | protected static final int STATE_NONE = 0; 9 | protected static final int STATE_REFRESH = 1; 10 | protected static final int STATE_LOADMORE = 2; 11 | protected int mState = STATE_NONE; 12 | 13 | @Override 14 | public void onClick(View v) { 15 | 16 | } 17 | 18 | /** 19 | * Listener the back key click event. 20 | * 21 | * @return false (default) 22 | */ 23 | public boolean onBackPressed() { 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/base/BaseTabFragment.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.base; 2 | 3 | import tk.wlemuel.cotable.model.BlogList; 4 | 5 | public abstract class BaseTabFragment extends BaseFragment { 6 | 7 | protected int mCatalog = BlogList.CATALOG_LASTEST; 8 | private TabChangedListener mListener; 9 | 10 | public BaseTabFragment() { 11 | } 12 | 13 | public void setCatalog(int catalog) { 14 | mCatalog = catalog; 15 | } 16 | 17 | public final void addListener(TabChangedListener listener) { 18 | mListener = listener; 19 | } 20 | 21 | protected final boolean e() { 22 | return mListener.isCurrent(this); 23 | } 24 | 25 | public void f() { 26 | } 27 | 28 | public void g() { 29 | } 30 | 31 | public void h() { 32 | } 33 | 34 | public void i() { 35 | } 36 | 37 | public interface TabChangedListener { 38 | 39 | boolean isCurrent(BaseTabFragment fragment); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/cache/CacheManager.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.cache; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.InvalidClassException; 10 | import java.io.ObjectInputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.io.Serializable; 13 | 14 | /** 15 | * CacheManager 16 | * 17 | * @author Steve Lemuel 18 | * @version 0.1 19 | * @desc CacheManager 20 | * @created 2015/05/09 21 | * @updated 2015/05/09 22 | */ 23 | public class CacheManager { 24 | 25 | /** 26 | * Save the object 27 | * 28 | * @param context context 29 | * @param ser serializable object 30 | * @param file cache file 31 | * @throws java.io.IOException IOException 32 | */ 33 | @SuppressWarnings("JavaDoc") 34 | public static boolean saveObject(Context context, Serializable ser, 35 | String file) { 36 | FileOutputStream fos = null; 37 | ObjectOutputStream oos = null; 38 | try { 39 | fos = context.openFileOutput(file, Context.MODE_PRIVATE); 40 | oos = new ObjectOutputStream(fos); 41 | oos.writeObject(ser); 42 | oos.flush(); 43 | return true; 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | return false; 47 | } finally { 48 | try { 49 | if (oos != null) oos.close(); 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | try { 54 | if (fos != null) fos.close(); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * Read the object 63 | * 64 | * @param context context 65 | * @param file cache file 66 | * @return serializable object 67 | * @throws java.io.IOException Exception 68 | */ 69 | @SuppressWarnings("JavaDoc") 70 | public static Serializable readObject(Context context, String file) { 71 | if (!isExistDataCache(context, file)) 72 | return null; 73 | FileInputStream fis = null; 74 | ObjectInputStream ois = null; 75 | try { 76 | fis = context.openFileInput(file); 77 | ois = new ObjectInputStream(fis); 78 | return (Serializable) ois.readObject(); 79 | } catch (FileNotFoundException e) { 80 | e.printStackTrace(); 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | // Delete the cache file if the deserialization failed. 84 | if (e instanceof InvalidClassException) { 85 | File data = context.getFileStreamPath(file); 86 | //noinspection ResultOfMethodCallIgnored 87 | data.delete(); 88 | } 89 | } finally { 90 | try { 91 | if (ois != null) ois.close(); 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } 95 | try { 96 | if (fis != null) fis.close(); 97 | } catch (Exception e) { 98 | e.printStackTrace(); 99 | } 100 | } 101 | return null; 102 | } 103 | 104 | /** 105 | * Judge whether the cache file is readable. 106 | * 107 | * @param context context 108 | * @param cachefile cache file 109 | * @return true if the cache file is readable, false otherwise. 110 | */ 111 | public static boolean isReadDataCache(Context context, String cachefile) { 112 | return readObject(context, cachefile) != null; 113 | } 114 | 115 | /** 116 | * Juget whether the cache file exists. 117 | * 118 | * @param context context 119 | * @param cachefile cache file 120 | * @return true if the cache data exists, false otherwise. 121 | */ 122 | public static boolean isExistDataCache(Context context, String cachefile) { 123 | if (context == null) 124 | return false; 125 | boolean exist = false; 126 | File data = context.getFileStreamPath(cachefile); 127 | if (data.exists()) 128 | exist = true; 129 | return exist; 130 | } 131 | 132 | 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/core/AppConfig.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.core; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Environment; 6 | import android.preference.PreferenceManager; 7 | 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileOutputStream; 11 | import java.util.Properties; 12 | 13 | /** 14 | * AppConfig 15 | * 16 | * @author Steve Lemuel 17 | * @version 0.1 18 | * @desc AppConfig 19 | * @created 2015/05/08 20 | * @updated 2015/05/08 21 | */ 22 | public class AppConfig { 23 | 24 | public final static String TAG = AppConfig.class.getSimpleName(); 25 | 26 | public final static String APP_CONFIG = "config"; 27 | public final static String APP_NAME = "Cotable"; 28 | public final static String UTF8 = "utf-8"; 29 | public final static int DEFAULT_PAGE_SIZE = 20; 30 | 31 | // Set the image and cache directory. 32 | public final static String DOWNLOAD_IMAGE_DIR = "image"; 33 | public final static String SAVE_IMAGE_PATH = "SAVE_IMAGE_PATH"; 34 | public final static String DEFAULT_IMAGE_PATH = Environment.getExternalStorageDirectory() + 35 | File.separator + APP_NAME + File.separator + DOWNLOAD_IMAGE_DIR + File.separator; 36 | 37 | public final static String CONF_LOAD_IMAGE = "CONF_LOAD_IMAGE"; 38 | public final static String CONF_PAGE_SIZE = "CONF_PAGE_SIZE"; 39 | 40 | // Other configurations 41 | public final static int SEARCH_ICON_SIZE_PATCH = 20; 42 | public final static String LOCAL_PATH = "file:///android_asset/"; 43 | 44 | private static AppConfig appConfig; 45 | private Context mContext; 46 | 47 | public static AppConfig getAppConfig() { 48 | if (appConfig == null) appConfig = new AppConfig(); 49 | 50 | return appConfig; 51 | } 52 | 53 | public static AppConfig getAppConfig(Context context) { 54 | getAppConfig().mContext = context; 55 | return appConfig; 56 | } 57 | 58 | public static SharedPreferences getSharedPreferences(Context context) { 59 | return PreferenceManager.getDefaultSharedPreferences(context); 60 | } 61 | 62 | public static boolean isLoadImage(Context context) { 63 | return getSharedPreferences(context).getBoolean(CONF_LOAD_IMAGE, true); 64 | } 65 | 66 | public static int getPageSize(Context context) { 67 | return getSharedPreferences(context).getInt(CONF_PAGE_SIZE, DEFAULT_PAGE_SIZE); 68 | } 69 | 70 | 71 | public String get(String key) { 72 | Properties props = get(); 73 | return (props == null) ? null : props.getProperty(key); 74 | } 75 | 76 | public Properties get() { 77 | FileInputStream fis = null; 78 | Properties props = new Properties(); 79 | 80 | File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_MULTI_PROCESS); 81 | try { 82 | fis = new FileInputStream(dirConf.getPath() + File.separator + APP_CONFIG); 83 | props.load(fis); 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | } finally { 87 | try { 88 | if (fis != null) fis.close(); 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | 94 | return props; 95 | } 96 | 97 | private void setProps(Properties props) { 98 | FileOutputStream fos = null; 99 | try { 100 | File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_MULTI_PROCESS); 101 | File conf = new File(dirConf, APP_CONFIG); 102 | fos = new FileOutputStream(conf); 103 | 104 | props.store(fos, null); 105 | fos.flush(); 106 | } catch (Exception e) { 107 | e.printStackTrace(); 108 | } finally { 109 | try { 110 | if (fos != null) fos.close(); 111 | } catch (Exception e) { 112 | e.printStackTrace(); 113 | } 114 | 115 | } 116 | } 117 | 118 | public void set(Properties p) { 119 | Properties props = get(); 120 | props.putAll(p); 121 | setProps(props); 122 | } 123 | 124 | public void set(String key, String value) { 125 | Properties props = get(); 126 | props.put(key, value); 127 | setProps(props); 128 | } 129 | 130 | public void remove(String... keys) { 131 | Properties props = get(); 132 | for (String key : keys) 133 | props.remove(key); 134 | 135 | setProps(props); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/core/AppException.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.core; 2 | 3 | /** 4 | * AppException 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc AppException 9 | * @created 2015/05/20 10 | * @updated 2015/05/20 11 | */ 12 | public class AppException { 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/core/AppManager.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.core; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.content.Context; 6 | 7 | import java.util.Stack; 8 | 9 | /** 10 | * AppManager 11 | * 12 | * @author Steve Lemuel 13 | * @version 0.1 14 | * @desc Manage the activities of current application. 15 | * @created 2015/05/18 16 | * @updated 2015/05/18 17 | */ 18 | public class AppManager { 19 | 20 | private static Stack mActivityStack; 21 | private static AppManager mInstance; 22 | 23 | private AppManager() { 24 | } 25 | 26 | 27 | /** 28 | * Simple Singleton Design pattern. 29 | * 30 | * @return {@code AppManager} 31 | */ 32 | public static AppManager getAppManager() { 33 | if (mInstance == null) mInstance = new AppManager(); 34 | 35 | return mInstance; 36 | } 37 | 38 | /** 39 | * Add activity to the stack. 40 | * 41 | * @param activity activity 42 | */ 43 | public void addActivity(Activity activity) { 44 | if (mActivityStack == null) mActivityStack = new Stack<>(); 45 | 46 | mActivityStack.add(activity); 47 | } 48 | 49 | /** 50 | * Returns the current activity at the top of stack. 51 | * 52 | * @return Activity if the stack exists, null otherwise. 53 | */ 54 | public Activity currentActivity() { 55 | if (mActivityStack == null) return null; 56 | return mActivityStack.lastElement(); 57 | } 58 | 59 | /** 60 | * Finish the given activity. 61 | * 62 | * @param activity given activity. 63 | */ 64 | public void finishActivity(Activity activity) { 65 | if (mActivityStack != null && activity != null) { 66 | mActivityStack.remove(activity); 67 | activity.finish(); 68 | } 69 | } 70 | 71 | /** 72 | * Finish the current activity. 73 | */ 74 | public void finishActivity() { 75 | finishActivity(currentActivity()); 76 | } 77 | 78 | /** 79 | * Finish the activities according to the given class type. 80 | * 81 | * @param clz the class type 82 | */ 83 | public void finishActivity(Class clz) { 84 | if (mActivityStack == null) return; 85 | 86 | for (Activity activity : mActivityStack) { 87 | if (activity.getClass().equals(clz)) 88 | finishActivity(activity); 89 | } 90 | } 91 | 92 | /** 93 | * Finish all the activities. 94 | */ 95 | public void finishAllActivities() { 96 | if (mActivityStack == null) return; 97 | 98 | for (Activity activity : mActivityStack) { 99 | if (null != activity) 100 | finishActivity(activity); 101 | } 102 | } 103 | 104 | /** 105 | * Exit the application. 106 | * 107 | * @param context given context 108 | */ 109 | public void AppExit(Context context) { 110 | try { 111 | finishAllActivities(); 112 | ActivityManager activityManager = (ActivityManager) context.getSystemService(Context 113 | .ACTIVITY_SERVICE); 114 | activityManager.restartPackage(context.getPackageName()); 115 | System.exit(0); 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/Base.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Base 7 | * 8 | * @author Steve Lemuel 9 | * @version 0.1 10 | * @desc Base 11 | * @created 2015/05/09 12 | * @updated 2015/05/09 13 | */ 14 | public abstract class Base implements Serializable { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/BlogDetail.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | import org.json.JSONObject; 4 | import org.json.JSONTokener; 5 | 6 | /** 7 | * BlogDetail 8 | * 9 | * @author Steve Lemuel 10 | * @version 0.1 11 | * @desc BlogDetail 12 | * @created 2015/05/11 13 | * @updated 2015/05/11 14 | */ 15 | public class BlogDetail extends Entity { 16 | 17 | private final static String TAG_BODY = "string"; 18 | 19 | private String postId; 20 | 21 | private String body; 22 | 23 | public BlogDetail(String postId, String body) { 24 | setPostId(postId); 25 | setBody(body); 26 | } 27 | 28 | public static BlogDetail parse(String data) { 29 | BlogDetail blog = new BlogDetail("", "

Hello, I'm Lemuel.

"); 30 | 31 | 32 | if (data != null && !data.equals("")) { 33 | 34 | try { 35 | JSONTokener jsonParser = new JSONTokener(data); 36 | 37 | JSONObject content = (JSONObject) jsonParser.nextValue(); 38 | blog.setBody(content.getString("data")); 39 | 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | return blog; 46 | 47 | } 48 | 49 | public String getPostId() { 50 | return postId; 51 | } 52 | 53 | public void setPostId(String postId) { 54 | this.postId = postId; 55 | } 56 | 57 | public String getBody() { 58 | return body; 59 | } 60 | 61 | public void setBody(String body) { 62 | this.body = body; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/BlogList.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * BlogList 8 | * 9 | * @author Steve Lemuel 10 | * @version 0.1 11 | * @desc BlogList 12 | * @created 2015/05/09 13 | * @updated 2015/05/09 14 | */ 15 | public class BlogList extends Entity implements ListEntity { 16 | 17 | public static final int CATALOG_LASTEST = 1; 18 | public static final int CATALOG_RECOMMEND = 2; 19 | 20 | public static final String TYPE_LASTEST = "BLOG_LASTEST"; 21 | public static final String TYPE_RECOMMEND = "BLOG_RECOMMEND"; 22 | 23 | private List bloglist = new ArrayList<>(); 24 | private int pageSize; 25 | private int blogCount; 26 | 27 | public static BlogList parse(String data) { 28 | BlogList bloglist = new BlogList(); 29 | bloglist.getBloglist().addAll(Blog.parse(data)); 30 | return bloglist; 31 | } 32 | 33 | public int getPageSize() { 34 | return pageSize; 35 | } 36 | 37 | public int getBlogCount() { 38 | return blogCount; 39 | } 40 | 41 | public List getBloglist() { 42 | return bloglist; 43 | } 44 | 45 | @Override 46 | public List getList() { 47 | return bloglist; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/DrawerMenu.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | 4 | public class DrawerMenu extends Entity { 5 | private String icon; 6 | private String text; 7 | 8 | 9 | public String getIcon() { 10 | return icon; 11 | } 12 | 13 | public void setIcon(String icon) { 14 | this.icon = icon; 15 | } 16 | 17 | public String getText() { 18 | return text; 19 | } 20 | 21 | public void setText(String text) { 22 | this.text = text; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/Entity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | /** 4 | * Entity 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc Entity 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public abstract class Entity extends Base { 13 | 14 | protected int id; 15 | protected String cacheKey; 16 | 17 | public int getId() { 18 | return id; 19 | } 20 | 21 | public void setId(int id) { 22 | this.id = id; 23 | } 24 | 25 | public String getCacheKey() { 26 | return cacheKey; 27 | } 28 | 29 | public void setCacheKey(String cacheKey) { 30 | this.cacheKey = cacheKey; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/ListEntity.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * ListEntity 8 | * 9 | * @author Steve Lemuel 10 | * @version 0.1 11 | * @desc ListEntity 12 | * @created 2015/05/09 13 | * @updated 2015/05/09 14 | */ 15 | public interface ListEntity extends Serializable { 16 | 17 | List getList(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/News.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | /** 4 | * News 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc News 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public class News extends Base{ 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/model/SimpleBackPage.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.model; 2 | 3 | import tk.wlemuel.cotable.R; 4 | import tk.wlemuel.cotable.activity.blog.fragment.BlogDetailFragment; 5 | import tk.wlemuel.cotable.activity.settings.fragment.AboutFragment; 6 | import tk.wlemuel.cotable.activity.settings.fragment.SettingFragment; 7 | 8 | /** 9 | * SimpleBackPage 10 | * 11 | * @author Steve Lemuel 12 | * @version 0.1 13 | * @desc SimpleBackPage 14 | * @created 2015/05/12 15 | * @updated 2015/05/12 16 | */ 17 | public enum SimpleBackPage { 18 | 19 | SETTING(0, R.string.actionbar_title_setting, SettingFragment.class), 20 | ABOUT(1, R.string.actionbar_title_about, AboutFragment.class), 21 | DETAILS(2, R.string.actionbar_title_blogdetail, BlogDetailFragment.class); 22 | 23 | private int title; 24 | private Class clz; 25 | private int value; 26 | 27 | SimpleBackPage(int value, int title, Class clz) { 28 | this.title = title; 29 | this.clz = clz; 30 | this.value = value; 31 | } 32 | 33 | public static SimpleBackPage getPageByValue(int value) { 34 | for (SimpleBackPage p : values()) { 35 | if (p.getValue() == value) { 36 | return p; 37 | } 38 | } 39 | 40 | return null; 41 | } 42 | 43 | public int getTitle() { 44 | return title; 45 | } 46 | 47 | public void setTitle(int title) { 48 | this.title = title; 49 | } 50 | 51 | public Class getClz() { 52 | return clz; 53 | } 54 | 55 | public void setClz(Class clz) { 56 | this.clz = clz; 57 | } 58 | 59 | public int getValue() { 60 | return value; 61 | } 62 | 63 | public void setValue(int value) { 64 | this.value = value; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/customWidget/CircleImageView.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.customWidget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.PaintFlagsDrawFilter; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.graphics.RectF; 13 | import android.util.AttributeSet; 14 | import android.view.View; 15 | 16 | /** 17 | * Created by stevelemuel on 4/12/15. 18 | */ 19 | public class CircleImageView extends View { 20 | private Bitmap bitmap; 21 | private Rect bitmapRect = new Rect(); 22 | private PaintFlagsDrawFilter pdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 23 | private Paint paint = new Paint(); 24 | 25 | { 26 | paint.setStyle(Paint.Style.STROKE); 27 | paint.setFlags(Paint.ANTI_ALIAS_FLAG); 28 | paint.setAntiAlias(true);// 设置画笔的锯齿效果。 true是去除,大家一看效果就明白了 29 | } 30 | 31 | private Bitmap mDstB = null; 32 | private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY); 33 | 34 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 35 | super(context, attrs, defStyle); 36 | init(); 37 | } 38 | 39 | public CircleImageView(Context context, AttributeSet attrs) { 40 | super(context, attrs); 41 | init(); 42 | } 43 | 44 | public CircleImageView(Context context) { 45 | super(context); 46 | init(); 47 | } 48 | 49 | private void init() { 50 | try { 51 | if (android.os.Build.VERSION.SDK_INT >= 11) { 52 | setLayerType(LAYER_TYPE_SOFTWARE, null); 53 | } 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | public void setImageBitmap(Bitmap bitmap) { 60 | this.bitmap = bitmap; 61 | } 62 | 63 | private Bitmap makeDst(int w, int h) { 64 | Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 65 | Canvas c = new Canvas(bm); 66 | Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); 67 | p.setColor(Color.parseColor("#ffffffff")); 68 | c.drawOval(new RectF(0, 0, w, h), p); 69 | return bm; 70 | } 71 | 72 | @Override 73 | protected void onDraw(Canvas canvas) { 74 | 75 | if (null == bitmap) { 76 | return; 77 | } 78 | if (null == mDstB) { 79 | mDstB = makeDst(getWidth(), getHeight()); 80 | } 81 | 82 | bitmapRect.set(0, 0, getWidth(), getHeight()); 83 | canvas.save(); 84 | canvas.setDrawFilter(pdf); 85 | canvas.drawBitmap(mDstB, 0, 0, paint); 86 | paint.setXfermode(xfermode); 87 | canvas.drawBitmap(bitmap, null, bitmapRect, paint); 88 | paint.setXfermode(null); 89 | canvas.restore(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/decorator/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.decorator; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.support.v4.view.ViewCompat; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.view.View; 12 | 13 | /** 14 | * DividerItemDecoration 15 | * 16 | * @author Steve Lemuel 17 | * @version 0.1 18 | * @desc DividerItemDecoration 19 | * @created 2015/05/10 20 | * @updated 2015/05/10 21 | */ 22 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 23 | 24 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 25 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 26 | private static final int[] ATTRS = new int[]{ 27 | android.R.attr.listDivider 28 | }; 29 | private Drawable mDivider; 30 | 31 | private int mOrientation; 32 | 33 | public DividerItemDecoration(Context context, int orientation) { 34 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 35 | mDivider = a.getDrawable(0); 36 | a.recycle(); 37 | setOrientation(orientation); 38 | } 39 | 40 | public void setOrientation(int orientation) { 41 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 42 | throw new IllegalArgumentException("invalid orientation"); 43 | } 44 | mOrientation = orientation; 45 | } 46 | 47 | @Override 48 | public void onDraw(Canvas c, RecyclerView parent) { 49 | if (mOrientation == VERTICAL_LIST) { 50 | drawVertical(c, parent); 51 | } else { 52 | drawHorizontal(c, parent); 53 | } 54 | } 55 | 56 | public void drawVertical(Canvas c, RecyclerView parent) { 57 | final int left = parent.getPaddingLeft(); 58 | final int right = parent.getWidth() - parent.getPaddingRight(); 59 | 60 | final int childCount = parent.getChildCount(); 61 | for (int i = 0; i < childCount; i++) { 62 | final View child = parent.getChildAt(i); 63 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 64 | .getLayoutParams(); 65 | final int top = child.getBottom() + params.bottomMargin + 66 | Math.round(ViewCompat.getTranslationY(child)); 67 | final int bottom = top + mDivider.getIntrinsicHeight(); 68 | mDivider.setBounds(left, top, right, bottom); 69 | mDivider.draw(c); 70 | } 71 | } 72 | 73 | public void drawHorizontal(Canvas c, RecyclerView parent) { 74 | final int top = parent.getPaddingTop(); 75 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 76 | 77 | final int childCount = parent.getChildCount(); 78 | for (int i = 0; i < childCount; i++) { 79 | final View child = parent.getChildAt(i); 80 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 81 | .getLayoutParams(); 82 | final int left = child.getRight() + params.rightMargin + 83 | Math.round(ViewCompat.getTranslationX(child)); 84 | final int right = left + mDivider.getIntrinsicHeight(); 85 | mDivider.setBounds(left, top, right, bottom); 86 | mDivider.draw(c); 87 | } 88 | } 89 | 90 | @Override 91 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { 92 | if (mOrientation == VERTICAL_LIST) { 93 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 94 | } else { 95 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/dialog/DialogControl.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.dialog; 2 | 3 | /** 4 | * Created by stevelemuel on 4/17/15. 5 | */ 6 | public interface DialogControl { 7 | 8 | public abstract void hideWaitDialog(); 9 | 10 | public abstract WaitDialog showWaitDialog(); 11 | 12 | public abstract WaitDialog showWaitDialog(int resId); 13 | 14 | public abstract WaitDialog showWaitDialog(String text); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/dialog/WaitDialog.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | 6 | /** 7 | * Created by stevelemuel on 4/17/15. 8 | */ 9 | public class WaitDialog extends Dialog{ 10 | 11 | public WaitDialog(Context context){ 12 | super(context); 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/drawer/DrawerMenuAdapter.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.drawer; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | 9 | import java.util.List; 10 | 11 | import tk.wlemuel.cotable.R; 12 | import tk.wlemuel.cotable.model.DrawerMenu; 13 | 14 | /** 15 | * DrawerMenuAdapter 16 | * 17 | * @author Steve Lemuel 18 | * @version 0.1 19 | * @desc DrawerMenuAdapter 20 | * @created 2015/05/14 21 | * @updated 2015/05/14 22 | */ 23 | public class DrawerMenuAdapter extends BaseAdapter { 24 | 25 | private LayoutInflater mInflater; 26 | private List mItemsData; 27 | 28 | public DrawerMenuAdapter(Context context, List listItemData) { 29 | mInflater = LayoutInflater.from(context); 30 | mItemsData = listItemData; 31 | 32 | } 33 | 34 | @Override 35 | public Object getItem(int position) { 36 | return mItemsData.get(position); 37 | } 38 | 39 | @Override 40 | public long getItemId(int position) { 41 | return position; 42 | } 43 | 44 | @Override 45 | public View getView(int position, View convertView, ViewGroup parent) { 46 | DrawerMenuHolder holder; 47 | 48 | if (convertView == null) { 49 | convertView = mInflater.inflate(R.layout.activity_main_drawer_left_list_item, null); 50 | holder = new DrawerMenuHolder(convertView); 51 | convertView.setTag(holder); 52 | } else { 53 | holder = (DrawerMenuHolder) convertView.getTag(); 54 | } 55 | 56 | DrawerMenu item = mItemsData.get(position); 57 | holder.getIconTextView().setText(item.getIcon()); 58 | holder.getTextView().setText(item.getText()); 59 | 60 | return convertView; 61 | } 62 | 63 | @Override 64 | public int getCount() { 65 | return mItemsData.size(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/drawer/DrawerMenuHolder.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.drawer; 2 | 3 | import android.view.View; 4 | import android.widget.IconTextView; 5 | import android.widget.TextView; 6 | 7 | import tk.wlemuel.cotable.R; 8 | 9 | 10 | public class DrawerMenuHolder { 11 | private IconTextView mIconTextView; 12 | private TextView mTextView; 13 | 14 | public DrawerMenuHolder(View view) { 15 | mIconTextView = (IconTextView) view.findViewById(R.id.drawer_left_list_item_icon); 16 | mTextView = (TextView) view.findViewById(R.id.drawer_left_list_item_text); 17 | } 18 | 19 | public TextView getTextView() { 20 | return mTextView; 21 | } 22 | 23 | public IconTextView getIconTextView() { 24 | return mIconTextView; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/empty/EmptyLayout.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.empty; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.view.animation.Animation; 7 | import android.view.animation.AnimationUtils; 8 | import android.widget.ImageView; 9 | import android.widget.LinearLayout; 10 | import android.widget.ProgressBar; 11 | import android.widget.RelativeLayout; 12 | import android.widget.TextView; 13 | 14 | import tk.wlemuel.cotable.R; 15 | import tk.wlemuel.cotable.utils.TDevice; 16 | 17 | 18 | public class EmptyLayout extends LinearLayout implements 19 | View.OnClickListener { 20 | 21 | public static final int HIDE_LAYOUT = 4; 22 | public static final int NETWORK_ERROR = 1; 23 | public static final int NETWORK_LOADING = 2; 24 | public static final int NODATA = 3; 25 | public static final int NODATA_ENABLE_CLICK = 5; 26 | private ProgressBar animProgress; 27 | private boolean clickEnable = true; 28 | private Context context; 29 | private ImageView img; 30 | private OnClickListener listener; 31 | private int mErrorState; 32 | private RelativeLayout mLayout; 33 | private String strNoDataContent = ""; 34 | private TextView mTv; 35 | private Animation mAnim; 36 | 37 | public EmptyLayout(Context context) { 38 | super(context); 39 | this.context = context; 40 | init(); 41 | } 42 | 43 | public EmptyLayout(Context context, AttributeSet attrs) { 44 | super(context, attrs); 45 | this.context = context; 46 | init(); 47 | } 48 | 49 | /** 50 | * init the view. 51 | */ 52 | private void init() { 53 | View view = View.inflate(context, R.layout.view_error_layout, null); 54 | img = (ImageView) view.findViewById(R.id.error_layout_img); 55 | mTv = (TextView) view.findViewById(R.id.error_layout_tv); 56 | mLayout = (RelativeLayout) view.findViewById(R.id.error_layout_main); 57 | animProgress = (ProgressBar) view.findViewById(R.id.error_layout_animProgress); 58 | mAnim = AnimationUtils.loadAnimation(context, R.anim.progressbar_loading); 59 | setBackgroundColor(-1); 60 | setOnClickListener(this); 61 | img.setOnClickListener(new OnClickListener() { 62 | 63 | @Override 64 | public void onClick(View v) { 65 | if (clickEnable) { 66 | //setErrorType(NETWORK_LOADING); 67 | if (listener != null) 68 | listener.onClick(v); 69 | } 70 | } 71 | }); 72 | 73 | addView(view); 74 | } 75 | 76 | public void dismiss() { 77 | mErrorState = HIDE_LAYOUT; 78 | setVisibility(View.GONE); 79 | } 80 | 81 | public int getErrorState() { 82 | return mErrorState; 83 | } 84 | 85 | public boolean isLoadError() { 86 | return mErrorState == NETWORK_ERROR; 87 | } 88 | 89 | public boolean isLoading() { 90 | return mErrorState == NETWORK_LOADING; 91 | } 92 | 93 | @Override 94 | public void onClick(View v) { 95 | if (clickEnable) { 96 | //setErrorType(NETWORK_LOADING); 97 | if (listener != null) 98 | listener.onClick(v); 99 | } 100 | } 101 | 102 | @Override 103 | protected void onAttachedToWindow() { 104 | super.onAttachedToWindow(); 105 | } 106 | 107 | @Override 108 | protected void onDetachedFromWindow() { 109 | super.onDetachedFromWindow(); 110 | } 111 | 112 | public void setErrorMessage(String msg) { 113 | mTv.setText(msg); 114 | } 115 | 116 | public void setErrorMessage(int msg) { 117 | if (msg != 0) mTv.setText(msg); 118 | } 119 | 120 | public void setErrorType(int i) { 121 | setVisibility(View.VISIBLE); 122 | switch (i) { 123 | case NETWORK_ERROR: 124 | mErrorState = NETWORK_ERROR; 125 | if (TDevice.hasInternet()) { 126 | mTv.setText(R.string.empty_view_click_to_refresh); 127 | img.setBackgroundResource(R.drawable.pagefailed_bg); 128 | } else { 129 | mTv.setText(R.string.empty_view_network_error); 130 | img.setBackgroundResource(R.drawable.page_icon_network); 131 | } 132 | img.setVisibility(View.VISIBLE); 133 | animProgress.setVisibility(View.GONE); 134 | animProgress.clearAnimation(); 135 | clickEnable = true; 136 | break; 137 | case NETWORK_LOADING: 138 | mErrorState = NETWORK_LOADING; 139 | animProgress.setVisibility(View.VISIBLE); 140 | animProgress.clearAnimation(); 141 | animProgress.startAnimation(mAnim); 142 | img.setVisibility(View.GONE); 143 | mTv.setText(R.string.loading); 144 | clickEnable = false; 145 | break; 146 | case NODATA: 147 | mErrorState = NODATA; 148 | img.setVisibility(View.VISIBLE); 149 | animProgress.setVisibility(View.GONE); 150 | animProgress.clearAnimation(); 151 | setTvNoDataContent(); 152 | clickEnable = false; 153 | break; 154 | case HIDE_LAYOUT: 155 | setVisibility(View.GONE); 156 | animProgress.clearAnimation(); 157 | break; 158 | case NODATA_ENABLE_CLICK: 159 | mErrorState = NODATA_ENABLE_CLICK; 160 | img.setVisibility(View.VISIBLE); 161 | animProgress.setVisibility(View.GONE); 162 | animProgress.clearAnimation(); 163 | setTvNoDataContent(); 164 | clickEnable = true; 165 | break; 166 | default: 167 | break; 168 | } 169 | } 170 | 171 | public void setNoDataContent(String noDataContent) { 172 | strNoDataContent = noDataContent; 173 | } 174 | 175 | public void setOnLayoutClickListener(OnClickListener listener) { 176 | this.listener = listener; 177 | } 178 | 179 | public void setTvNoDataContent() { 180 | if (!strNoDataContent.equals("")) 181 | mTv.setText(strNoDataContent); 182 | else 183 | mTv.setText(R.string.empty_view_no_data); 184 | } 185 | 186 | @Override 187 | public void setVisibility(int visibility) { 188 | if (visibility == View.GONE) 189 | mErrorState = HIDE_LAYOUT; 190 | super.setVisibility(visibility); 191 | } 192 | 193 | public String getMessage() { 194 | if (mTv != null) { 195 | return mTv.getText().toString(); 196 | } 197 | return ""; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/pagertab/SlidingTabPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.pagertab; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | import android.support.v4.view.ViewPager; 7 | 8 | import tk.wlemuel.cotable.base.BaseTabFragment; 9 | import tk.wlemuel.cotable.base.BaseTabFragment.TabChangedListener; 10 | import tk.wlemuel.cotable.ui.pagertab.PagerSlidingTabStrip.OnTabClickListener; 11 | 12 | /** 13 | * SlidingTabPagerAdapter 14 | * 15 | * @author Steve Lemuel 16 | * @version 0.1 17 | * @desc SlidingTabPagerAdapter 18 | * @created 2015/05/10 19 | * @updated 2015/05/10 20 | */ 21 | public abstract class SlidingTabPagerAdapter extends FragmentPagerAdapter 22 | implements TabChangedListener, OnTabClickListener { 23 | 24 | protected final Context context; 25 | protected final BaseTabFragment[] fragments; 26 | private final ViewPager pager; 27 | private int lastPostion; 28 | 29 | public SlidingTabPagerAdapter(FragmentManager mgr, int i, Context context, 30 | ViewPager vp) { 31 | super(mgr); 32 | lastPostion = 0; 33 | fragments = new BaseTabFragment[i]; 34 | this.context = context; 35 | pager = vp; 36 | lastPostion = 0; 37 | } 38 | 39 | /** 40 | * Get the fragment according to the position. 41 | * 42 | * @param i position 43 | * @return BaseTabFragment 44 | */ 45 | private BaseTabFragment getFragmentByPosition(int i) { 46 | BaseTabFragment fragment = null; 47 | if (i >= 0 && i < fragments.length) 48 | fragment = fragments[i]; 49 | return fragment; 50 | } 51 | 52 | private void onLeave(int i) { 53 | BaseTabFragment fragment = getFragmentByPosition(lastPostion); 54 | lastPostion = i; 55 | if (fragment != null) 56 | fragment.g(); 57 | } 58 | 59 | public abstract int getCacheCount(); 60 | 61 | @Override 62 | public abstract int getCount(); 63 | 64 | @Override 65 | public BaseTabFragment getItem(int i) { 66 | return fragments[i]; 67 | } 68 | 69 | @Override 70 | public abstract CharSequence getPageTitle(int i); 71 | 72 | public boolean isCurrent(BaseTabFragment fragment) { 73 | boolean flag = false; 74 | int i = pager.getCurrentItem(); 75 | int j = 0; 76 | do { 77 | label0: 78 | { 79 | if (j < fragments.length) { 80 | if (fragment != fragments[j] || j != i) 81 | break label0; 82 | flag = true; 83 | } 84 | return flag; 85 | } 86 | j++; 87 | } while (true); 88 | } 89 | 90 | public void onPageScrolled(int i) { 91 | BaseTabFragment fragment = getFragmentByPosition(i); 92 | if (fragment != null) { 93 | fragment.h(); 94 | onLeave(i); 95 | } 96 | } 97 | 98 | public void onPageSelected(int i) { 99 | BaseTabFragment fragment = getFragmentByPosition(i); 100 | if (fragment != null) { 101 | fragment.f(); 102 | onLeave(i); 103 | } 104 | } 105 | 106 | @Override 107 | public void onTabClicked(int i) { 108 | BaseTabFragment fragment = getFragmentByPosition(i); 109 | if (fragment != null) 110 | fragment.i(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/pagertab/q.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.pagertab; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | /** 9 | * q 10 | * 11 | * @author Steve Lemuel 12 | * @version 0.1 13 | * @desc q 14 | * @created 2015/05/10 15 | * @updated 2015/05/10 16 | */ 17 | public final class q implements Serializable { 18 | 19 | private static final long serialVersionUID = 0xe2d57122f51e480bL; 20 | private final int a; 21 | private int b; 22 | private boolean c; 23 | private int d; 24 | private List e; 25 | 26 | public q(int i) { 27 | a = i; 28 | d = -1; 29 | } 30 | 31 | public q(q q1) { 32 | a = q1.a; 33 | b = q1.b; 34 | c = q1.c; 35 | d = q1.d; 36 | } 37 | 38 | public final int a() { 39 | return a; 40 | } 41 | 42 | final void a(int i) { 43 | b = i; 44 | } 45 | 46 | final void a(q q1) { 47 | if (e == null) 48 | e = new ArrayList(); 49 | e.add(q1); 50 | q1.d = a; 51 | } 52 | 53 | final void a(boolean flag) { 54 | c = flag; 55 | } 56 | 57 | public final int b() { 58 | return b; 59 | } 60 | 61 | public final boolean c() { 62 | return b <= 0 && c; 63 | } 64 | 65 | final void d() { 66 | if (e != null && e.size() > 0) { 67 | b = 0; 68 | c = false; 69 | Iterator iterator = e.iterator(); 70 | while (iterator.hasNext()) { 71 | q q1 = (q) iterator.next(); 72 | b = b + q1.b; 73 | c = c | q1.c; 74 | } 75 | } 76 | } 77 | 78 | final int e() { 79 | return d; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/pagertab/r.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.pagertab; 2 | 3 | import android.util.SparseArray; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import tk.wlemuel.cotable.utils.ViewUtils; 8 | 9 | /** 10 | * r 11 | * 12 | * @author Steve Lemuel 13 | * @version 0.1 14 | * @desc r 15 | * @created 2015/05/10 16 | * @updated 2015/05/10 17 | */ 18 | public final class r { 19 | 20 | public r() { 21 | // a(a); 22 | } 23 | 24 | static final void a(SparseArray sparsearray) { 25 | sparsearray.put(0, new q(0)); 26 | q q1 = new q(1); 27 | q q2 = new q(4); 28 | q q3 = new q(5); 29 | q q4 = new q(11); 30 | q q5 = new q(7); 31 | q q6 = new q(8); 32 | q q7 = new q(10); 33 | q q8 = new q(12); 34 | q q9 = new q(13); 35 | q q10 = new q(14); 36 | sparsearray.put(1, q1); 37 | sparsearray.put(4, q2); 38 | sparsearray.put(5, q3); 39 | sparsearray.put(11, q4); 40 | sparsearray.put(12, q8); 41 | sparsearray.put(7, q5); 42 | sparsearray.put(8, q6); 43 | sparsearray.put(10, q7); 44 | sparsearray.put(13, q9); 45 | sparsearray.put(14, q10); 46 | q1.a(q2); 47 | q1.a(q3); 48 | q1.a(q4); 49 | q1.a(q8); 50 | q1.a(q10); 51 | q4.a(q5); 52 | sparsearray.put(2, new q(2)); 53 | q q11 = new q(3); 54 | sparsearray.put(3, q11); 55 | q11.a(q9); 56 | q q12 = new q(6); 57 | sparsearray.put(6, q12); 58 | q11.a(q12); 59 | } 60 | 61 | public static void a(q q1, TextView tv, View view) { 62 | if (q1 != null && tv != null && view != null) { 63 | int j = q1.b(); 64 | boolean flag = q1.c(); 65 | tv.setVisibility(j > 0 ? View.VISIBLE : View.GONE); 66 | view.setVisibility(flag ? View.VISIBLE : View.GONE); 67 | if (j > 0) 68 | tv.setText(String.valueOf(Math.min(99, j))); 69 | } else { 70 | ViewUtils.a(tv, View.GONE); 71 | ViewUtils.a(view, View.GONE); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/ui/widget/FixedRecyclerView.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.ui.widget; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | 9 | /** 10 | * FixedRecycleView 11 | * 12 | * @author Steve Lemuel 13 | * @version 0.1 14 | * @desc FixedRecycleView 15 | * @created 2015/05/11 16 | * @updated 2015/05/11 17 | */ 18 | public class FixedRecyclerView extends RecyclerView { 19 | public FixedRecyclerView(Context context) { 20 | super(context); 21 | 22 | } 23 | 24 | public FixedRecyclerView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | } 27 | 28 | public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) { 29 | super(context, attrs, defStyle); 30 | } 31 | 32 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 33 | @Override 34 | public boolean canScrollVertically(int direction) { 35 | // check if scrolling up 36 | if (direction < 1) { 37 | boolean original = super.canScrollVertically(direction); 38 | return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original; 39 | } 40 | return super.canScrollVertically(direction); 41 | 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/CircleBitmapDisplayer.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.PorterDuff; 7 | import android.graphics.PorterDuffXfermode; 8 | import android.graphics.Rect; 9 | 10 | import com.nostra13.universalimageloader.core.assist.LoadedFrom; 11 | import com.nostra13.universalimageloader.core.display.BitmapDisplayer; 12 | import com.nostra13.universalimageloader.core.imageaware.ImageAware; 13 | 14 | /** 15 | * CircleBitmapDisplayer 16 | * 17 | * @author Steve Lemuel 18 | * @version 0.1 19 | * @desc CircleBitmapDisplayer 20 | * @created 2015/05/14 21 | * @updated 2015/05/14 22 | */ 23 | public class CircleBitmapDisplayer implements BitmapDisplayer { 24 | 25 | private float borderWidth = 0; 26 | private int borderColor; 27 | 28 | public CircleBitmapDisplayer() { 29 | super(); 30 | } 31 | 32 | public CircleBitmapDisplayer(int borderColor, int borderWidth) { 33 | super(); 34 | this.borderColor = borderColor; 35 | this.borderWidth = borderWidth; 36 | } 37 | 38 | @Override 39 | public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) { 40 | Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); 41 | 42 | Canvas canvas = new Canvas(output); 43 | 44 | final int color = 0xff424242; 45 | final Paint paint = new Paint(); 46 | final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 47 | 48 | paint.setAntiAlias(true); 49 | canvas.drawARGB(0, 0, 0, 0); 50 | paint.setColor(color); 51 | 52 | //--CROP THE IMAGE 53 | canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2 - 1, paint); 54 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 55 | canvas.drawBitmap(bitmap, rect, rect, paint); 56 | 57 | //--ADD BORDER IF NEEDED 58 | if (this.borderWidth > 0) { 59 | final Paint paint2 = new Paint(); 60 | paint2.setAntiAlias(true); 61 | paint2.setColor(this.borderColor); 62 | paint2.setStrokeWidth(this.borderWidth); 63 | paint2.setStyle(Paint.Style.STROKE); 64 | canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, (float) (bitmap.getWidth() / 2 - Math.ceil(this.borderWidth / 2)), paint2); 65 | } 66 | imageAware.setImageBitmap(output); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/CyptoUtils.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import java.security.Key; 4 | import java.security.spec.AlgorithmParameterSpec; 5 | 6 | import javax.crypto.Cipher; 7 | import javax.crypto.SecretKeyFactory; 8 | import javax.crypto.spec.DESKeySpec; 9 | import javax.crypto.spec.IvParameterSpec; 10 | 11 | /** 12 | * Utils for encryption and decryption. 13 | * 14 | * @author Winter Lau 15 | * @updated Steve Lemuel 16 | * @created 2011-12-26 17 | */ 18 | public class CyptoUtils { 19 | 20 | public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding"; 21 | 22 | /** 23 | * DES Algorithm,encryption 24 | * 25 | * @param data the string needs to be encrypted. 26 | * @param key secretKey, longer than 8 bytes. 27 | * @return the encrypted data. 28 | */ 29 | public static String encode(String key, String data) { 30 | if (data == null) 31 | return null; 32 | try { 33 | DESKeySpec dks = new DESKeySpec(key.getBytes()); 34 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 35 | // The secretkey ought to longer than 8 bytes. 36 | Key secretKey = keyFactory.generateSecret(dks); 37 | Cipher cipher = Cipher.getInstance(ALGORITHM_DES); 38 | // IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); 39 | AlgorithmParameterSpec paramSpec; 40 | paramSpec = new IvParameterSpec("12345678".getBytes()); 41 | cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); 42 | byte[] bytes = cipher.doFinal(data.getBytes()); 43 | return byte2hex(bytes); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | return data; 47 | } 48 | } 49 | 50 | /** 51 | * DES Algorithm,decryption 52 | * 53 | * @param data the string needs to be decrypted. 54 | * @param key secretKey, longer than 8 bytes. 55 | * @return the decrypted data. 56 | */ 57 | public static String decode(String key, String data) { 58 | if (data == null) 59 | return null; 60 | try { 61 | DESKeySpec dks = new DESKeySpec(key.getBytes()); 62 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 63 | // The secretkey ought to longer than 8 bytes. 64 | Key secretKey = keyFactory.generateSecret(dks); 65 | Cipher cipher = Cipher.getInstance(ALGORITHM_DES); 66 | // IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); 67 | AlgorithmParameterSpec paramSpec; 68 | paramSpec = new IvParameterSpec("12345678".getBytes()); 69 | cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); 70 | return new String(cipher.doFinal(hex2byte(data.getBytes()))); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | return data; 74 | } 75 | } 76 | 77 | /** 78 | * Convert the binary to String 79 | * 80 | * @param b the byte array. 81 | * @return {@code String} 82 | */ 83 | private static String byte2hex(byte[] b) { 84 | StringBuilder hs = new StringBuilder(); 85 | String stmp; 86 | for (int n = 0; b != null && n < b.length; n++) { 87 | stmp = Integer.toHexString(b[n] & 0XFF); 88 | if (stmp.length() == 1) 89 | hs.append('0'); 90 | hs.append(stmp); 91 | } 92 | return hs.toString().toUpperCase(); 93 | } 94 | 95 | // TODO Don't understand this method. 96 | private static byte[] hex2byte(byte[] b) { 97 | if ((b.length % 2) != 0) 98 | throw new IllegalArgumentException(); 99 | byte[] b2 = new byte[b.length / 2]; 100 | for (int n = 0; n < b.length; n += 2) { 101 | String item = new String(b, n, 2); 102 | b2[n / 2] = (byte) Integer.parseInt(item, 16); 103 | } 104 | return b2; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/HtmlUtils.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | /** 4 | * HtmlUtils 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc HtmlUtils 9 | * @created 2015/05/09 10 | * @updated 2015/05/09 11 | */ 12 | public class HtmlUtils { 13 | 14 | private static final String LESS_THEN = "<"; 15 | private static final String GREAT_THEN = ">"; 16 | private static final String AND = "&"; 17 | private static final String QUOTE = """; 18 | 19 | private static final String REAL_LESS_THEN = "<"; 20 | private static final String REAL_GREAT_THEN = ">"; 21 | private static final String REAL_AND = "&"; 22 | private static final String REAL_QUOTE = "\""; 23 | 24 | public static String filter(String org) { 25 | if (org == null || org == "") return ""; 26 | org = org.replace(LESS_THEN, REAL_LESS_THEN); 27 | org = org.replace(GREAT_THEN, REAL_GREAT_THEN); 28 | org = org.replace(AND, REAL_AND); 29 | org = org.replace(QUOTE, REAL_QUOTE); 30 | 31 | return org; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/OnWebViewImageListener.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | /** 4 | * OnWebViewImageListener 5 | * 6 | * @author Steve Lemuel 7 | * @version 0.1 8 | * @desc OnWebViewImageListener 9 | * @created 2015/05/14 10 | * @updated 2015/05/14 11 | */ 12 | public interface OnWebViewImageListener { 13 | 14 | void onImageClick(String bigImageUrl); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/TLog.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import android.util.Log; 4 | 5 | import tk.wlemuel.cotable.core.AppConfig; 6 | 7 | 8 | public class TLog { 9 | public static final String LOG_TAG = AppConfig.APP_NAME; 10 | public static boolean DEBUG = true; 11 | 12 | public TLog() { 13 | } 14 | 15 | public static void analytics(String log) { 16 | if (DEBUG) 17 | Log.d(LOG_TAG, log); 18 | } 19 | 20 | public static void error(String log) { 21 | if (DEBUG) 22 | Log.e(LOG_TAG, "" + log); 23 | } 24 | 25 | public static void log(String log) { 26 | if (DEBUG) 27 | Log.i(LOG_TAG, log); 28 | } 29 | 30 | public static void log(String tag, String log) { 31 | if (DEBUG) 32 | Log.i(tag, log); 33 | } 34 | 35 | public static void logv(String log) { 36 | if (DEBUG) 37 | Log.v(LOG_TAG, log); 38 | } 39 | 40 | public static void warning(String log) { 41 | if (DEBUG) 42 | Log.w(LOG_TAG, log); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/TimeZoneUtil.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import java.util.Date; 4 | import java.util.TimeZone; 5 | 6 | /** 7 | * Utils for handling the timezone issues. 8 | * 9 | * @author HuangWenwei 10 | * @updated Steve Lemuel 11 | * @created 2014-07-31 12 | */ 13 | public class TimeZoneUtil { 14 | 15 | /** 16 | * Returns if the timezone of current device is EasternEightZone (China). 17 | * 18 | * @return {@code true} if the timezone of current device is EasternEightZone, 19 | * {@code false} otherwise. 20 | */ 21 | public static boolean isInEasternEightZones() { 22 | return TimeZone.getDefault() == TimeZone.getTimeZone("GMT+08"); 23 | } 24 | 25 | /** 26 | * Convert the {@code date} according to the timezone. 27 | * 28 | * @param date the current date 29 | * @param oldZone old timezone 30 | * @param newZone new timezone 31 | * @return {@code finalDate} the converted date. 32 | */ 33 | public static Date transformTime(Date date, TimeZone oldZone, 34 | TimeZone newZone) { 35 | Date finalDate = null; 36 | if (date != null) { 37 | int timeOffset = oldZone.getOffset(date.getTime()) 38 | - newZone.getOffset(date.getTime()); 39 | finalDate = new Date(date.getTime() - timeOffset); 40 | } 41 | return finalDate; 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/UIHelper.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.webkit.WebView; 9 | 10 | import java.util.Map; 11 | 12 | import tk.wlemuel.cotable.activity.common.SimpleBackActivity; 13 | import tk.wlemuel.cotable.model.SimpleBackPage; 14 | 15 | /** 16 | * UIHelper 17 | * 18 | * @author Steve Lemuel 19 | * @version 0.1 20 | * @desc UIHelper 21 | * @created 2015/05/11 22 | * @updated 2015/05/11 23 | */ 24 | public class UIHelper { 25 | 26 | /** 27 | * Show Blog Details 28 | * 29 | * @param context context 30 | * @param blogInfo blog id 31 | */ 32 | public static void showBlogDetail(Context context, Map blogInfo) { 33 | Bundle args = new Bundle(); 34 | 35 | if (blogInfo != null) { 36 | for (Map.Entry entry : blogInfo.entrySet()) { 37 | args.putString(entry.getKey(), entry.getValue()); 38 | } 39 | } 40 | 41 | showSimpleBack(context, SimpleBackPage.DETAILS, args); 42 | } 43 | 44 | /** 45 | * Call the system application with shares. 46 | * 47 | * @param context context 48 | * @param title share title 49 | * @param url share url 50 | */ 51 | public static void showShareMore(Activity context, final String title, final String url) { 52 | Intent intent = new Intent(Intent.ACTION_SEND); 53 | intent.setType("text/plain"); 54 | intent.putExtra(Intent.EXTRA_SUBJECT, "Share: " + title); 55 | intent.putExtra(Intent.EXTRA_TEXT, title + " " + url); 56 | context.startActivity(Intent.createChooser(intent, "Choose to share")); 57 | } 58 | 59 | public static void showSimpleBack(Context context, SimpleBackPage page) { 60 | Intent intent = new Intent(context, SimpleBackActivity.class); 61 | intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); 62 | 63 | context.startActivity(intent); 64 | } 65 | 66 | public static void showSimpleBack(Context context, SimpleBackPage page, 67 | Bundle args) { 68 | Intent intent = new Intent(context, SimpleBackActivity.class); 69 | intent.putExtra(SimpleBackActivity.BUNDLE_KEY_ARGS, args); 70 | intent.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE, page.getValue()); 71 | context.startActivity(intent); 72 | } 73 | 74 | /** 75 | * 添加网页的点击图片展示支持 76 | */ 77 | @SuppressLint("JavascriptInterface") 78 | public static void addWebImageShow(final Context cxt, WebView wv) { 79 | wv.getSettings().setJavaScriptEnabled(true); 80 | wv.addJavascriptInterface(new OnWebViewImageListener() { 81 | 82 | @Override 83 | public void onImageClick(String bigImageUrl) { 84 | if (bigImageUrl != null) { 85 | // UIHelper.showImageZoomDialog(cxt, bigImageUrl); 86 | // UIHelper.showImagePreview(cxt, new String[]{bigImageUrl}); 87 | } 88 | } 89 | }, "mWebViewImageListener"); 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/tk/wlemuel/cotable/utils/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package tk.wlemuel.cotable.utils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.app.Dialog; 6 | import android.content.Context; 7 | import android.graphics.Bitmap; 8 | import android.graphics.Canvas; 9 | import android.os.Build; 10 | import android.text.TextUtils; 11 | import android.util.TypedValue; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.TextView; 15 | 16 | /** 17 | * ViewUtils 18 | * 19 | * @author Steve Lemuel 20 | * @version 0.1 21 | * @desc ViewUtils 22 | * @created 2015/05/10 23 | * @updated 2015/05/10 24 | */ 25 | public final class ViewUtils { 26 | 27 | public static float a(TextView tv) { 28 | float f = 0.0F; 29 | if (tv != null) { 30 | float f1 = 0.0f; 31 | CharSequence text = tv.getText(); 32 | if (!TextUtils.isEmpty(text)) { 33 | f1 = tv.getPaint().measureText(text.toString()); 34 | } 35 | int i = tv.getPaddingLeft(); 36 | int j = tv.getPaddingRight(); 37 | f = f1 + (float) (j + i); 38 | } 39 | return f; 40 | } 41 | 42 | public static int a(Context context) { 43 | return (int) TypedValue.applyDimension(1, 40F, context.getResources() 44 | .getDisplayMetrics()); 45 | } 46 | 47 | public static void a(Activity activity, int[] ai) { 48 | if (ai != null && activity != null) { 49 | int size = ai.length; 50 | for (int i = 0; i < size; i++) { 51 | View view = activity.findViewById(ai[i]); 52 | if (view != null) 53 | view.setOnClickListener((View.OnClickListener) activity); 54 | } 55 | } 56 | } 57 | 58 | public static void a(Dialog dialog, int[] ai) { 59 | if (ai != null && dialog != null) { 60 | int size = ai.length; 61 | for (int j = 0; j < size; j++) { 62 | View view = dialog.findViewById(ai[j]); 63 | if (view != null) 64 | view.setOnClickListener((View.OnClickListener) dialog); 65 | } 66 | } 67 | } 68 | 69 | public static void a(View view) { 70 | if (view != null && (view.getParent() instanceof ViewGroup)) 71 | ((ViewGroup) view.getParent()).removeView(view); 72 | } 73 | 74 | public static void a(View view, int i) { 75 | if (view != null) 76 | view.setVisibility(i); 77 | } 78 | 79 | public static void a(View view, View.OnClickListener listener, int[] ai) { 80 | if (ai != null && view != null) { 81 | int size = ai.length; 82 | for (int j = 0; j < size; j++) { 83 | View view1 = view.findViewById(ai[j]); 84 | if (view1 != null) 85 | view1.setOnClickListener(listener); 86 | } 87 | } 88 | } 89 | 90 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 91 | public static Bitmap b(View view) { 92 | Bitmap bitmap = null; 93 | view.measure(View.MeasureSpec.makeMeasureSpec(0, 0), 94 | View.MeasureSpec.makeMeasureSpec(0, 0)); 95 | int i = view.getMeasuredWidth(); 96 | int j = view.getMeasuredHeight(); 97 | view.layout(0, 0, i, j); 98 | view.setDrawingCacheEnabled(false); 99 | view.setWillNotCacheDrawing(true); 100 | view.setDrawingCacheEnabled(false); 101 | view.setWillNotCacheDrawing(true); 102 | if (i > 0 && j > 0) { 103 | bitmap = Bitmap.createBitmap(i, j, 104 | Bitmap.Config.ARGB_8888); 105 | Canvas canvas = new Canvas(bitmap); 106 | if (Build.VERSION.SDK_INT >= 11) 107 | view.setLayerType(1, null); 108 | view.draw(canvas); 109 | } 110 | return bitmap; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/res/anim/progressbar_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_comment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_comment_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_comment_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_dianzan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_dianzan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_dianzan_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_dianzan_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_pullrefresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_pullrefresh.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_reply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_reply.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_reply_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_reply_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_scrolltoup_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/ic_scrolltoup_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_bottombtn_down.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_bottombtn_down.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_bottombtn_up.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_bottombtn_up.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_icon_zoomin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_icon_zoomin.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_icon_zoomin_dis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_icon_zoomin_dis.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_icon_zoomout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_icon_zoomout.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_icon_zoomout_dis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_icon_zoomout_dis.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_topbtn_down.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_topbtn_down.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_topbtn_up.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/main_topbtn_up.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_zoomin.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/main_zoomout.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_48_inner_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/spinner_48_inner_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_48_outer_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-hdpi/spinner_48_outer_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_avatar_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-mdpi/ic_avatar_author.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/actionbar_back_icon_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/actionbar_back_icon_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/animdraw.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_splash_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/bg_splash_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_about_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_about_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_about_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_about_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_close_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_close_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_close_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_close_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_day_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_day_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_daymode_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_daymode_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_night_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_night_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_night_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_night_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_options_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_options_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_menu_options_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/btn_menu_options_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/drawer_left_header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/drawer_left_header.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_avatar_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/ic_avatar_author.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_blog_item_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/ic_blog_item_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_default_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/ic_default_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loadingpage_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/loadingpage_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/loadingpage_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/loadingpage_light.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/page_icon_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/page_icon_network.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pagefailed_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/pagefailed_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_notification_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xhdpi/tab_notification_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_avatar_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xxhdpi/ic_avatar_author.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_drawer_left_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_cell_background_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_bottombutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_topbutton.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_medium_holo.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 25 | 26 | 27 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_strip_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 15 | 16 | 20 | 21 | 25 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_blog_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_blog_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 25 | 26 | 37 | 38 | 44 | 45 | 46 | 51 | 52 | 59 | 60 | 61 | 66 | 67 | 77 | 78 | 86 | 87 | 96 | 97 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 24 | 25 | 34 | 35 | 45 | 46 | 47 | 48 | 55 | 56 | 57 | 58 | 62 | 63 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer_left_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer_left_list_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer_left_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer_left_setting_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | 32 | 33 | 34 | 40 | 41 | 47 | 48 | 58 | 59 | 60 | 66 | 67 | 73 | 74 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /app/src/main/res/layout/aty_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/aty_simple_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/aty_splash_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_blog_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | 53 | 54 | 61 | 62 | 63 | 64 | 65 | 71 | 72 | 76 | 77 | 84 | 88 | 95 | 96 | 102 | 108 | 109 | 116 | 117 | 123 | 129 | 136 | 137 | 138 | 139 | 140 | 141 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_swipe_refresh_recycleview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 36 | 37 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_viewpager.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_cell_blog.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 24 | 25 | 36 | 37 | 43 | 44 | 45 | 50 | 51 | 58 | 59 | 66 | 67 | 68 | 73 | 74 | 84 | 85 | 93 | 94 | 103 | 104 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_cell_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_layout_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 | 24 | 32 | 33 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_error_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 18 | 19 | 23 | 24 | 31 | 32 | 33 | 40 | 41 | 42 | 43 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_toast.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 26 | 27 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-en-rUS/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Cotable 3 | Steve Lemuel 4 | wlemuel 5 | wlemuel@hotmail.com 6 | 1078707962 7 | 1078707962@qq.com 8 | http://wlemuel.tk 9 | 10 | User 11 | Favors 12 | Setting 13 | Exit 14 | Close 15 | Open 16 | Search 17 | Comments (%d) 18 | Posted at : 19 | Read (%d) 20 | Click to refresh 21 | Loading... 22 | No data 23 | JAVA EXCEPTION HANDLE 24 | days ago 25 | hours ago 26 | a minute ago 27 | an hour ago 28 | minutes ago 29 | the day before yesterday 30 | yesterday 31 | @string/app_author 32 | About 33 | Content 34 | Preferences 35 | Loading... 36 | Loading Error. 37 | No more data 38 | Network Unavailable 39 | LATEST 40 | RECOMMEND 41 | NEWS 42 | Author : 43 | Network Error 44 | 2015-04-19 14:52 45 | 想到用python发送邮件主要是服务器 有时候会产生coredump文件 ,然后因为脚本重启原因,服务器coredump产生后会重启但是没有主动通知开发人员想了下可以写个脚本一旦产生coredump文件就可以发送邮件给开发者让其立马知道下面只介绍简单的发送脚本如果需要在生产环境用起来 还需要按要求修... 46 | Developer 47 | Instructions 48 | License 49 | Source 50 | Update 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/values-ja-rJP/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | コタブル 3 | オウシン 4 | wlemuel 5 | wlemuel@hotmail.com 6 | 1078707962 7 | 1078707962@qq.com 8 | http://wlemuel.tk 9 | 10 | ユーザ 11 | クリップ 12 | 設定 13 | 終了 14 | 閉じる 15 | 開く 16 | 検索 17 | コメント (%d) 18 | 再ロード 19 | ロード中 20 | JAVAの異常処理 21 | 日前 22 | 1分間前 23 | 1時間前 24 | 発表時間 : 25 | 読み (%d) 26 | 昨日 27 | おととい 28 | @string/app_author 29 | 設定 30 | ブログ内容 31 | 32 | ネトワクに接続できません。 33 | データなし 34 | 2015-04-19 14:52 35 | 想到用python发送邮件主要是服务器 有时候会产生coredump文件 ,然后因为脚本重启原因,服务器coredump产生后会重启但是没有主动通知开发人员想了下可以写个脚本一旦产生coredump文件就可以发送邮件给开发者让其立马知道下面只介绍简单的发送脚本如果需要在生产环境用起来 还需要按要求修... 36 | 作者 : 37 | 時間前 38 | ロード中... 39 | エラー発生 40 | ネトワクエラー 41 | 分前 42 | 最新ボログ 43 | オススメ 44 | 最新情報 45 | データなし 46 | 47 | 48 | Java 49 | C++ 50 | Python 51 | Ruby 52 | PHP 53 | Objective-C 54 | Perl 55 | 56 | エンジニア 57 | 機能紹介 58 | 更新ローグ 59 | ライセンス 60 | ソースコード 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #2196F3 6 | #1976D2 7 | #BBDEFB 8 | #ff303030 9 | #ff000000 10 | #ff252525 11 | 12 | #8BC34A 13 | #1976D2 14 | 15 | #212121 16 | #727272 17 | #B6B6B6 18 | 19 | #DE000000 20 | #9E9E9E 21 | 22 | 23 | @color/colorPrimary 24 | #40AA53 25 | #9A9A9A 26 | #353535 27 | #576B95 28 | #ff000000 29 | #ffffffff 30 | #9A9A9A 31 | @color/text_color_black 32 | #00000000 33 | #ffffffff 34 | 35 | 36 | #fff 37 | #000 38 | #9A9A9A 39 | #e9eff3 40 | 41 | 42 | @color/text_color_white 43 | @color/main 44 | 45 | 46 | @color/toolbar_text_color 47 | @color/toolbar_background 48 | @color/main 49 | @color/main_black 50 | #66fafafa 51 | 52 | 53 | @color/main 54 | @color/text_color_white 55 | 56 | 57 | #757575 58 | @color/text_color_black 59 | #ffffffff 60 | #F1F1F1 61 | 62 | 63 | @color/list_item_background_normal 64 | #EEEEEE 65 | @color/list_item_background_pressed 66 | @color/main 67 | #757575 68 | #FF3B6E75 69 | @color/text_color_black 70 | 71 | 72 | @color/window_background 73 | @color/text_color_white 74 | @color/drawer_left_header_username 75 | @color/list_divider_color 76 | @color/list_divider_color 77 | @color/list_item_background_normal 78 | @color/drawer_left_list_item_ic_color 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 7 | 20dip 8 | 16sp 9 | 4dip 10 | 6dip 11 | 16dip 12 | 40.0dip 13 | 14 | 8.0dip 15 | 55.0dip 16 | 16.0dip 17 | 10.0dip 18 | 19 | 20 | 280dp 21 | 160dp 22 | 70dp 23 | 35dp 24 | 2dp 25 | 20dp 26 | 15sp 27 | 28 | 48dp 29 | 24sp 30 | 24dp 31 | 16sp 32 | 42dp 33 | 8dp 34 | 48dp 35 | 14sp 36 | 20sp 37 | 38 | 60dp 39 | 8dp 40 | 6dp 41 | 25dp 42 | 10sp 43 | 44 | 45 | 16dp 46 | 18sp 47 | 8dp 48 | 8dp 49 | 10sp 50 | 10sp 51 | 5dp 52 | 10sp 53 | 10sp 54 | 5dp 55 | 10sp 56 | 12dp 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 码厩 4 | 激荡的天石 5 | wlemuel 6 | wlemuel@hotmail.com 7 | 1078707962 8 | 1078707962@qq.com 9 | http://wlemuel.tk 10 | 11 | 打开 12 | 关闭 13 | 14 | 15 | Java 16 | C++ 17 | Python 18 | Ruby 19 | PHP 20 | Objective-C 21 | Perl 22 | 23 | 24 | JAVA异常处理、常用类、反射、集合 25 | 想到用python发送邮件主要是服务器 有时候会产生coredump文件 ,然后因为脚本重启原因,服务器coredump产生后会重启但是没有主动通知开发人员想了下可以写个脚本一旦产生coredump文件就可以发送邮件给开发者让其立马知道下面只介绍简单的发送脚本如果需要在生产环境用起来 还需要按要求修... 26 | @string/app_author 27 | 2015-04-19 14:52 28 | 评论 (%d) 29 | 阅读 (%d) 30 | 发布时间: 31 | 作者 : 32 | 33 | 34 | 点击屏幕, 重新加载 35 | 暂无内容 36 | 加载中... 37 | 没有网络连接 38 | 39 | 40 | 分钟前 41 | 小时前 42 | 天前 43 | 1分钟前 44 | 1小时前 45 | 昨天 46 | 前天 47 | 48 | 加载中... 49 | 没有更多数据 50 | 网络不稳定,加载出错 51 | 没有可用的网络 52 | 53 | 最新博客 54 | 推荐阅读 55 | 资讯新闻 56 | 57 | 设置 58 | 关于 59 | 博客内容 60 | 退出 61 | 收藏 62 | 搜索 63 | 设置 64 | 用户 65 | 66 | 开发者 67 | 源代码 68 | 功能介绍 69 | 开源协议 70 | 更新日志 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 26 | 27 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /screenshot/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlemuel/Cotable/ddeee9adfa1ceb5459ccb9109235879a70eaa6b7/screenshot/screenshot.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' //, 'library-pulltorefresh' , ':library-photoview', ':library-viewpager-indicator', 2 | //':library-sticky-listheaders', ':library-umengshare' 3 | //project(':library-photoview').projectDir = new File('libraries/library-photoview') 4 | //project(':library-viewpager-indicator').projectDir = new File('libraries/library-viewpager-indicator') 5 | //project(':library-sticky-listheaders').projectDir = new File('libraries/library-sticky-listheaders') 6 | //project(':library-umengshare').projectDir = new File('libraries/library-umengshare') 7 | //project(':library-pulltorefresh').projectDir = new File('libraries/library-pulltorefresh') --------------------------------------------------------------------------------