newest;
36 |
37 | public static class TokenName {
38 | public String token;
39 | public String name;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/common/Constants.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.common;
2 |
3 | /**
4 | * Created by fanhl on 15/11/8.
5 | */
6 | public class Constants {
7 | public static final int TIME_OUT = 30000;
8 | /*每次加载书籍的数量*/
9 | public static final int PAGE_BOOK_COUNT_MAX = 36;
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/exception/GetBookFailException.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * Created by fanhl on 15/11/20.
7 | */
8 | public class GetBookFailException extends IOException {
9 | public GetBookFailException() {
10 | }
11 |
12 | public GetBookFailException(String detailMessage) {
13 | super(detailMessage);
14 | }
15 |
16 | public GetBookFailException(String detailMessage, Throwable e) {
17 | super(detailMessage, e);
18 | }
19 |
20 | public GetBookFailException(Throwable throwable) {
21 | super(throwable);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/exception/GetDataFailException.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.exception;
2 |
3 | /**
4 | * Created by fanhl on 15/11/8.
5 | */
6 | public class GetDataFailException extends Exception {
7 | public GetDataFailException() {
8 | }
9 |
10 | public GetDataFailException(String detailMessage) {
11 | super(detailMessage);
12 | }
13 |
14 | public GetDataFailException(String detailMessage, Throwable e) {
15 | super(detailMessage, e);
16 | }
17 |
18 | public GetDataFailException(Throwable throwable) {
19 | super(throwable);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/exception/NetworkAccessFailException.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.exception;
2 |
3 | /**
4 | * Created by fanhl on 15/11/6.
5 | */
6 | public class NetworkAccessFailException extends Exception {
7 | public NetworkAccessFailException() {
8 | }
9 |
10 | public NetworkAccessFailException(String msg, Throwable e) {
11 | super(msg, e);
12 | }
13 |
14 | public NetworkAccessFailException(Throwable throwable) {
15 | super(throwable);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/interfaceX/OnDownloadManagerBookChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.interfaceX;
2 |
3 | import com.fanhl.doujinMoe.model.Book;
4 |
5 | /**
6 | * 用于在父onAttach时绑定activity,并在DownloadManager下载成功/失败时通知Fragment
7 | *
8 | * Created by fanhl on 15/11/27.
9 | */
10 | public interface OnDownloadManagerBookChangeListener {
11 | /**
12 | * 用来响应 DownloadManager 下载书籍成功/失败
13 | *
14 | * @param book
15 | * @param success
16 | */
17 | void onDownloadBookChanged(Book book, boolean success);
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/model/Book.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Date;
7 | import java.util.List;
8 |
9 | /**
10 | * Created by fanhl on 15/11/5.
11 | */
12 | public class Book {
13 |
14 | //--------------------- Gson 解析取得-----------------------
15 |
16 | public String token;
17 | @SerializedName("title")
18 | public String name;
19 | @SerializedName("objectcount")
20 | public int count;
21 | public boolean main;
22 | public String rating;
23 | public String date;
24 |
25 | //---------------------- 本地信息 ---------------------------
26 |
27 | public List pages;
28 | /*当前看到的页码*/
29 | public int position;
30 | /*最新阅读日期*/
31 | public Date recent;
32 | /*下载状态*/
33 | public Status status;
34 |
35 | //--------------其它相关-----------------
36 |
37 | /*当 status=.DOWNLOADING 时记录下载到的页码*/
38 | public int downloadedPosition = -1;
39 |
40 | public Book() {
41 | pages = new ArrayList<>();
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "Book(" + name + "," + token + ")";
47 | }
48 |
49 | public boolean isDownloading() {
50 | return status == Status.DOWNLOADING;
51 | }
52 |
53 | public boolean isDownloaded() {
54 | return status == Status.DOWNLOADED;
55 | }
56 |
57 | public boolean isWaitDownload() {
58 | return status == Status.WAIT_DOWNLOAD;
59 | }
60 |
61 | public enum Status {
62 | NONE, WAIT_DOWNLOAD, DOWNLOADING, DOWNLOADED
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/model/IndexItem.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.model;
2 |
3 | /**
4 | * 将一个对象连同一个index打包起来
5 | *
6 | * Created by fanhl on 15/11/19.
7 | */
8 | public class IndexItem {
9 | public I item;
10 | public int index;
11 |
12 | public IndexItem(I item, int index) {
13 | this.item = item;
14 | this.index = index;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/model/Page.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.model;
2 |
3 | /**
4 | * Created by fanhl on 15/11/6.
5 | */
6 | public class Page {
7 | /*预览图(src链接)*/
8 | public String preview;
9 | /*大图(src链接)*/
10 | public String href;
11 |
12 | @Override
13 | public String toString() {
14 | return "Page(" + preview + "," + href + ")";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/rest/DoujinmoeClient.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.rest;
2 |
3 | import com.fanhl.doujinMoe.rest.service.HomeService;
4 |
5 | import retrofit.GsonConverterFactory;
6 | import retrofit.Retrofit;
7 | import retrofit.RxJavaCallAdapterFactory;
8 |
9 | /**
10 | * Created by fanhl on 15/12/1.
11 | */
12 | public class DoujinmoeClient {
13 |
14 | public static final String BASE_URL = "http://m.doujin-moe.us";
15 | private final HomeService homeService;
16 |
17 | public DoujinmoeClient() {
18 | Retrofit retrofit = new Retrofit.Builder()
19 | .baseUrl(BASE_URL)
20 | .addConverterFactory(GsonConverterFactory.create())
21 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
22 | .build();
23 |
24 | homeService = retrofit.create(HomeService.class);
25 | }
26 |
27 | public HomeService getHomeService() {
28 | return homeService;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/rest/model/FolderResponse.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.rest.model;
2 |
3 | import com.fanhl.doujinMoe.model.Book;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * 存放状态,书籍列表
9 | *
10 | * Created by fanhl on 15/12/1.
11 | */
12 | public class FolderResponse {
13 | /**
14 | * success : true
15 | * message :
16 | * folders : [{"token":"a2ze9msz","title":"A Rainy Afternoon with Friends","objectcount":"20","main":true,"rating":"2.70","date":"11/29/2015"},{"token":"mrejuww9","title":"About-Face","objectcount":"24","main":true,"rating":"4.84","date":"11/29/2015"},{"token":"ywthbq8j","title":"Do You Know About Buddha's Face","objectcount":"24","main":true,"rating":"4.42","date":"11/29/2015"},{"token":"w8wrwmm4","title":"I Like My Sister","objectcount":"22","main":true,"rating":"3.94","date":"11/29/2015"},{"token":"wrevngbe","title":"Jelly Multiplication","objectcount":"20","main":true,"rating":"3.81","date":"11/29/2015"}]
17 | * complete : false
18 | */
19 |
20 | public boolean success;
21 | public String message;
22 | public boolean complete;
23 | /**
24 | * token : a2ze9msz
25 | * title : A Rainy Afternoon with Friends
26 | * objectcount : 20
27 | * main : true
28 | * rating : 2.70
29 | * date : 11/29/2015
30 | */
31 |
32 | public List folders;
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/rest/service/HomeService.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.rest.service;
2 |
3 | import com.fanhl.doujinMoe.rest.model.FolderResponse;
4 | import com.squareup.okhttp.Response;
5 |
6 | import retrofit.Call;
7 | import retrofit.http.Field;
8 | import retrofit.http.FormUrlEncoded;
9 | import retrofit.http.GET;
10 | import retrofit.http.POST;
11 | import retrofit.http.Path;
12 | import rx.Observable;
13 |
14 | /**
15 | * 移动端 数据传输服务 (好像所有服务全走的这一个接口)
16 | *
17 | * Created by fanhl on 15/12/1.
18 | */
19 | public interface HomeService {
20 | @FormUrlEncoded
21 | @POST("/ajax/folder.php")
22 | Observable bookList(
23 | @Field("token") String token,
24 | @Field("offset") int offset,
25 | @Field("max") int max,
26 | @Field("sort") String sort,
27 | @Field("param") String param);
28 |
29 | // FIXME: 15/12/7 未完成
30 | // @Multipart
31 | @GET("{url}")
32 | Call downloadPage(@Path("url") String pagePath);
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/GalleryActivity.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.content.res.Configuration;
6 | import android.graphics.Color;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.os.Handler;
10 | import android.support.annotation.Nullable;
11 | import android.support.v4.view.DirectionalViewPager;
12 | import android.support.v4.view.ViewCompat;
13 | import android.support.v4.view.ViewPager;
14 | import android.support.v7.app.ActionBar;
15 | import android.support.v7.widget.AppCompatSeekBar;
16 | import android.support.v7.widget.AppCompatTextView;
17 | import android.support.v7.widget.Toolbar;
18 | import android.util.Log;
19 | import android.view.View;
20 | import android.view.WindowManager;
21 | import android.widget.LinearLayout;
22 | import android.widget.SeekBar;
23 |
24 | import com.fanhl.doujinMoe.R;
25 | import com.fanhl.doujinMoe.api.BookApi;
26 | import com.fanhl.doujinMoe.model.Book;
27 | import com.fanhl.doujinMoe.ui.adapter.GalleryPagerAdapter;
28 | import com.fanhl.doujinMoe.ui.common.AbsActivity;
29 | import com.fanhl.doujinMoe.util.FullScreenHelper;
30 | import com.fanhl.doujinMoe.util.Utility;
31 | import com.fanhl.util.GsonUtil;
32 |
33 | import butterknife.Bind;
34 | import butterknife.ButterKnife;
35 |
36 | public class GalleryActivity extends AbsActivity {
37 | public static final String TAG = GalleryActivity.class.getSimpleName();
38 | private static final int AUTO_HIDE_DELAY_MILLIS = 1500;
39 | public static final String EXTRA_BOOK_DATA = "EXTRA_BOOK_DATA";
40 |
41 | @Bind(R.id.toolbar)
42 | Toolbar toolbar;
43 | @Bind(R.id.pager)
44 | DirectionalViewPager mPager;
45 | @Bind(R.id.app_bar)
46 | LinearLayout mAppBar;
47 | @Bind(R.id.bottom_bar)
48 | LinearLayout mBottomBar;
49 | @Bind(R.id.seekBar)
50 | AppCompatSeekBar mSeekBar;
51 | @Bind(R.id.total_pages_text)
52 | AppCompatTextView mTotalPagesText;
53 |
54 | //custom
55 |
56 | private Book book;
57 |
58 | private FullScreenHelper mFullScreenHelper;
59 | private GalleryPagerAdapter mPagerAdapter;
60 |
61 | public static void launch(Activity activity, Book book) {
62 | Intent intent = new Intent(activity, GalleryActivity.class);
63 | intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
64 | intent.putExtra(EXTRA_BOOK_DATA, GsonUtil.json(book));
65 | activity.startActivity(intent);
66 | }
67 |
68 | @Override
69 | protected void onCreate(Bundle savedInstanceState) {
70 | super.onCreate(savedInstanceState);
71 |
72 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !Utility.isChrome()) {
73 | getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
74 | }
75 |
76 | if (Build.VERSION.SDK_INT >= 21) {
77 | getWindow().setStatusBarColor(Color.TRANSPARENT);
78 | getWindow().setNavigationBarColor(Color.TRANSPARENT);
79 | }
80 |
81 | mFullScreenHelper = new FullScreenHelper(this);
82 | // 别问我为什么这么干 让我先冷静一下→_→
83 | mFullScreenHelper.setFullScreen(true);
84 | mFullScreenHelper.setFullScreen(false);
85 |
86 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
87 |
88 | setContentView(R.layout.activity_gallery);
89 | ButterKnife.bind(this);
90 | setSupportActionBar(toolbar);
91 |
92 | Intent intent = getIntent();
93 | book = GsonUtil.obj(intent.getStringExtra(EXTRA_BOOK_DATA), Book.class);
94 | assert book != null;
95 | int tmpPosition = book.position;//详细页点击第三张page时,position=2,此时本地bookJson中position=3.这种情况下使用2这个值.
96 | //从本地取最新的数据
97 | book = BookApi.getBookFormJson(this, book);
98 | book.position = tmpPosition;
99 |
100 | ActionBar actionBar = getSupportActionBar();
101 | if (actionBar != null) {
102 | actionBar.setDisplayHomeAsUpEnabled(true);
103 | }
104 |
105 | setTitle(book.name);
106 |
107 | mPagerAdapter = new GalleryPagerAdapter(getFragmentManager(), book);
108 | mPager.setAdapter(mPagerAdapter);
109 | mPager.setCurrentItem(book.position, false);
110 | // mPager.setOffscreenPageLimit(4);
111 |
112 | //注:DirectionalViewPager实现的是过时的方法setOnPageChangeListener
113 | mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
114 | @Override
115 | public void onPageSelected(int position) {
116 | Log.d(TAG, "page currentIndex:" + position);
117 | mSeekBar.setProgress(position);
118 | mTotalPagesText.setText(getString(R.string.info_total_pages, position + 1, book.count));
119 | book.position = position;
120 | }
121 | });
122 |
123 | refreshForOrientation(getResources().getConfiguration());
124 |
125 | mTotalPagesText.setText(getString(R.string.info_total_pages, book.position + 1, book.count));
126 | mSeekBar.setKeyProgressIncrement(1);
127 | mSeekBar.setMax(book.count - 1);
128 | mSeekBar.setProgress(book.position);
129 | mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
130 | int progress = 0;
131 |
132 | @Override
133 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
134 | this.progress = progress;
135 | mTotalPagesText.setText(getString(R.string.info_total_pages, progress + 1, book.count));
136 | }
137 |
138 | @Override
139 | public void onStartTrackingTouch(SeekBar seekBar) {
140 | }
141 |
142 | @Override
143 | public void onStopTrackingTouch(SeekBar seekBar) {
144 | book.position = progress;
145 | mPager.setCurrentItem(progress, false);
146 | }
147 | });
148 | }
149 |
150 | @Override
151 | protected void onPostCreate(@Nullable Bundle savedInstanceState) {
152 | super.onPostCreate(savedInstanceState);
153 | new Handler().postDelayed(this::hide, AUTO_HIDE_DELAY_MILLIS);
154 | }
155 |
156 | @Override
157 | protected void onStop() {
158 | super.onStop();
159 | BookApi.saveBookJson(this, book);
160 | }
161 |
162 | @Override
163 | public void onConfigurationChanged(Configuration newConfig) {
164 | super.onConfigurationChanged(newConfig);
165 | refreshForOrientation(newConfig);
166 | }
167 |
168 | private void refreshForOrientation(Configuration newConfig) {
169 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
170 | mPager.setOrientation(DirectionalViewPager.HORIZONTAL);
171 | } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
172 | mPager.setOrientation(DirectionalViewPager.VERTICAL);
173 | }
174 | }
175 |
176 | public void toggle() {
177 | if (mAppBar.getAlpha() != 0f) {
178 | hide();
179 | } else if (mAppBar.getAlpha() != 1f) {
180 | show();
181 | }
182 | }
183 |
184 | private void hide() {
185 | ViewCompat.animate(mAppBar).alpha(0f).start();
186 | ViewCompat.animate(mBottomBar).alpha(0f).start();
187 | mFullScreenHelper.setFullScreen(true);
188 | }
189 |
190 | private void show() {
191 | ViewCompat.animate(mAppBar).alpha(1f).start();
192 | ViewCompat.animate(mBottomBar).alpha(1f).start();
193 | mFullScreenHelper.setFullScreen(false);
194 | }
195 |
196 | @Override
197 | public void onBackPressed() {
198 | if (mAppBar.getAlpha() != 1f) {
199 | toggle();
200 | } else {
201 | super.onBackPressed();
202 | }
203 | }
204 |
205 | @Override
206 | public void onDMDownloadSuccess(Book book) {
207 | if (this.book.name.equals(book.name)) {
208 | book.status = Book.Status.DOWNLOADED;
209 | }
210 | }
211 |
212 | }
213 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.FloatingActionButton;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.design.widget.Snackbar;
7 | import android.support.v4.view.GravityCompat;
8 | import android.support.v4.view.ViewPager;
9 | import android.support.v4.widget.DrawerLayout;
10 | import android.support.v7.app.ActionBarDrawerToggle;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 |
15 | import com.fanhl.doujinMoe.R;
16 | import com.fanhl.doujinMoe.model.Book;
17 | import com.fanhl.doujinMoe.ui.adapter.MainPagerAdapter;
18 | import com.fanhl.doujinMoe.ui.common.AbsActivity;
19 |
20 | import butterknife.Bind;
21 | import butterknife.ButterKnife;
22 |
23 | public class MainActivity extends AbsActivity
24 | implements NavigationView.OnNavigationItemSelectedListener {
25 |
26 | @Bind(R.id.drawer_layout)
27 | DrawerLayout drawer;
28 | @Bind(R.id.nav_view)
29 | NavigationView navigationView;
30 | @Bind(R.id.toolbar)
31 | Toolbar toolbar;
32 | @Bind(R.id.fab)
33 | FloatingActionButton fab;
34 | @Bind(R.id.pager)
35 | ViewPager mViewpager;
36 |
37 | //custom
38 |
39 | MainPagerAdapter mPagerAdapter;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 | ButterKnife.bind(this);
46 | setSupportActionBar(toolbar);
47 |
48 | fab.setOnClickListener(view -> Snackbar.make(view, "这个按钮没啥用", Snackbar.LENGTH_LONG)
49 | .setAction("Action", null).show());
50 |
51 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
52 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
53 | drawer.setDrawerListener(toggle);
54 | toggle.syncState();
55 |
56 | navigationView.setNavigationItemSelectedListener(this);
57 |
58 | //custom
59 |
60 | mPagerAdapter = new MainPagerAdapter(getFragmentManager());
61 | mViewpager.setAdapter(mPagerAdapter);
62 | mViewpager.setOffscreenPageLimit(2);//使6个fragment都保持活动 // FIXME: 15/12/1 用 fragment.saveState 来替换
63 | mViewpager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
64 | @Override
65 | public void onPageSelected(int position) {
66 | mPagerAdapter.pageSelected(MainActivity.this, navigationView, position);
67 | }
68 | });
69 |
70 | //执行一次,初始化 显示标题, 抽屉选中项
71 | // mViewpager.setCurrentItem(0);//默认为0时不用写
72 | mPagerAdapter.pageSelected(this, navigationView, 0);
73 | }
74 |
75 | @Override
76 | public void onBackPressed() {
77 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
78 | if (drawer.isDrawerOpen(GravityCompat.START)) {
79 | drawer.closeDrawer(GravityCompat.START);
80 | } else {
81 | super.onBackPressed();
82 | }
83 | }
84 |
85 | @Override
86 | public boolean onCreateOptionsMenu(Menu menu) {
87 | // Inflate the menu; this adds items to the action bar if it is present.
88 | getMenuInflater().inflate(R.menu.main, menu);
89 | return true;
90 | }
91 |
92 | @Override
93 | public boolean onOptionsItemSelected(MenuItem item) {
94 | // Handle action bar item clicks here. The action bar will
95 | // automatically handle clicks on the Home/Up button, so long
96 | // as you specify a parent activity in AndroidManifest.xml.
97 | int id = item.getItemId();
98 |
99 | //noinspection SimplifiableIfStatement
100 | if (id == R.id.action_download) {
101 | return true;
102 | }
103 |
104 | return super.onOptionsItemSelected(item);
105 | }
106 |
107 | @SuppressWarnings("StatementWithEmptyBody")
108 | @Override
109 | public boolean onNavigationItemSelected(MenuItem item) {
110 | // Handle navigation view item clicks here.
111 | int id = item.getItemId();
112 |
113 | if (id == R.id.nav_newest) {
114 | mViewpager.setCurrentItem(MainPagerAdapter.NEWEST_INDEX);
115 | } else if (id == R.id.nav_best) {
116 | mViewpager.setCurrentItem(MainPagerAdapter.BEST_INDEX);
117 | } else if (id == R.id.nav_artist) {
118 | mViewpager.setCurrentItem(MainPagerAdapter.ARTIST_INDEX);
119 | } else if (id == R.id.nav_category) {
120 | mViewpager.setCurrentItem(MainPagerAdapter.CATEGORY_INDEX);
121 | } else if (id == R.id.nav_abc) {
122 | mViewpager.setCurrentItem(MainPagerAdapter.ABC_INDEX);
123 | } else if (id == R.id.nav_search) {
124 | mViewpager.setCurrentItem(MainPagerAdapter.SEARCH_INDEX);
125 | } else if (id == R.id.nav_downloaded) {
126 | mViewpager.setCurrentItem(MainPagerAdapter.DOWNLOADED_INDEX);
127 | } else if (id == R.id.nav_download_manage) {
128 | DownloadManagerActivity.launch(this);
129 | } else if (id == R.id.nav_share) {
130 |
131 | } else if (id == R.id.nav_send) {
132 |
133 | }
134 |
135 | drawer.closeDrawer(GravityCompat.START);
136 | return true;
137 | }
138 |
139 |
140 | @Override
141 | public void onDMDownloadSuccess(Book book) {
142 | Snackbar.make(mViewpager, String.format(getString(R.string.download_book_success), book.name), Snackbar.LENGTH_LONG).setAction(R.string.action_check, v -> {
143 | // FIXME: 15/11/20 跳转到下载列表页面.
144 | }).show();
145 | }
146 |
147 | @Override
148 | public void onDMDownloadFail(Book book) {
149 | Snackbar.make(mViewpager, String.format(getString(R.string.download_book_fail), book.name), Snackbar.LENGTH_LONG).show();
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/adapter/BookGridRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.fanhl.doujinMoe.R;
12 | import com.fanhl.doujinMoe.api.PageApi;
13 | import com.fanhl.doujinMoe.api.common.DouJinMoeUrl;
14 | import com.fanhl.doujinMoe.model.Book;
15 | import com.fanhl.doujinMoe.ui.common.AbsRecyclerViewAdapter;
16 | import com.fanhl.doujinMoe.ui.widget.TextDrawable;
17 | import com.fanhl.doujinMoe.util.ColorGenerator;
18 | import com.fanhl.doujinMoe.util.Utility;
19 | import com.squareup.picasso.Picasso;
20 |
21 | import java.util.List;
22 |
23 | import butterknife.Bind;
24 | import butterknife.ButterKnife;
25 |
26 | /**
27 | * Created by fanhl on 15/10/29.
28 | */
29 | public class BookGridRecyclerAdapter extends AbsRecyclerViewAdapter {
30 | public static final String TAG = BookGridRecyclerAdapter.class.getSimpleName();
31 |
32 | private final List list;
33 | private final ColorGenerator mColorGenerator;
34 |
35 | public BookGridRecyclerAdapter(Context context, RecyclerView mRecyclerView, List list) {
36 | super(context, mRecyclerView);
37 | this.list = list;
38 |
39 | mColorGenerator = ColorGenerator.MATERIAL;
40 | }
41 |
42 | @Override
43 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
44 | View view = LayoutInflater.from(context).inflate(R.layout.list_item_book_card, parent, false);
45 | return new ViewHolder(view);
46 | }
47 |
48 | @Override
49 | public void onBindViewHolder(ViewHolder holder, int position) {
50 | super.onBindViewHolder(holder, position);
51 | Book item = list.get(position);
52 | int color = this.mColorGenerator.getColor(item.name);
53 | holder.bind(this.context, item, color);
54 | }
55 |
56 | @Override
57 | public int getItemCount() {
58 | return list.size();
59 | }
60 |
61 | @Override
62 | public void onViewRecycled(ViewHolder holder) {
63 | super.onViewRecycled(holder);
64 | }
65 |
66 | public void addItem(Book item) {
67 | list.add(item);
68 | notifyItemInserted(list.size() - 1);
69 | }
70 |
71 | public void addItems(List books) {
72 | int positionStart = list.size();
73 | list.addAll(books);
74 | notifyItemRangeInserted(positionStart, books.size());
75 | }
76 |
77 | public void clear() {
78 | int itemCount = list.size();
79 | list.clear();
80 | notifyItemRangeRemoved(0, itemCount);
81 | }
82 |
83 | public class ViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder {
84 | @Bind(R.id.preview)
85 | ImageView mPreview;
86 | @Bind(R.id.title)
87 | TextView mTitle;
88 |
89 | public Book item;
90 |
91 | public ViewHolder(View itemView) {
92 | super(itemView);
93 | ButterKnife.bind(this, itemView);
94 | }
95 |
96 | private void bind(Context context, Book item, int color) {
97 | mTitle.setText(item.name);
98 |
99 | if (item.isDownloaded()) {
100 | Picasso.with(context)
101 | .load(PageApi.getPageFile(context, item, 0))
102 | .fit()
103 | .centerInside()
104 | .into(mPreview);
105 | } else {
106 | TextDrawable drawablePlaceHolder = TextDrawable.builder().buildRect(Utility.getFirstCharacter(item.name), color);
107 | Picasso.with(context)
108 | .load(DouJinMoeUrl.previewUrl(item.token))
109 | .placeholder(drawablePlaceHolder)
110 | .fit()
111 | .centerInside()
112 | .into(mPreview);
113 | }
114 |
115 | this.item = item;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/adapter/GalleryPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.adapter;
2 |
3 | import android.app.Fragment;
4 | import android.app.FragmentManager;
5 | import android.support.v13.app.FragmentPagerAdapter;
6 |
7 | import com.fanhl.doujinMoe.model.Book;
8 | import com.fanhl.doujinMoe.ui.fragment.BookPageFragment;
9 |
10 | public class GalleryPagerAdapter extends FragmentPagerAdapter {
11 |
12 | private BookPageFragment[] fragments;
13 | private Book book;
14 |
15 | public GalleryPagerAdapter(FragmentManager fm, Book book) {
16 | super(fm);
17 | this.fragments = new BookPageFragment[book.count];
18 | this.book = book;
19 | }
20 |
21 | @Override
22 | public Fragment getItem(int position) {
23 | if (fragments[position] == null) fragments[position] = BookPageFragment.newInstance(book, position);
24 | return fragments[position];
25 | }
26 |
27 | @Override
28 | public int getCount() {
29 | return book.count;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/adapter/MainPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.adapter;
2 |
3 | import android.app.Fragment;
4 | import android.app.FragmentManager;
5 | import android.support.design.widget.NavigationView;
6 | import android.support.v13.app.FragmentPagerAdapter;
7 |
8 | import com.fanhl.doujinMoe.R;
9 | import com.fanhl.doujinMoe.ui.MainActivity;
10 | import com.fanhl.doujinMoe.ui.fragment.main.AbcFragment;
11 | import com.fanhl.doujinMoe.ui.fragment.main.ArtistFragment;
12 | import com.fanhl.doujinMoe.ui.fragment.main.BestFragment;
13 | import com.fanhl.doujinMoe.ui.fragment.main.CategoryFragment;
14 | import com.fanhl.doujinMoe.ui.fragment.main.DownloadedFragment;
15 | import com.fanhl.doujinMoe.ui.fragment.main.NewestFragment;
16 | import com.fanhl.doujinMoe.ui.fragment.main.SearchFragment;
17 |
18 | /**
19 | * Created by fanhl on 15/11/5.
20 | */
21 | public class MainPagerAdapter extends FragmentPagerAdapter {
22 |
23 | public static final int NEWEST_INDEX = 0;
24 | public static final int BEST_INDEX = 1;
25 | public static final int ARTIST_INDEX = 2;
26 | public static final int CATEGORY_INDEX = 3;
27 | public static final int ABC_INDEX = 4;
28 | public static final int SEARCH_INDEX = 5;
29 | public static final int DOWNLOADED_INDEX = 6;
30 |
31 | public static final int PAGE_COUNT = 7;
32 |
33 | private NewestFragment newestFragment;
34 | private BestFragment bestFragment;
35 | private ArtistFragment artistFragment;
36 | private CategoryFragment categoryFragment;
37 | private AbcFragment abcFragment;
38 | private SearchFragment searchFragment;
39 | private DownloadedFragment downloadedFragment;
40 |
41 | public MainPagerAdapter(FragmentManager fm) {
42 | super(fm);
43 | }
44 |
45 | @Override
46 | public Fragment getItem(int position) {
47 | switch (position) {
48 | case NEWEST_INDEX:
49 | if (newestFragment == null) newestFragment = NewestFragment.newInstance();
50 | return newestFragment;
51 | case BEST_INDEX:
52 | if (bestFragment == null) bestFragment = BestFragment.newInstance();
53 | return bestFragment;
54 | case ARTIST_INDEX:
55 | if (artistFragment == null) artistFragment = ArtistFragment.newInstance();
56 | return artistFragment;
57 | case CATEGORY_INDEX:
58 | if (categoryFragment == null) categoryFragment = CategoryFragment.newInstance();
59 | return categoryFragment;
60 | case ABC_INDEX:
61 | if (abcFragment == null) abcFragment = AbcFragment.newInstance();
62 | return abcFragment;
63 | case SEARCH_INDEX:
64 | if (searchFragment == null) searchFragment = SearchFragment.newInstance();
65 | return searchFragment;
66 | case DOWNLOADED_INDEX:
67 | if (downloadedFragment == null) downloadedFragment = DownloadedFragment.newInstance();
68 | return downloadedFragment;
69 | default:
70 | return null;
71 | }
72 | }
73 |
74 | /**
75 | * 方法为title改名等
76 | *
77 | * @param activity
78 | * @param navigationView
79 | * @param position
80 | */
81 | public void pageSelected(MainActivity activity, NavigationView navigationView, int position) {
82 | switch (position) {
83 | case NEWEST_INDEX:
84 | activity.setTitle(activity.getString(R.string.title_newest));
85 | navigationView.setCheckedItem(R.id.nav_newest);
86 | break;
87 | case BEST_INDEX:
88 | activity.setTitle(activity.getString(R.string.title_best));
89 | navigationView.setCheckedItem(R.id.nav_best);
90 | break;
91 | case ARTIST_INDEX:
92 | activity.setTitle(activity.getString(R.string.title_artist));
93 | navigationView.setCheckedItem(R.id.nav_artist);
94 | break;
95 | case CATEGORY_INDEX:
96 | activity.setTitle(activity.getString(R.string.title_category));
97 | navigationView.setCheckedItem(R.id.nav_category);
98 | break;
99 | case ABC_INDEX:
100 | activity.setTitle(activity.getString(R.string.title_abc));
101 | navigationView.setCheckedItem(R.id.nav_abc);
102 | break;
103 | case SEARCH_INDEX:
104 | activity.setTitle(activity.getString(R.string.title_search));
105 | navigationView.setCheckedItem(R.id.nav_search);
106 | break;
107 | case DOWNLOADED_INDEX:
108 | activity.setTitle(activity.getString(R.string.title_downloaded));
109 | navigationView.setCheckedItem(R.id.nav_downloaded);
110 | break;
111 | default:
112 | break;
113 | }
114 | }
115 |
116 | @Override
117 | public int getCount() {
118 | return PAGE_COUNT;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/adapter/PageGridRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 |
10 | import com.fanhl.doujinMoe.R;
11 | import com.fanhl.doujinMoe.api.PageApi;
12 | import com.fanhl.doujinMoe.model.Book;
13 | import com.fanhl.doujinMoe.ui.common.AbsRecyclerViewAdapter;
14 | import com.squareup.picasso.MemoryPolicy;
15 | import com.squareup.picasso.Picasso;
16 |
17 | import butterknife.Bind;
18 | import butterknife.ButterKnife;
19 |
20 | /**
21 | * Created by fanhl on 15/11/6.
22 | */
23 | public class PageGridRecyclerAdapter extends AbsRecyclerViewAdapter {
24 | private final Book book;
25 |
26 | public PageGridRecyclerAdapter(Context context, RecyclerView mRecyclerView, Book book) {
27 | super(context, mRecyclerView);
28 | this.book = book;
29 | }
30 |
31 | @Override
32 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
33 | View view = LayoutInflater.from(context).inflate(R.layout.list_item_page_card, parent, false);
34 | return new ViewHolder(view);
35 | }
36 |
37 | @Override
38 | public void onBindViewHolder(ViewHolder holder, int position) {
39 | super.onBindViewHolder(holder, position);
40 | holder.bind(this.context, book, position);
41 | }
42 |
43 | @Override
44 | public int getItemCount() {
45 | return book.pages.size();
46 | }
47 |
48 | public class ViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder {
49 | @Bind(R.id.preview)
50 | ImageView mPreview;
51 |
52 | public ViewHolder(View itemView) {
53 | super(itemView);
54 | ButterKnife.bind(this, itemView);
55 | }
56 |
57 | public void bind(Context context, Book book, int position) {
58 | if (book.isDownloaded()) {
59 | Picasso.with(context)
60 | .load(PageApi.getPageFile(context, book, position))
61 | .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)//不缓存大图到内存
62 | // .resize(DisplayUtil.dip2px(context, 250), DisplayUtil.dip2px(context, 250))
63 | .fit()
64 | .centerInside()
65 | // .centerCrop()
66 | .into(mPreview);
67 | } else {
68 | Picasso.with(context)
69 | .load(book.pages.get(position).preview)
70 | .fit()
71 | .centerInside()
72 | .into(mPreview);
73 | }
74 | }
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/adapter/downloadManager/AbsDownloadManagerRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.adapter.downloadManager;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.FrameLayout;
11 | import android.widget.ImageView;
12 | import android.widget.TextView;
13 |
14 | import com.fanhl.doujinMoe.R;
15 | import com.fanhl.doujinMoe.api.PageApi;
16 | import com.fanhl.doujinMoe.api.common.DouJinMoeUrl;
17 | import com.fanhl.doujinMoe.model.Book;
18 | import com.fanhl.doujinMoe.ui.common.AbsRecyclerViewAdapter;
19 | import com.fanhl.doujinMoe.ui.widget.TextDrawable;
20 | import com.fanhl.doujinMoe.util.ColorGenerator;
21 | import com.fanhl.doujinMoe.util.DownloadManager;
22 | import com.fanhl.doujinMoe.util.Utility;
23 | import com.squareup.picasso.Picasso;
24 |
25 | import butterknife.Bind;
26 | import butterknife.ButterKnife;
27 |
28 | /**
29 | * Created by fanhl on 15/11/24.
30 | */
31 | public abstract class AbsDownloadManagerRecyclerAdapter extends AbsRecyclerViewAdapter {
32 | public static final String TAG = AbsDownloadManagerRecyclerAdapter.class.getSimpleName();
33 |
34 | protected final DownloadManager downloadManager;
35 | private final Handler uihandler;
36 |
37 | public AbsDownloadManagerRecyclerAdapter(Context context, RecyclerView mRecyclerView, DownloadManager downloadManager) {
38 | super(context, mRecyclerView);
39 | this.context = context;
40 | this.downloadManager = downloadManager;
41 | uihandler = new Handler();
42 | }
43 |
44 | @Override
45 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
46 | View view = LayoutInflater.from(context).inflate(R.layout.list_item_download_card, parent, false);
47 | return new ViewHolder(context, view);
48 | }
49 |
50 | @Override
51 | public void onViewRecycled(ViewHolder holder) {
52 | super.onViewRecycled(holder);
53 | holder.unbind(downloadManager);
54 | }
55 |
56 |
57 | public class ViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder implements DownloadManager.OnDownloadProgressChangeListener {
58 | private final Context context;
59 |
60 | @Bind(R.id.preview)
61 | ImageView mPreview;
62 | @Bind(R.id.title)
63 | TextView mTitle;
64 | @Bind(R.id.download_container)
65 | FrameLayout mDownloadContainer;
66 | @Bind(R.id.progress)
67 | TextView mProgress;
68 |
69 | public Book item;
70 |
71 | public ViewHolder(Context context, View itemView) {
72 | super(itemView);
73 | this.context = context;
74 | ButterKnife.bind(this, itemView);
75 | }
76 |
77 | public void bind(Book item) {
78 | if (item == null) {
79 | Log.e(TAG, "书籍为空");
80 | return;
81 | }
82 | mTitle.setText(item.name);
83 | if (item.isDownloaded()) {
84 | Picasso.with(AbsDownloadManagerRecyclerAdapter.this.context)
85 | .load(PageApi.getPageFile(AbsDownloadManagerRecyclerAdapter.this.context, item, 0))
86 | .into(mPreview);
87 | mDownloadContainer.setVisibility(View.GONE);
88 | } else {
89 | TextDrawable drawablePlaceHolder = TextDrawable.builder().buildRect(Utility.getFirstCharacter(item.name), getColor(item));
90 | Picasso.with(AbsDownloadManagerRecyclerAdapter.this.context)
91 | .load(DouJinMoeUrl.previewUrl(item.token))
92 | .placeholder(drawablePlaceHolder)
93 | .into(mPreview);
94 |
95 | if (item.isWaitDownload()) {
96 | mProgress.setText(R.string.wait_for_download);
97 | } else if (item.isDownloading()) {
98 | mProgress.setText(context.getResources().getString(R.string.info_total_pages, item.downloadedPosition + 1, item.count));
99 | } else {
100 | mDownloadContainer.setVisibility(View.GONE);
101 | }
102 | }
103 |
104 | this.item = item;
105 | }
106 |
107 | public void bind(Book book, DownloadManager downloadManager) {
108 | bind(book);
109 | downloadManager.addOnDownloadProgressChangeListener(this);
110 | }
111 |
112 | public void unbind(DownloadManager downloadManager) {
113 | downloadManager.removeOnDownloadProgressChangeListener(this);
114 | }
115 |
116 | private int getColor(Book item) {
117 | return ColorGenerator.MATERIAL.getColor(item.name);
118 | }
119 |
120 | @Override
121 | public void onDownloadProgressChanged(Book book) {
122 | if (book == null || !book.name.equals(item.name)) return;
123 |
124 | //ui Thread
125 | uihandler.post(() -> mProgress.setText(context.getResources().getString(R.string.info_total_pages, book.downloadedPosition + 1, book.count)));
126 | // FIXME: 15/11/28 以下无用删除
127 | // if (book.downloadedPosition + 1 == book.count) {
128 | // uihandler.post(() -> mDownloadContainer.setVisibility(View.GONE));
129 | // }
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/common/AbsActivity.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.common;
2 |
3 | import android.os.Build;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.MenuItem;
7 |
8 | import com.fanhl.doujinMoe.App;
9 | import com.fanhl.doujinMoe.R;
10 | import com.fanhl.doujinMoe.model.Book;
11 | import com.fanhl.doujinMoe.util.DownloadManager;
12 |
13 | /**
14 | * Created by fanhl on 15/10/30.
15 | */
16 | public abstract class AbsActivity extends AppCompatActivity implements DownloadManager.OnDownloadManagerInteractionListener {
17 |
18 | protected App app;
19 |
20 | private DownloadManager downloadManager;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 |
26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
27 | getWindow().setStatusBarColor(getResources().getColor(R.color.primary));
28 | getWindow().setNavigationBarColor(getResources().getColor(R.color.primary));
29 | }
30 |
31 | app = ((App) getApplication());
32 | downloadManager = app.getDownloadManager();
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | downloadManager.registerOnDownloadManagerInteractionListener(this);
39 | }
40 |
41 | @Override
42 | protected void onPause() {
43 | super.onPause();
44 | downloadManager.unregisterOnDownloadManagerInteractionListener(this);
45 | }
46 |
47 | @Override
48 | public boolean onOptionsItemSelected(MenuItem item) {
49 | if (item.getItemId() == android.R.id.home) {
50 | this.onBackPressed();
51 | return true;
52 | }
53 |
54 | return super.onOptionsItemSelected(item);
55 | }
56 |
57 | @Override
58 | public void onDMDownloadSuccess(Book book) {
59 | //在需要响应的Activity中实现
60 | }
61 |
62 | @Override
63 | public void onDMDownloadFail(Book book) {
64 | //在需要响应的Activity中实现
65 | }
66 |
67 | public DownloadManager getDownloadManager() {
68 | return downloadManager;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/common/AbsRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.common;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public abstract class AbsRecyclerViewAdapter extends RecyclerView.Adapter {
11 |
12 | protected Context context;
13 |
14 | protected RecyclerView mRecyclerView;
15 | protected List mListeners = new ArrayList<>();
16 |
17 | public AbsRecyclerViewAdapter(Context context, RecyclerView recyclerView) {
18 | this.context = context;
19 |
20 | this.mRecyclerView = recyclerView;
21 | this.mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
22 | @Override
23 | public void onScrollStateChanged(RecyclerView rv, int newState) {
24 | for (RecyclerView.OnScrollListener listener : mListeners) {
25 | listener.onScrollStateChanged(rv, newState);
26 | }
27 | }
28 |
29 | @Override
30 | public void onScrolled(RecyclerView rv, int dx, int dy) {
31 | for (RecyclerView.OnScrollListener listener : mListeners) {
32 | listener.onScrolled(rv, dx, dy);
33 | }
34 | }
35 | });
36 | }
37 |
38 | public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
39 | mListeners.add(listener);
40 | }
41 |
42 | public interface OnItemClickListener {
43 | void onItemClick(int position, AbsRecyclerViewAdapter.ClickableViewHolder holder);
44 | }
45 |
46 | public interface OnItemLongClickListener {
47 | boolean onItemLongClick(int position, AbsRecyclerViewAdapter.ClickableViewHolder holder);
48 | }
49 |
50 | private OnItemClickListener itemClickListener;
51 | private OnItemLongClickListener itemLongClickListener;
52 |
53 | public void setOnItemClickListener(OnItemClickListener listener) {
54 | this.itemClickListener = listener;
55 | }
56 |
57 | public void setOnItemLongClickListener(OnItemLongClickListener listener) {
58 | this.itemLongClickListener = listener;
59 | }
60 |
61 | @Override
62 | public void onBindViewHolder(final CVH holder, final int position) {
63 | holder.itemView.setOnClickListener(v -> {
64 | if (itemClickListener != null) {
65 | itemClickListener.onItemClick(position, holder);
66 | }
67 | });
68 | holder.itemView.setOnLongClickListener(v -> itemLongClickListener != null && itemLongClickListener.onItemLongClick(position, holder));
69 | }
70 |
71 | public class ClickableViewHolder extends RecyclerView.ViewHolder {
72 | public ClickableViewHolder(View itemView) {
73 | super(itemView);
74 | }
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/AbsFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment;
2 |
3 | import android.app.Fragment;
4 |
5 | import com.fanhl.doujinMoe.App;
6 | import com.fanhl.doujinMoe.ui.common.AbsActivity;
7 |
8 | /**
9 | * Created by fanhl on 15/11/20.
10 | */
11 | public abstract class AbsFragment extends Fragment {
12 |
13 | public App app() {
14 | return (App) getActivity().getApplication();
15 | }
16 |
17 | protected AbsActivity getAbsActivity() {
18 | return ((AbsActivity) getActivity());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/BookPageFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment;
2 |
3 |
4 | import android.app.Fragment;
5 | import android.content.res.Configuration;
6 | import android.os.Bundle;
7 | import android.support.v7.widget.AppCompatTextView;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.FrameLayout;
13 | import android.widget.ImageView;
14 |
15 | import com.fanhl.doujinMoe.R;
16 | import com.fanhl.doujinMoe.api.PageApi;
17 | import com.fanhl.doujinMoe.model.Book;
18 | import com.fanhl.doujinMoe.model.Page;
19 | import com.fanhl.doujinMoe.ui.GalleryActivity;
20 | import com.fanhl.photoview.PhotoViewAttacherEx;
21 | import com.fanhl.util.DisplayUtil;
22 | import com.fanhl.util.GsonUtil;
23 | import com.squareup.picasso.Callback;
24 | import com.squareup.picasso.Picasso;
25 |
26 | import butterknife.Bind;
27 | import butterknife.ButterKnife;
28 | import uk.co.senab.photoview.PhotoView;
29 |
30 | /**
31 | * A simple {@link Fragment} subclass.
32 | * Use the {@link BookPageFragment#newInstance} factory method to
33 | * create an instance of this fragment.
34 | */
35 | public class BookPageFragment extends Fragment {
36 | public static final String TAG = BookPageFragment.class.getSimpleName();
37 |
38 | private static final String ARG_BOOK_DATA = "ARG_BOOK_DATA";
39 | private static final String ARG_POSITION = "ARG_POSITION";
40 |
41 | @Bind(R.id.backgroundView)
42 | FrameLayout mBackgroundView;
43 | @Bind(R.id.textView)
44 | AppCompatTextView mTextView;
45 | @Bind(R.id.imageView)
46 | PhotoView mImageView;
47 |
48 | private Book book;
49 | private int position;
50 |
51 | private PhotoViewAttacherEx mAttacher;
52 |
53 | /**
54 | * @param book
55 | * @param position
56 | * @return
57 | */
58 | public static BookPageFragment newInstance(Book book, int position) {
59 | BookPageFragment fragment = new BookPageFragment();
60 | Bundle args = new Bundle();
61 | args.putString(ARG_BOOK_DATA, GsonUtil.json(book));
62 | args.putInt(ARG_POSITION, position);
63 | fragment.setArguments(args);
64 | return fragment;
65 | }
66 |
67 | @Override
68 | public void onCreate(Bundle savedInstanceState) {
69 | super.onCreate(savedInstanceState);
70 | Bundle bundle = getArguments();
71 | book = GsonUtil.obj(bundle.getString(ARG_BOOK_DATA), Book.class);
72 | position = bundle.getInt(ARG_POSITION);
73 | }
74 |
75 | @Override
76 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
77 | Bundle savedInstanceState) {
78 | // Log.d(TAG, "onCreateView page position:" + position);
79 | View view = inflater.inflate(R.layout.fragment_book_page, container, false);
80 | ButterKnife.bind(this, view);
81 |
82 | mBackgroundView.setOnClickListener(view1 -> ((GalleryActivity) getActivity()).toggle());
83 | mTextView.setText(String.valueOf(position + 1));
84 | mAttacher = new PhotoViewAttacherEx(mImageView);
85 | mAttacher.setOnViewTapListener((view1, v, v1) -> ((GalleryActivity) getActivity()).toggle());
86 |
87 | refreshForOrientation(getResources().getConfiguration());
88 |
89 | if (book.isDownloaded() || PageApi.isPageDownloaded(getActivity(), book, position)) {
90 | Picasso.with(getActivity())
91 | .load(PageApi.getPageFile(getActivity(), book, position))
92 | .fit()
93 | .centerInside()
94 | .into(mImageView, new Callback.EmptyCallback() {
95 | @Override
96 | public void onSuccess() {
97 | mAttacher.update();
98 | }
99 | });
100 | } else {
101 | Page page = book.pages.get(position);
102 | Picasso.with(getActivity())
103 | .load(page.href)
104 | .fit()
105 | .centerInside()
106 | .into(mImageView, new Callback.EmptyCallback() {
107 | @Override
108 | public void onSuccess() {
109 | mAttacher.update();
110 | }
111 | });
112 | }
113 |
114 | return view;
115 | }
116 |
117 | @Override
118 | public void onDestroyView() {
119 | // Log.d(TAG, "onDestroyView page position:" + position);
120 | super.onDestroyView();
121 | ButterKnife.unbind(this);
122 | }
123 |
124 | @Override
125 | public void onConfigurationChanged(Configuration newConfig) {
126 | super.onConfigurationChanged(newConfig);
127 | Log.d(TAG, "横竖屏切换");
128 | refreshForOrientation(newConfig);
129 | }
130 |
131 | private void refreshForOrientation(Configuration newConfig) {
132 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
133 | mAttacher.setScaleType(ImageView.ScaleType.FIT_CENTER);
134 | mAttacher.setParentIsVertical(false);
135 | } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
136 | if (position >= book.position) {
137 | // Log.d(TAG, "refreshForOrientation page position:" + position+ " book.position:"+book.position+" CROP_TOP.");
138 | mAttacher.setScaleType(PhotoViewAttacherEx.ScaleTypeEx.CROP_TOP);
139 | } else {
140 | // Log.d(TAG, "refreshForOrientation page position:" + position+ " book.position:"+book.position+" CROP_BOTTOM.");
141 | mAttacher.setScaleType(PhotoViewAttacherEx.ScaleTypeEx.CROP_BOTTOM);
142 | }
143 | mAttacher.setParentIsVertical(true);
144 | }
145 | }
146 |
147 | private int dp2px(float dp) {
148 | return DisplayUtil.dip2px(getActivity(), dp);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/downloadManager/AbsDownloadManagerFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.downloadManager;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import com.fanhl.doujinMoe.interfaceX.OnDownloadManagerBookChangeListener;
7 | import com.fanhl.doujinMoe.ui.DownloadManagerActivity;
8 | import com.fanhl.doujinMoe.ui.fragment.AbsFragment;
9 |
10 | /**
11 | * Created by fanhl on 15/11/27.
12 | */
13 | public abstract class AbsDownloadManagerFragment extends AbsFragment implements OnDownloadManagerBookChangeListener {
14 | public static final String TAG = AbsDownloadManagerFragment.class.getSimpleName();
15 |
16 | // FIXME: 15/11/28 到没问题 下面就删了
17 | // /**
18 | // * 这个方法实际没有调用!!!,所以我还是用 onAttach(Activity activity) 了!!?
19 | // * fixme 两个方法都实现的话,会不会重复?
20 | // * @param context
21 | // */
22 | // @Override
23 | // public void onAttach(Context context) {
24 | // super.onAttach(context);
25 | // Log.d(TAG, "onAttach(context) addOnDownloadManagerBookChangeListener");
26 | // ((DownloadManagerActivity) context).addOnDownloadManagerBookChangeListener(this);
27 | // }
28 |
29 | @Override
30 | public void onAttach(Activity activity) {
31 | super.onAttach(activity);
32 | Log.d(TAG, "onAttach(activity) addOnDownloadManagerBookChangeListener");
33 | ((DownloadManagerActivity) activity).addOnDownloadManagerBookChangeListener(this);
34 | }
35 |
36 | @Override
37 | public void onDetach() {
38 | super.onDetach();
39 | Log.d(TAG, "onDetach removeOnDownloadManagerBookChangeListener");
40 | ((DownloadManagerActivity) getActivity()).removeOnDownloadManagerBookChangeListener(this);
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/downloadManager/DownloadFailFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.downloadManager;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.design.widget.Snackbar;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.StaggeredGridLayoutManager;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.fanhl.doujinMoe.R;
14 | import com.fanhl.doujinMoe.model.Book;
15 | import com.fanhl.doujinMoe.ui.DetailsActivity;
16 | import com.fanhl.doujinMoe.ui.adapter.downloadManager.AbsDownloadManagerRecyclerAdapter;
17 | import com.fanhl.doujinMoe.util.DownloadManager;
18 |
19 | import butterknife.Bind;
20 | import butterknife.ButterKnife;
21 |
22 | /**
23 | * Created by fanhl on 15/11/27.
24 | */
25 | public class DownloadFailFragment extends AbsDownloadManagerFragment {
26 | public static final String TAG = DownloadFailFragment.class.getSimpleName();
27 |
28 | @Bind(R.id.recycler_view)
29 | RecyclerView mRecyclerView;
30 |
31 | AbsDownloadManagerRecyclerAdapter mAdapter;
32 | private DownloadManager downloadManager;
33 |
34 | public static DownloadFailFragment newInstance() {
35 | return new DownloadFailFragment();
36 | }
37 |
38 | @Nullable
39 | @Override
40 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
41 | View view = inflater.inflate(R.layout.fragment_recycle, container, false);
42 | ButterKnife.bind(this, view);
43 | assignViews();
44 | return view;
45 | }
46 |
47 | @Override
48 | public void onDestroyView() {
49 | super.onDestroyView();
50 | mRecyclerView.setAdapter(null);
51 | ButterKnife.unbind(this);
52 | }
53 |
54 | private void assignViews() {
55 | //流式布局
56 | StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(getResources().getInteger(R.integer.span_count_book), StaggeredGridLayoutManager.VERTICAL);
57 | mRecyclerView.setLayoutManager(mLayoutManager);
58 | mRecyclerView.setHasFixedSize(true);
59 |
60 | //mRecyclerView
61 | downloadManager = getAbsActivity().getDownloadManager();
62 | mAdapter = new AbsDownloadManagerRecyclerAdapter(getActivity(), mRecyclerView, downloadManager) {
63 | @Override
64 | public void onBindViewHolder(ViewHolder holder, int position) {
65 | super.onBindViewHolder(holder, position);
66 | holder.bind(downloadManager.getFailBooks().get(position));
67 | }
68 |
69 | @Override
70 | public int getItemCount() {
71 | return downloadManager.getFailBooks().size();
72 | }
73 | };
74 | mRecyclerView.setAdapter(mAdapter);
75 | mAdapter.setOnItemClickListener((position, viewHolder) -> DetailsActivity.launch(getActivity(), ((AbsDownloadManagerRecyclerAdapter.ViewHolder) viewHolder).item));
76 | mAdapter.setOnItemLongClickListener((position, holder) -> {
77 | Log.d(TAG, "加入重新下载确认.");
78 | Snackbar.make(mRecyclerView, R.string.text_retry_download, Snackbar.LENGTH_LONG).setAction(R.string.action_download, v -> {
79 | downloadManager.retryDownload(((AbsDownloadManagerRecyclerAdapter.ViewHolder) holder).item);
80 | }).show();
81 | return true;
82 | });
83 | }
84 |
85 | @Override
86 | public void onDownloadBookChanged(Book book, boolean success) {
87 | Log.d(TAG, "onDownloadBookChanged 刷新列表");
88 | mAdapter.notifyDataSetChanged();
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/downloadManager/DownloadSuccessFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.downloadManager;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.support.v7.widget.StaggeredGridLayoutManager;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.fanhl.doujinMoe.R;
13 | import com.fanhl.doujinMoe.model.Book;
14 | import com.fanhl.doujinMoe.ui.DetailsActivity;
15 | import com.fanhl.doujinMoe.ui.adapter.downloadManager.AbsDownloadManagerRecyclerAdapter;
16 | import com.fanhl.doujinMoe.util.DownloadManager;
17 |
18 | import butterknife.Bind;
19 | import butterknife.ButterKnife;
20 |
21 | /**
22 | * Created by fanhl on 15/11/27.
23 | */
24 | public class DownloadSuccessFragment extends AbsDownloadManagerFragment {
25 | public static final String TAG = DownloadSuccessFragment.class.getSimpleName();
26 |
27 | @Bind(R.id.recycler_view)
28 | RecyclerView mRecyclerView;
29 |
30 | AbsDownloadManagerRecyclerAdapter mAdapter;
31 | private DownloadManager downloadManager;
32 |
33 | public static DownloadSuccessFragment newInstance() {
34 | return new DownloadSuccessFragment();
35 | }
36 |
37 | @Nullable
38 | @Override
39 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
40 | View view = inflater.inflate(R.layout.fragment_recycle, container, false);
41 | ButterKnife.bind(this, view);
42 | assignViews();
43 | return view;
44 | }
45 |
46 | @Override
47 | public void onDestroyView() {
48 | super.onDestroyView();
49 | mRecyclerView.setAdapter(null);
50 | ButterKnife.unbind(this);
51 | }
52 |
53 | private void assignViews() {
54 | //流式布局
55 | StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(getResources().getInteger(R.integer.span_count_book), StaggeredGridLayoutManager.VERTICAL);
56 | mRecyclerView.setLayoutManager(mLayoutManager);
57 | mRecyclerView.setHasFixedSize(true);
58 |
59 | //mRecyclerView
60 | downloadManager = getAbsActivity().getDownloadManager();
61 | mAdapter = new AbsDownloadManagerRecyclerAdapter(getActivity(), mRecyclerView, downloadManager) {
62 | @Override
63 | public void onBindViewHolder(ViewHolder holder, int position) {
64 | super.onBindViewHolder(holder, position);
65 | holder.bind(downloadManager.getDownloadedBooks().get(position));
66 | }
67 |
68 | @Override
69 | public int getItemCount() {
70 | return downloadManager.getDownloadedBooks().size();
71 | }
72 | };
73 | mRecyclerView.setAdapter(mAdapter);
74 | mAdapter.setOnItemClickListener((position, viewHolder) -> DetailsActivity.launch(getActivity(), ((AbsDownloadManagerRecyclerAdapter.ViewHolder) viewHolder).item));
75 | }
76 |
77 | @Override
78 | public void onDownloadBookChanged(Book book, boolean success) {
79 | Log.d(TAG, "onDownloadBookChanged 刷新列表");
80 | mAdapter.notifyDataSetChanged();
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/downloadManager/DownloadingFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.downloadManager;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.design.widget.Snackbar;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.StaggeredGridLayoutManager;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.fanhl.doujinMoe.R;
14 | import com.fanhl.doujinMoe.model.Book;
15 | import com.fanhl.doujinMoe.ui.DetailsActivity;
16 | import com.fanhl.doujinMoe.ui.adapter.downloadManager.AbsDownloadManagerRecyclerAdapter;
17 | import com.fanhl.doujinMoe.util.DownloadManager;
18 |
19 | import butterknife.Bind;
20 | import butterknife.ButterKnife;
21 |
22 | /**
23 | * Created by fanhl on 15/11/24.
24 | */
25 | public class DownloadingFragment extends AbsDownloadManagerFragment {
26 | public static final String TAG = DownloadingFragment.class.getSimpleName();
27 |
28 | // @Bind(R.id.swipe_refresh_layout)
29 | // SwipeRefreshLayout mSwipeRefreshLayout;
30 | @Bind(R.id.recycler_view)
31 | RecyclerView mRecyclerView;
32 |
33 | AbsDownloadManagerRecyclerAdapter mAdapter;
34 | private DownloadManager downloadManager;
35 |
36 | public static DownloadingFragment newInstance() {
37 | return new DownloadingFragment();
38 | }
39 |
40 | @Nullable
41 | @Override
42 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
43 | View view = inflater.inflate(R.layout.fragment_recycle, container, false);
44 | ButterKnife.bind(this, view);
45 | assignViews();
46 | return view;
47 | }
48 |
49 | @Override
50 | public void onDestroyView() {
51 | super.onDestroyView();
52 | mRecyclerView.setAdapter(null);
53 | ButterKnife.unbind(this);
54 | }
55 |
56 | private void assignViews() {
57 | //流式布局
58 | StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(getResources().getInteger(R.integer.span_count_book), StaggeredGridLayoutManager.VERTICAL);
59 | mRecyclerView.setLayoutManager(mLayoutManager);
60 | mRecyclerView.setHasFixedSize(true);
61 |
62 | //mRecyclerView
63 | downloadManager = getAbsActivity().getDownloadManager();
64 | mAdapter = new AbsDownloadManagerRecyclerAdapter(getActivity(), mRecyclerView, downloadManager) {
65 | @Override
66 | public void onBindViewHolder(ViewHolder holder, int position) {
67 | super.onBindViewHolder(holder, position);
68 | // FIXME: 15/11/27 存在一个正在下载,多个未下载时.当正在下载完成后.再notifyDataChanged后显示不正常.
69 | if (downloadManager.getDownloadingBook() != null) {
70 | if (position == 0) {
71 | holder.bind(downloadManager.getDownloadingBook(), downloadManager);
72 | } else {
73 | holder.bind(downloadManager.getWaitBooks().get(position - 1), downloadManager);
74 | }
75 | } else {
76 | holder.bind(downloadManager.getWaitBooks().get(position), downloadManager);
77 | }
78 |
79 | }
80 |
81 | @Override
82 | public int getItemCount() {
83 | return downloadManager.getWaitBooks().size() + (downloadManager.getDownloadingBook() == null ? 0 : 1);
84 | }
85 | };
86 |
87 | mRecyclerView.setAdapter(mAdapter);
88 |
89 | mAdapter.setOnItemClickListener((position, viewHolder) -> DetailsActivity.launch(getActivity(), ((AbsDownloadManagerRecyclerAdapter.ViewHolder) viewHolder).item));
90 | mAdapter.setOnItemLongClickListener((position, holder) -> {
91 | Log.d(TAG, "取消下载确认.");
92 | Snackbar.make(mRecyclerView, R.string.text_cancel_download, Snackbar.LENGTH_LONG).setAction(R.string.action_cancel, v -> {
93 | downloadManager.cancelDownload(((AbsDownloadManagerRecyclerAdapter.ViewHolder) holder).item);
94 | }).show();
95 | return true;
96 | });
97 | }
98 |
99 | @Override
100 | public void onDownloadBookChanged(Book book, boolean success) {
101 | Log.d(TAG, "onDownloadBookChanged 刷新列表");
102 | mAdapter.notifyDataSetChanged();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/AbcFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * http://m.doujin-moe.us/abc
9 | * Created by fanhl on 15/12/1.
10 | */
11 | public class AbcFragment extends AbsHomeFragment {
12 | public static AbcFragment newInstance() {
13 | return new AbcFragment();
14 | }
15 |
16 | @Override
17 | @NonNull
18 | protected String getToken() {
19 | return "abc";
20 | }
21 |
22 | /**
23 | * @return
24 | */
25 | @Override
26 | @NonNull
27 | protected String getSort() {
28 | return "name";
29 | }
30 |
31 | /**
32 | * Non-series
33 | * 0-9
34 | * A
35 | * A
36 | * B
37 | * ...
38 | * Z
39 | *
40 | * @return
41 | */
42 | @NonNull
43 | @Override
44 | protected String getParam() {
45 | return "Non-series";
46 | }
47 |
48 | @Override
49 | protected int getLoadFailMsgResId() {
50 | return R.string.text_abc_get_fail;
51 | }
52 |
53 | // FIXME: 15/12/2 过滤条件
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/AbsBookRecyclerFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.widget.SwipeRefreshLayout;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.StaggeredGridLayoutManager;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.fanhl.doujinMoe.R;
14 | import com.fanhl.doujinMoe.model.Book;
15 | import com.fanhl.doujinMoe.ui.DetailsActivity;
16 | import com.fanhl.doujinMoe.ui.adapter.BookGridRecyclerAdapter;
17 | import com.fanhl.doujinMoe.ui.fragment.AbsFragment;
18 | import com.fanhl.loadmore.OnRcvScrollListener;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | import butterknife.Bind;
24 | import butterknife.ButterKnife;
25 |
26 | /**
27 | * Created by fanhl on 15/11/10.
28 | */
29 | public abstract class AbsBookRecyclerFragment extends AbsFragment {
30 | public static final String TAG = AbsBookRecyclerFragment.class.getSimpleName();
31 |
32 | @Bind(R.id.swipe_refresh_layout)
33 | SwipeRefreshLayout mSwipeRefreshLayout;
34 | @Bind(R.id.recycler_view)
35 | RecyclerView mRecyclerView;
36 |
37 | protected BookGridRecyclerAdapter mAdapter;
38 | protected List mBooks;
39 |
40 | @Nullable
41 | @Override
42 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
43 | View view = inflater.inflate(R.layout.fragment_swipe_recycle, container, false);
44 | ButterKnife.bind(this, view);
45 | assignViews();
46 | initData();
47 | refreshData();
48 | return view;
49 | }
50 |
51 | @Override
52 | public void onDestroyView() {
53 | super.onDestroyView();
54 | ButterKnife.unbind(this);
55 | }
56 |
57 | protected void assignViews() {
58 | mSwipeRefreshLayout.setColorSchemeColors(getResources().getIntArray(R.array.refresh_array));
59 | mSwipeRefreshLayout.setOnRefreshListener(this::refreshData);
60 |
61 | //流式布局
62 | StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(getResources().getInteger(R.integer.span_count_book), StaggeredGridLayoutManager.VERTICAL);
63 | mRecyclerView.setLayoutManager(mLayoutManager);
64 | mRecyclerView.setHasFixedSize(true);
65 |
66 | //mRecyclerView
67 | mBooks = new ArrayList<>();
68 | mAdapter = new BookGridRecyclerAdapter(getActivity(), mRecyclerView, mBooks);
69 | mRecyclerView.setAdapter(mAdapter);
70 |
71 | mAdapter.setOnItemClickListener((position, viewHolder) -> {
72 | BookGridRecyclerAdapter.ViewHolder holder = (BookGridRecyclerAdapter.ViewHolder) viewHolder;
73 | DetailsActivity.launch(getActivity(), holder.item);
74 | });
75 |
76 | mRecyclerView.addOnScrollListener(new OnRcvScrollListener() {
77 | @Override
78 | public void onScrollBottom() {
79 | super.onScrollBottom();
80 | loadMore();
81 | }
82 | });
83 | }
84 |
85 | protected void initData() {
86 |
87 | }
88 |
89 | protected abstract void refreshData();
90 |
91 | protected void loadMore() {
92 | //load more data
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/AbsHomeFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.design.widget.Snackbar;
5 | import android.util.Log;
6 |
7 | import com.fanhl.doujinMoe.R;
8 | import com.fanhl.doujinMoe.common.Constants;
9 |
10 | import rx.android.schedulers.AndroidSchedulers;
11 | import rx.schedulers.Schedulers;
12 |
13 | /**
14 | * 首页(newest,best,artist...的公共父类
15 | * Created by fanhl on 15/12/1.
16 | */
17 | public abstract class AbsHomeFragment extends AbsBookRecyclerFragment {
18 | public static final String TAG = AbsHomeFragment.class.getSimpleName();
19 |
20 | /*是滞已加载完所有数据*/
21 | private boolean isLoadingComplete = false;
22 | /*loadMore用*/
23 | private boolean isLoadingData = false;
24 | private int offset = 0;
25 |
26 |
27 | @Override
28 | protected void initData() {
29 | super.initData();
30 | }
31 |
32 | @Override
33 | protected void refreshData() {
34 | if (!mSwipeRefreshLayout.isRefreshing()) mSwipeRefreshLayout.setRefreshing(true);
35 | offset = 0;
36 | loadData(false);
37 | }
38 |
39 | @Override
40 | protected void loadMore() {
41 | // 到底部自动加载
42 | loadData(true);
43 | }
44 |
45 | private void loadData(boolean isLoadMore) {
46 | if (!isLoadingData && !(isLoadMore && isLoadingComplete)) {
47 | if (!isLoadMore) Log.d(TAG, "refresh data.");
48 | else Log.d(TAG, "loading more.");
49 |
50 | isLoadingData = true;
51 |
52 | app().getClient().getHomeService()
53 | .bookList(getToken(), offset, Constants.PAGE_BOOK_COUNT_MAX, getSort(), getParam())
54 | .subscribeOn(Schedulers.io())
55 | .observeOn(AndroidSchedulers.mainThread())
56 | .subscribe(folderResponse -> {
57 | isLoadingData = false;
58 | isLoadingComplete = folderResponse.complete;
59 | if (isLoadingComplete) Log.d(TAG, "已加载完数据");
60 | offset += Constants.PAGE_BOOK_COUNT_MAX;
61 | if (mSwipeRefreshLayout == null) return;
62 | mSwipeRefreshLayout.setRefreshing(false);
63 | if (!isLoadMore) mAdapter.clear();
64 | mAdapter.addItems(folderResponse.folders);
65 | }, throwable -> {
66 | isLoadingData = false;
67 | mSwipeRefreshLayout.setRefreshing(false);
68 | if (mSwipeRefreshLayout == null) return;
69 | Log.e(NewestFragment.TAG, Log.getStackTraceString(throwable));
70 | Snackbar.make(mSwipeRefreshLayout, getLoadFailMsgResId(), Snackbar.LENGTH_LONG).setAction(R.string.action_retry, v -> refreshData()).show();
71 | });
72 | }
73 | }
74 |
75 | /**
76 | * 取得版块类型
77 | *
78 | *
newest
79 | * best
80 | * artist
81 | *
82 | * @return
83 | */
84 | @NonNull
85 | protected abstract String getToken();
86 |
87 | /**
88 | * 取得排序方式
89 | * name
90 | *
91 | *
ever
92 | * year
93 | * mouth
94 | *
95 | * @return
96 | */
97 | @NonNull
98 | protected abstract String getSort();
99 |
100 | @NonNull
101 | protected String getParam() {
102 | return "";
103 | }
104 |
105 | protected abstract int getLoadFailMsgResId();
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/ArtistFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * Created by fanhl on 15/11/8.
9 | */
10 | public class ArtistFragment extends AbsHomeFragment {
11 |
12 | public static ArtistFragment newInstance() {
13 | return new ArtistFragment();
14 | }
15 |
16 | @Override
17 | @NonNull
18 | protected String getToken() {
19 | return "artist";
20 | }
21 |
22 | @Override
23 | @NonNull
24 | protected String getSort() {
25 | return "name";
26 | }
27 |
28 | @Override
29 | protected int getLoadFailMsgResId() {
30 | return R.string.text_artist_get_fail;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/BestFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * Top Rated
9 | */
10 | public class BestFragment extends AbsHomeFragment {
11 | public static BestFragment newInstance() {
12 | return new BestFragment();
13 | }
14 |
15 | @Override
16 | @NonNull
17 | protected String getToken() {
18 | return "best";
19 | }
20 |
21 | /**
22 | * ever
23 | * year
24 | * mouth
25 | *
26 | * @return
27 | */
28 | @Override
29 | @NonNull
30 | protected String getSort() {
31 | return "mouth";
32 | }
33 |
34 | @Override
35 | protected int getLoadFailMsgResId() {
36 | return R.string.text_best_get_fail;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/CategoryFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * http://m.doujin-moe.us/category
9 | * Created by fanhl on 15/12/1.
10 | */
11 | public class CategoryFragment extends AbsHomeFragment {
12 | public static CategoryFragment newInstance() {
13 | return new CategoryFragment();
14 | }
15 |
16 | // FIXME: 15/12/1 注,这里点item进去不是书籍,而是另一个列表了
17 |
18 | @Override
19 | @NonNull
20 | protected String getToken() {
21 | return "category";
22 | }
23 |
24 | /**
25 | * @return
26 | */
27 | @Override
28 | @NonNull
29 | protected String getSort() {
30 | return "name";
31 | }
32 |
33 | @Override
34 | protected int getLoadFailMsgResId() {
35 | return R.string.text_category_get_fail;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/DownloadedFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.os.Handler;
4 | import android.support.design.widget.Snackbar;
5 | import android.util.Log;
6 |
7 | import com.fanhl.doujinMoe.R;
8 | import com.fanhl.doujinMoe.api.BookApi;
9 | import com.fanhl.doujinMoe.model.Book;
10 | import com.fanhl.doujinMoe.ui.adapter.BookGridRecyclerAdapter;
11 | import com.fanhl.util.ThreadUtil;
12 |
13 | import java.util.List;
14 |
15 | import rx.Observable;
16 | import rx.android.schedulers.AndroidSchedulers;
17 | import rx.android.schedulers.HandlerScheduler;
18 |
19 | /**
20 | * 已下载
21 | * Created by fanhl on 15/11/20.
22 | */
23 | public class DownloadedFragment extends AbsBookRecyclerFragment {
24 | public static final String TAG = DownloadedFragment.class.getSimpleName();
25 |
26 | private Handler downloadedHandler;
27 |
28 | public static DownloadedFragment newInstance() {
29 | return new DownloadedFragment();
30 | }
31 |
32 | @Override
33 | protected void assignViews() {
34 | super.assignViews();
35 |
36 | mAdapter.setOnItemLongClickListener((position, viewHolder) -> {
37 | Log.d(TAG, "删除书籍确认.");
38 | BookGridRecyclerAdapter.ViewHolder holder = (BookGridRecyclerAdapter.ViewHolder) viewHolder;
39 | Snackbar.make(mRecyclerView, getResources().getString(R.string.text_book_delete, holder.item.name), Snackbar.LENGTH_LONG).setAction(R.string.action_delete, v -> {
40 | if (BookApi.deleteBook(getActivity(), holder.item)) {
41 | app().getLocalManager().refresh(() -> getActivity().runOnUiThread(this::refreshData));
42 | }
43 | }).show();
44 | return true;
45 | });
46 | }
47 |
48 | @Override
49 | protected void initData() {
50 | super.initData();
51 | downloadedHandler = ThreadUtil.createBackgroundHandler("已下载用线程");
52 | }
53 |
54 | @Override
55 | protected void refreshData() {
56 | if (!mSwipeRefreshLayout.isRefreshing()) mSwipeRefreshLayout.setRefreshing(true);
57 | Observable.>create(subscriber -> {
58 | try {
59 | subscriber.onNext(app().getLocalManager().getDownloadedBooks());
60 | subscriber.onCompleted();
61 | } catch (Exception e) {
62 | subscriber.onError(e);
63 | }
64 | }).subscribeOn(HandlerScheduler.from(downloadedHandler))
65 | .observeOn(AndroidSchedulers.mainThread())
66 | .subscribe(books -> {
67 | mSwipeRefreshLayout.setRefreshing(false);
68 | mBooks.clear();
69 | mBooks.addAll(books);
70 | mAdapter.notifyDataSetChanged();
71 | }, throwable -> {
72 | mSwipeRefreshLayout.setRefreshing(false);
73 | Log.e(TAG, Log.getStackTraceString(throwable));
74 | Snackbar.make(mSwipeRefreshLayout, R.string.text_downloaded_get_fail, Snackbar.LENGTH_LONG).setAction(R.string.action_retry, v -> refreshData()).show();
75 | });
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/NewestFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * Created by fanhl on 15/11/8.
9 | */
10 | public class NewestFragment extends AbsHomeFragment {
11 |
12 | public static NewestFragment newInstance() {
13 | return new NewestFragment();
14 | }
15 |
16 | @Override
17 | @NonNull
18 | protected String getToken() {
19 | return "newest";
20 | }
21 |
22 | @Override
23 | @NonNull
24 | protected String getSort() {
25 | return "name";
26 | }
27 |
28 | @Override
29 | protected int getLoadFailMsgResId() {
30 | return R.string.text_newest_get_fail;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/fragment/main/SearchFragment.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.fragment.main;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.fanhl.doujinMoe.R;
6 |
7 | /**
8 | * http://m.doujin-moe.us/search?search=lolicon&sort=-created
9 | *
10 | * Created by fanhl on 15/12/1.
11 | */
12 | public class SearchFragment extends AbsHomeFragment {
13 | public static SearchFragment newInstance() {
14 | return new SearchFragment();
15 | }
16 |
17 | @Override
18 | @NonNull
19 | protected String getToken() {
20 | return "search";
21 | }
22 |
23 | /**
24 | * @return
25 | */
26 | @Override
27 | @NonNull
28 | protected String getSort() {
29 | return "name";
30 | }
31 |
32 | /**
33 | * @return
34 | */
35 | @NonNull
36 | @Override
37 | protected String getParam() {
38 | return "futanari";
39 | }
40 |
41 | @Override
42 | protected int getLoadFailMsgResId() {
43 | return R.string.text_search_get_fail;
44 | }
45 |
46 | // FIXME: 15/12/2 过滤条件
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/widget/NavigationFooterView.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.fanhl.doujinMoe.util.Utility;
9 |
10 |
11 | public class NavigationFooterView extends View {
12 |
13 | public NavigationFooterView(Context context) {
14 | super(context);
15 | }
16 |
17 | public NavigationFooterView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | public NavigationFooterView(Context context, AttributeSet attrs, int defStyleAttr) {
22 | super(context, attrs, defStyleAttr);
23 | }
24 |
25 | @Override
26 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
28 |
29 | ViewGroup.LayoutParams params = getLayoutParams();
30 |
31 | if (isInEditMode()) {
32 | params.height = 0;
33 | return;
34 | }
35 |
36 | params.height = Utility.getNavigationBarHeight(getContext());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/ui/widget/StatusBarHeaderView.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.fanhl.doujinMoe.util.Utility;
9 |
10 |
11 | public class StatusBarHeaderView extends View {
12 |
13 | public StatusBarHeaderView(Context context) {
14 | super(context);
15 | }
16 |
17 | public StatusBarHeaderView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | public StatusBarHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
22 | super(context, attrs, defStyleAttr);
23 | }
24 |
25 | @Override
26 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
28 |
29 | ViewGroup.LayoutParams params = getLayoutParams();
30 |
31 | if (isInEditMode()) {
32 | params.height = 0;
33 | return;
34 | }
35 |
36 | params.height = Utility.getStatusBarHeight(getContext());
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/ColorGenerator.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.Random;
6 |
7 | /**
8 | * @author amulya
9 | * @datetime 14 Oct 2014, 5:20 PM
10 | */
11 | public class ColorGenerator {
12 | public static final String TAG = ColorGenerator.class.getSimpleName();
13 |
14 | public static ColorGenerator DEFAULT;
15 |
16 | public static ColorGenerator MATERIAL;
17 |
18 | static {
19 | DEFAULT = create(Arrays.asList(
20 | 0xfff16364,
21 | 0xfff58559,
22 | 0xfff9a43e,
23 | 0xffe4c62e,
24 | 0xff67bf74,
25 | 0xff59a2be,
26 | 0xff2093cd,
27 | 0xffad62a7,
28 | 0xff805781
29 | ));
30 | MATERIAL = create(Arrays.asList(
31 | 0xffe57373,
32 | 0xfff06292,
33 | 0xffba68c8,
34 | 0xff9575cd,
35 | 0xff7986cb,
36 | 0xff64b5f6,
37 | 0xff4fc3f7,
38 | 0xff4dd0e1,
39 | 0xff4db6ac,
40 | 0xff81c784,
41 | 0xffaed581,
42 | 0xffff8a65,
43 | 0xffd4e157,
44 | 0xffffd54f,
45 | 0xffffb74d,
46 | 0xffa1887f,
47 | 0xff90a4ae
48 | ));
49 | }
50 |
51 | private final List mColors;
52 | private final Random mRandom;
53 |
54 | public static ColorGenerator create(List colorList) {
55 | return new ColorGenerator(colorList);
56 | }
57 |
58 | private ColorGenerator(List colorList) {
59 | mColors = colorList;
60 | mRandom = new Random(System.currentTimeMillis());
61 | }
62 |
63 | public int getRandomColor() {
64 | return mColors.get(mRandom.nextInt(mColors.size()));
65 | }
66 |
67 | public int getColor(Object key) {
68 | return mColors.get(Math.abs(key != null ? key.hashCode() : 0) % mColors.size());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.OutputStream;
11 |
12 | /**
13 | * Created by fanhl on 15/11/17.
14 | */
15 | public class FileUtil {
16 | public static final String TAG = FileUtil.class.getSimpleName();
17 |
18 | /**
19 | * 仅用于读取小文件(json文件)
20 | *
21 | * @param file
22 | * @return
23 | */
24 | public static String readFile(File file) {
25 | if (file == null || !file.exists() || !file.isFile()) return null;
26 |
27 | InputStream ins = null;
28 | try {
29 | ins = new FileInputStream(file);
30 | byte b[] = new byte[(int) file.length()];
31 | ins.read(b);
32 |
33 | return new String(b);
34 | } catch (Exception e) {
35 | Log.d(TAG, "读取文件失败.");
36 | e.printStackTrace();
37 | } finally {
38 | if (ins != null) {
39 | try {
40 | ins.close();
41 | } catch (IOException e) {
42 | e.printStackTrace();
43 | }
44 | }
45 | }
46 |
47 | return null;
48 | }
49 |
50 | public static boolean deleteDirectory(File directory) {
51 | if (directory.exists()) {
52 | File[] files = directory.listFiles();
53 | if (null != files) {
54 | for (File file : files) {
55 | if (file.isDirectory()) {
56 | deleteDirectory(file);
57 | } else {
58 | file.delete();
59 | }
60 | }
61 | }
62 | }
63 | return directory.delete();
64 | }
65 |
66 | /**
67 | * 将文本(json小文本)
68 | *
69 | * @param file
70 | * @param text
71 | * @return
72 | */
73 | static boolean writeFile(File file, String text) {
74 | return writeFile(file, text.getBytes());
75 | }
76 |
77 | private static boolean writeFile(File file, byte[] bytes) {
78 | OutputStream out = null;
79 | try {
80 | out = new FileOutputStream(file);
81 | out.write(bytes);
82 | } catch (IOException e) {
83 | e.printStackTrace();
84 | Log.d(TAG, "保存文件失败.");
85 | return false;
86 | } finally {
87 | if (out != null) {
88 | try {
89 | out.close();
90 | } catch (IOException e) {
91 | e.printStackTrace();
92 | }
93 | }
94 | }
95 | return true;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/FullScreenHelper.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.os.Build;
6 | import android.view.View;
7 | import android.view.ViewConfiguration;
8 | import android.view.Window;
9 | import android.view.WindowManager;
10 |
11 | @SuppressLint("InlinedApi")
12 | public final class FullScreenHelper implements View.OnSystemUiVisibilityChangeListener {
13 |
14 | private static final String TAG = FullScreenHelper.class.getSimpleName();
15 |
16 | private final int NOT_FULL_SCREEN_JELLY_BEAN =
17 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
18 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
19 |
20 | private final int FULL_SCREEN_JELLY_BEAN =
21 | NOT_FULL_SCREEN_JELLY_BEAN |
22 | View.SYSTEM_UI_FLAG_LOW_PROFILE |
23 | View.SYSTEM_UI_FLAG_FULLSCREEN;
24 |
25 | private final int FULL_SCREEN_FLAG_JELLY_BEAN =
26 | View.SYSTEM_UI_FLAG_LOW_PROFILE |
27 | View.SYSTEM_UI_FLAG_FULLSCREEN;
28 |
29 | private final int NOT_FULL_SCREEN_KITKAT =
30 | NOT_FULL_SCREEN_JELLY_BEAN |
31 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
32 |
33 | private final int FULL_SCREEN_KITKAT =
34 | NOT_FULL_SCREEN_KITKAT |
35 | View.SYSTEM_UI_FLAG_LOW_PROFILE |
36 | View.SYSTEM_UI_FLAG_FULLSCREEN |
37 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
38 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
39 |
40 | private boolean mFullScreen;
41 | private final Activity mActivity;
42 | private final Window mWindow;
43 | private final View mDecorView;
44 |
45 | private boolean mHasNavBar;
46 |
47 | private OnFullScreenBrokenListener mListener;
48 |
49 | private final int TEST_SDK = Build.VERSION.SDK_INT;
50 |
51 | public interface OnFullScreenBrokenListener {
52 |
53 | /**
54 | * FullScreen state should be fullScreen or not,
55 | * but user or system broke it
56 | *
57 | * @param fullScreen support to be
58 | */
59 | public void onFullScreenBroken(boolean fullScreen);
60 |
61 | }
62 |
63 | public FullScreenHelper(Activity activity) {
64 | mFullScreen = false;
65 | mActivity = activity;
66 | mWindow = mActivity.getWindow();
67 | mDecorView = mWindow.getDecorView();
68 | mDecorView.setOnSystemUiVisibilityChangeListener(this);
69 |
70 | String mainKey = Utility.getSystemProperties("qemu.hw.mainkeys");
71 | int resourceId = activity.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
72 | if (resourceId != 0) {
73 | mHasNavBar = activity.getResources().getBoolean(resourceId);
74 | // check override flag (see static block)
75 | if ("1".equals(mainKey)) {
76 | mHasNavBar = false;
77 | } else if ("0".equals(mainKey)) {
78 | mHasNavBar = true;
79 | }
80 | } else {
81 | mHasNavBar = !ViewConfiguration.get(activity).hasPermanentMenuKey();
82 | }
83 | }
84 |
85 | public boolean willHideNavBar() {
86 | if (TEST_SDK >= Build.VERSION_CODES.KITKAT && mHasNavBar)
87 | return true;
88 | else
89 | return false;
90 | }
91 |
92 | @Override
93 | public void onSystemUiVisibilityChange(int visibility) {
94 | if (TEST_SDK >= Build.VERSION_CODES.JELLY_BEAN &&
95 | TEST_SDK < Build.VERSION_CODES.KITKAT) {
96 | if ((mFullScreen && visibility != FULL_SCREEN_FLAG_JELLY_BEAN) ||
97 | (!mFullScreen && visibility != 0)) {
98 | // User or system change visibility
99 | if (mListener != null)
100 | mListener.onFullScreenBroken(mFullScreen);
101 | }
102 | }
103 | }
104 |
105 | public void setOnFullScreenBrokenListener(OnFullScreenBrokenListener l) {
106 | mListener = l;
107 | }
108 |
109 | public boolean getFullScreen() {
110 | return mFullScreen;
111 | }
112 |
113 | public void setFullScreen(boolean fullScreen) {
114 | mFullScreen = fullScreen;
115 | if (fullScreen) {
116 | if (TEST_SDK < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
117 | // Empty
118 | } else if (TEST_SDK < Build.VERSION_CODES.JELLY_BEAN) {
119 | mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
120 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
121 |
122 | } else if (TEST_SDK < Build.VERSION_CODES.KITKAT) {
123 | mDecorView.setSystemUiVisibility(FULL_SCREEN_JELLY_BEAN);
124 |
125 | } else {
126 | mDecorView.setSystemUiVisibility(FULL_SCREEN_KITKAT);
127 | }
128 | } else {
129 | if (TEST_SDK < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
130 | // Empty
131 | } else if (TEST_SDK < Build.VERSION_CODES.JELLY_BEAN) {
132 | mWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
133 |
134 | } else if (TEST_SDK < Build.VERSION_CODES.KITKAT) {
135 | mDecorView.setSystemUiVisibility(NOT_FULL_SCREEN_JELLY_BEAN);
136 |
137 | } else {
138 | mDecorView.setSystemUiVisibility(NOT_FULL_SCREEN_KITKAT);
139 | }
140 | }
141 | }
142 |
143 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/LocalManager.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.util.Log;
6 |
7 | import com.fanhl.doujinMoe.api.BookApi;
8 | import com.fanhl.doujinMoe.exception.GetBookFailException;
9 | import com.fanhl.doujinMoe.model.Book;
10 | import com.fanhl.util.ThreadUtil;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import rx.Observable;
16 | import rx.android.schedulers.HandlerScheduler;
17 |
18 | /**
19 | * 本地管理(最近阅读,喜爱,已下载)
20 | * Created by fanhl on 15/11/20.
21 | */
22 | public class LocalManager {
23 | public static final String TAG = LocalManager.class.getSimpleName();
24 |
25 | private static LocalManager mInstance;
26 |
27 | private final Handler localHandler;
28 |
29 | private final Context context;
30 |
31 | List recentBooks;
32 | List loveBooks;
33 | List downloadedBooks;
34 |
35 | public static LocalManager getInstance(Context context) {
36 | if (mInstance == null) {
37 | mInstance = new LocalManager(context);
38 | }
39 |
40 | return mInstance;
41 | }
42 |
43 | private LocalManager(Context context) {
44 | localHandler = ThreadUtil.createBackgroundHandler("DownloadThread");
45 |
46 | this.context = context;
47 |
48 | recentBooks = new ArrayList<>();
49 | loveBooks = new ArrayList<>();
50 | downloadedBooks = new ArrayList<>();
51 |
52 | refresh();
53 | }
54 |
55 | public void refresh() {
56 | refresh(null);
57 | }
58 |
59 | public void refresh(Runnable callback) {
60 | Observable.>create(subscriber -> {
61 | recentBooks.clear();
62 | loveBooks.clear();
63 | downloadedBooks.clear();
64 | try {
65 | subscriber.onNext(BookApi.getLocalBooks(context));
66 | subscriber.onCompleted();
67 | } catch (GetBookFailException e) {
68 | subscriber.onError(e);
69 | }
70 | }).subscribeOn(HandlerScheduler.from(localHandler))
71 | .flatMap(Observable::from)
72 | .subscribe(book -> {
73 | if (book.recent != null) {
74 | recentBooks.add(book);
75 | }
76 | if (book.isDownloaded()) {
77 | downloadedBooks.add(book);
78 | }
79 | }, throwable -> Log.e(TAG, Log.getStackTraceString(throwable)), () -> {
80 | // FIXME: 15/11/20 recentBooks.sort desc
81 |
82 | if (callback != null) callback.run();
83 | });
84 | }
85 |
86 | public List getRecentBooks() {
87 | return recentBooks;
88 | }
89 |
90 | public List getLoveBooks() {
91 | return loveBooks;
92 | }
93 |
94 | public List getDownloadedBooks() {
95 | return downloadedBooks;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/NumberUtil.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import java.text.DecimalFormat;
6 | import java.text.NumberFormat;
7 |
8 | /**
9 | * Created by fanhl on 15/11/20.
10 | */
11 | public class NumberUtil {
12 | @NonNull
13 | public static String formatPrefix(int index) {
14 | NumberFormat nf = new DecimalFormat("0000");
15 | return nf.format(index + 1);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/doujinMoe/util/Utility.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe.util;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.util.DisplayMetrics;
6 | import android.view.Display;
7 | import android.view.WindowManager;
8 |
9 | import java.io.File;
10 | import java.io.FileInputStream;
11 | import java.io.FileOutputStream;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.lang.reflect.Method;
15 |
16 | public class Utility {
17 |
18 | public static boolean isChrome() {
19 | return Build.BRAND.equals("chromium") || Build.BRAND.equals("chrome");
20 | }
21 |
22 | public static int getStatusBarHeight(Context context) {
23 | int result = 0;
24 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
25 | if (resourceId > 0) {
26 | result = context.getResources().getDimensionPixelSize(resourceId);
27 | }
28 | return result;
29 | }
30 |
31 | public static String getFirstCharacter(String sentence) {
32 | for (int i = 0; i < sentence.length(); i++) {
33 | String s = sentence.substring(i, i+1);
34 | if (s.equals("[") || s.equals("]")) continue;
35 | if (s.equals("{") || s.equals("}")) continue;
36 | if (s.equals("(") || s.equals(")")) continue;
37 | if (s.equals(",") || s.equals(".")) continue;
38 | if (s.equals("<") || s.equals(">")) continue;
39 | if (s.equals("《") || s.equals("》")) continue;
40 | if (s.equals("【") || s.equals("】")) continue;
41 | if (s.equals("{") || s.equals("}")) continue;
42 | return s;
43 | }
44 | return null;
45 | }
46 |
47 | public static String getSystemProperties(String key) {
48 | try {
49 | Class c = Class.forName("android.os.SystemProperties");
50 | Method m = c.getDeclaredMethod("get", String.class);
51 | m.setAccessible(true);
52 | return (String) m.invoke(null, key);
53 | } catch (Throwable e) {
54 | return "";
55 | }
56 | }
57 |
58 | public static int getTrueScreenHeight(Context context) {
59 | int dpi = 0;
60 | Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
61 | DisplayMetrics dm = new DisplayMetrics();
62 | if (Build.VERSION.SDK_INT >= 17) {
63 | display.getRealMetrics(dm);
64 | dpi = dm.heightPixels;
65 | } else {
66 | try {
67 | Class c = Class.forName("android.view.Display");
68 | Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
69 | method.invoke(display, dm);
70 | dpi = dm.heightPixels;
71 | } catch (Exception e) {
72 | e.printStackTrace();
73 | }
74 | }
75 |
76 | return dpi;
77 | }
78 |
79 | public static int getNavigationBarHeight(Context context) {
80 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
81 | DisplayMetrics dm = new DisplayMetrics();
82 | wm.getDefaultDisplay().getMetrics(dm);
83 |
84 | return getTrueScreenHeight(context) - dm.heightPixels;
85 | }
86 |
87 | public static void saveStringToFile(Context context, String name, String text) throws IOException {
88 | FileOutputStream fos = context.openFileOutput(name, Context.MODE_PRIVATE);
89 | fos.write(text.getBytes());
90 | fos.close();
91 | }
92 |
93 | public static String readStringFromFile(Context context, String name) throws IOException{
94 | File file = context.getFileStreamPath(name);
95 | InputStream is = new FileInputStream(file);
96 |
97 | byte b[] = new byte[(int) file.length()];
98 |
99 | is.read(b);
100 | is.close();
101 |
102 | String string = new String(b);
103 |
104 | return string;
105 | }
106 |
107 | public static int calcProgress(int progress, int max) {
108 | return (int) (((float) progress)/((float) max) * 100);
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/loadmore/OnBottomListener.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.loadmore;
2 |
3 | /**
4 | * @author Jack Tony
5 | * @brief
6 | * @date 2015/4/6
7 | */
8 | public interface OnBottomListener {
9 | public void onScrollBottom();
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/loadmore/OnRcvScrollListener.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.loadmore;
2 |
3 | /**
4 | * Created by fanhl on 15/12/1.
5 | */
6 |
7 | import android.support.v7.widget.GridLayoutManager;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.support.v7.widget.StaggeredGridLayoutManager;
11 |
12 | /**
13 | * @author Jack Tony
14 | * @brief recyle view 滚动监听器
15 | * @date 2015/4/6
16 | */
17 | public class OnRcvScrollListener extends RecyclerView.OnScrollListener implements OnBottomListener {
18 |
19 | private String TAG = getClass().getSimpleName();
20 |
21 | public static enum LAYOUT_MANAGER_TYPE {
22 | LINEAR,
23 | GRID,
24 | STAGGERED_GRID
25 | }
26 |
27 | /**
28 | * layoutManager的类型(枚举)
29 | */
30 | protected LAYOUT_MANAGER_TYPE layoutManagerType;
31 |
32 | /**
33 | * 最后一个的位置
34 | */
35 | private int[] lastPositions;
36 |
37 | /**
38 | * 最后一个可见的item的位置
39 | */
40 | private int lastVisibleItemPosition;
41 | /* *//**
42 | * 是否正在加载
43 | *//*
44 | private boolean isLoadingMore = false;*/
45 |
46 | /**
47 | * 当前滑动的状态
48 | */
49 | private int currentScrollState = 0;
50 |
51 | @Override
52 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
53 | super.onScrolled(recyclerView, dx, dy);
54 |
55 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
56 | // int lastVisibleItemPosition = -1;
57 | if (layoutManagerType == null) {
58 | if (layoutManager instanceof LinearLayoutManager) {
59 | layoutManagerType = LAYOUT_MANAGER_TYPE.LINEAR;
60 | } else if (layoutManager instanceof GridLayoutManager) {
61 | layoutManagerType = LAYOUT_MANAGER_TYPE.GRID;
62 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
63 | layoutManagerType = LAYOUT_MANAGER_TYPE.STAGGERED_GRID;
64 | } else {
65 | throw new RuntimeException(
66 | "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
67 | }
68 | }
69 |
70 | switch (layoutManagerType) {
71 | case LINEAR:
72 | lastVisibleItemPosition = ((LinearLayoutManager) layoutManager)
73 | .findLastVisibleItemPosition();
74 | break;
75 | case GRID:
76 | lastVisibleItemPosition = ((GridLayoutManager) layoutManager)
77 | .findLastVisibleItemPosition();
78 | break;
79 | case STAGGERED_GRID:
80 | StaggeredGridLayoutManager staggeredGridLayoutManager
81 | = (StaggeredGridLayoutManager) layoutManager;
82 | if (lastPositions == null) {
83 | lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
84 | }
85 | staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
86 | lastVisibleItemPosition = findMax(lastPositions);
87 | break;
88 | }
89 |
90 | }
91 |
92 | @Override
93 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
94 | super.onScrollStateChanged(recyclerView, newState);
95 | currentScrollState = newState;
96 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
97 | int visibleItemCount = layoutManager.getChildCount();
98 | int totalItemCount = layoutManager.getItemCount();
99 | if ((visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE &&
100 | (lastVisibleItemPosition) >= totalItemCount - 1)) {
101 | //Log.d(TAG, "is loading more");
102 | onScrollBottom();
103 | }
104 | }
105 |
106 |
107 | @Override
108 | public void onScrollBottom() {
109 | //Log.d(TAG, "is onScrollBottom");
110 | }
111 |
112 | private int findMax(int[] lastPositions) {
113 | int max = lastPositions[0];
114 | for (int value : lastPositions) {
115 | if (value > max) {
116 | max = value;
117 | }
118 | }
119 | return max;
120 | }
121 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/util/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.util;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * dp、sp 转换为 px 的工具类
7 | *
8 | * @author fxsky 2012.11.12
9 | */
10 | public class DisplayUtil {
11 | /**
12 | * 将px值转换为dip或dp值,保证尺寸大小不变(有精度损失)
13 | */
14 | public static int px2dip(Context context, float pxValue) {
15 | final float scale = context.getResources().getDisplayMetrics().density;
16 | return (int) (pxValue / scale + 0.5f);
17 | }
18 |
19 | /**
20 | * 将px值转换为dip或dp值,保证尺寸大小不变(无精度损失)
21 | */
22 | public static float px2dipByFloat(Context context, float pxValue) {
23 | final float scale = context.getResources().getDisplayMetrics().density;
24 | return (pxValue / scale);
25 | }
26 |
27 | /**
28 | * 将dip或dp值转换为px值,保证尺寸大小不变(有精度损失)
29 | */
30 | public static int dip2px(Context context, float dipValue) {
31 | final float scale = context.getResources().getDisplayMetrics().density;
32 | return (int) (dipValue * scale + 0.5f);
33 | }
34 |
35 | /**
36 | * 将dip或dp值转换为px值,保证尺寸大小不变(无精度损失)
37 | */
38 | public static float dip2pxByFloat(Context context, float dipValue) {
39 | final float scale = context.getResources().getDisplayMetrics().density;
40 | return (dipValue * scale);
41 | }
42 |
43 | /**
44 | * 将px值转换为sp值,保证文字大小不变
45 | */
46 | public static int px2sp(Context context, float pxValue) {
47 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
48 | return (int) (pxValue / fontScale + 0.5f);
49 | }
50 |
51 | /**
52 | * 将sp值转换为px值,保证文字大小不变
53 | */
54 | public static int sp2px(Context context, float spValue) {
55 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
56 | return (int) (spValue * fontScale + 0.5f);
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/util/GsonUtil.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.util;
2 |
3 | import android.util.Log;
4 |
5 | import com.google.gson.ExclusionStrategy;
6 | import com.google.gson.FieldAttributes;
7 | import com.google.gson.Gson;
8 | import com.google.gson.GsonBuilder;
9 | import com.google.gson.JsonSyntaxException;
10 |
11 | import java.lang.reflect.Type;
12 |
13 | /**
14 | * Gson用工具类
15 | * Created by honglin on 2014/9/24.
16 | */
17 | public class GsonUtil {
18 | public static final String TAG = GsonUtil.class.getSimpleName();
19 |
20 | private static final Gson gson;
21 |
22 | static {
23 | gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
24 | /**
25 | * 设置要过滤的属性
26 | */
27 | @Override
28 | public boolean shouldSkipField(FieldAttributes attr) {
29 | // 设置对应类中要过虑的属性
30 | // if (attr.getDeclaringClass() == UserInfo.class) {
31 | // return "password".equals(attr.getName());
32 | // }
33 | return false;
34 | }
35 |
36 | /**
37 | * 设置要过滤的类
38 | */
39 | @Override
40 | public boolean shouldSkipClass(Class> clazz) {
41 | // 这里,如果返回true就表示此类要过滤,否则就输出
42 | return false;
43 | }
44 | }).create();
45 | }
46 |
47 | public static final String json(Object obj) {
48 | return gson.toJson(obj);
49 | }
50 |
51 | public static final T obj(String json, Class classOfT) {
52 | try {
53 | return gson.fromJson(json, classOfT);
54 | } catch (JsonSyntaxException e) {
55 | Log.e(TAG, "解析json失败");
56 | }
57 | return null;
58 | }
59 |
60 | public static final T obj(String json, Type typeOfT) {
61 | try {
62 | return gson.fromJson(json, typeOfT);
63 | } catch (JsonSyntaxException e) {
64 | Log.e(TAG, "解析json失败");
65 | }
66 | return null;
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/util/ThreadUtil.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.util;
2 |
3 | import android.os.Handler;
4 | import android.os.HandlerThread;
5 | import android.support.annotation.NonNull;
6 |
7 | import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
8 |
9 | /**
10 | * Created by fanhl on 15/11/20.
11 | */
12 | public class ThreadUtil {
13 | /**
14 | * 创建后台线程,Rx用
15 | *
16 | * @param handlerThreadName
17 | * @return
18 | */
19 | @NonNull
20 | public static Handler createBackgroundHandler(String handlerThreadName) {
21 | HandlerThread downloadThread = new HandlerThread(handlerThreadName, THREAD_PRIORITY_BACKGROUND);
22 | downloadThread.start();
23 | return new Handler(downloadThread.getLooper());
24 | }
25 |
26 | public static void sleep(int time) {
27 | try {
28 | Thread.sleep(time);
29 | } catch (InterruptedException e) {
30 | e.printStackTrace();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/fanhl/util/UrlUtils.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.util;
2 |
3 |
4 | import java.io.UnsupportedEncodingException;
5 | import java.net.URLEncoder;
6 |
7 |
8 | /**
9 | * @author fanhl
10 | * @date 2014-9-17 下午3:52:28
11 | */
12 | public class UrlUtils {
13 | public static final String UTF_8 = "UTF-8";
14 |
15 | public static String urlEncode(String s) {
16 | return urlEncode(s, UTF_8);
17 | }
18 |
19 | public static String[] urlEncode(String... ss) {
20 | if (ss == null) {
21 | return null;
22 | }
23 |
24 | String[] resultStrings = new String[ss.length];
25 |
26 | for (int i = 0; i < ss.length; i++) {
27 | resultStrings[i] = urlEncode(ss[i], UTF_8);
28 | }
29 |
30 | return resultStrings;
31 | }
32 |
33 | public static String urlEncode(String s, String charsetName) {
34 | String result = null;
35 | try {
36 | result = URLEncoder.encode(s, charsetName);
37 | } catch (UnsupportedEncodingException e) {
38 | e.printStackTrace();
39 | }
40 | return result;
41 | }
42 |
43 | /**
44 | * 将url与params拼在一起
45 | *
46 | * @param url
47 | * @param values
48 | * @return
49 | */
50 | public static String getUrlWithParams(String url, String... values) {
51 | //add fanhl 20150819
52 | for (int i = 0; i < values.length; i++) {
53 | if (values[i] == null) {
54 | values[i] = "";//这里是为了防止 null时抛异常
55 | }
56 | }
57 |
58 | return String.format(url, (Object[]) urlEncode(values));
59 | // return String.format(url, (Object[]) values);
60 | }
61 |
62 | // /**
63 | // * 将url与params拼在一起
64 | // *
65 | // * @param url
66 | // * @param nameValuePairs
67 | // * @return
68 | // */
69 | // public static String getUrlWithParams(String url, NameValuePair... nameValuePairs) {
70 | // // 加参数
71 | // StringBuilder sb = new StringBuilder();
72 | // sb.append(url);
73 | // if (nameValuePairs != null && nameValuePairs.length > 0) {
74 | //
75 | // // 若url已有?就不再加了
76 | // boolean hasQuestionMark;
77 | // if (hasQuestionMark = (url.indexOf('?') < 0)) {
78 | // sb.append("?");
79 | // }
80 | // for (int i = 0; i < nameValuePairs.length; i++) {
81 | // if (i > 0 || hasQuestionMark) {
82 | // sb.append("&");
83 | // }
84 | // // FIXME 以后确认是否需要encode
85 | // sb.append(String.format("%s=%s", nameValuePairs[i].getName(),
86 | // nameValuePairs[i].getValue()));
87 | // }
88 | // }
89 | // return sb.toString();
90 | // }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/card_slide_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
9 |
11 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/state_anim_raise.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 | -
11 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fa_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/fa_book.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fa_bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/fa_bookmark.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fa_bookmark_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/fa_bookmark_o.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fa_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/fa_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fa_download_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/fa_download_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/place_holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-hdpi/place_holder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fa_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/fa_book.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fa_bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/fa_bookmark.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fa_bookmark_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/fa_bookmark_o.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fa_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/fa_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fa_download_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/fa_download_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/place_holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-mdpi/place_holder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_gallery.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_manage.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_send.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_slideshow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fa_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/fa_book.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fa_bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/fa_bookmark.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fa_bookmark_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/fa_bookmark_o.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fa_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/fa_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fa_download_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/fa_download_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/place_holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xhdpi/place_holder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fa_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/fa_book.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fa_bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/fa_bookmark.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fa_bookmark_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/fa_bookmark_o.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fa_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/fa_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fa_download_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/fa_download_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/place_holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxhdpi/place_holder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/fa_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/fa_book.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/fa_bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/fa_bookmark.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/fa_bookmark_o.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/fa_bookmark_o.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/fa_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/fa_download.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/fa_download_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/fa_download_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/place_holder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/drawable-xxxhdpi/place_holder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-v21/list_item_book_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-v21/list_item_download_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-v21/list_item_page_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
25 |
26 |
27 |
36 |
37 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_download_manager.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
40 |
41 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
26 |
27 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
50 |
51 |
56 |
57 |
64 |
65 |
74 |
75 |
76 |
77 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_book_page.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
19 |
20 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_recycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_swipe_recycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_book_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_book_card_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
29 |
30 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_download_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_download_card_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
12 |
22 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
50 |
51 |
52 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_page_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_page_card_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
27 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_details.xml:
--------------------------------------------------------------------------------
1 |
5 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_download_manager.xml:
--------------------------------------------------------------------------------
1 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 | 64dp
7 | 64dp
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #E91E63
4 | #C2185B
5 | #F8BBD0
6 | #FF9800
7 | #212121
8 | #727272
9 | #FFFFFF
10 | #B6B6B6
11 |
12 |
13 |
14 |
15 |
16 | #BA68C8
17 | #E91E63
18 | #3F51B5
19 | #2196F3
20 | #009688
21 | #4CAF50
22 | #81C784
23 | #FF9800
24 | #795548
25 |
26 | - @color/purple_300
27 | - @color/pink_500
28 | - @color/indigo_500
29 | - @color/blue_500
30 | - @color/teal_500
31 | - @color/green_500
32 | - @color/green_300
33 | - @color/orange_500
34 | - @color/brown_500
35 |
36 |
37 | #7f212121
38 |
39 | #6FE91E63
40 | #4b4b4b
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 160dp
5 |
6 | 0dp
7 | 0dp
8 | 16dp
9 | 16dp
10 | 16dp
11 |
12 | 6dp
13 |
14 | 5dp
15 | 360dp
16 | 16dp
17 | 100sp
18 | 70dp
19 | 8dp
20 |
21 | 120dp
22 | 1600dp
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 | - @android:drawable/ic_menu_camera
3 | - @android:drawable/ic_menu_gallery
4 | - @android:drawable/ic_menu_slideshow
5 | - @android:drawable/ic_menu_manage
6 | - @android:drawable/ic_menu_share
7 | - @android:drawable/ic_menu_send
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2
5 | 2
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Doujin-moe
3 |
4 | Open navigation drawer
5 | Close navigation drawer
6 |
7 | Settings
8 | 重试
9 | 下载
10 | 查看
11 |
12 | 最新
13 | 排行榜
14 | 作者
15 | 已下载
16 | 取得 最新漫画 失败.
17 | 取得 排行榜 失败.
18 | 取得 作者版块 失败.
19 | 取得 类别版块 失败.
20 | 取得 名称版块 失败.
21 | 取得 检索版块 失败.
22 | 取得 已下载书籍 失败.
23 | 书籍详细
24 | 刷新数据失败.
25 | 图库
26 | %1$d/%2$d
27 | 书籍 %s 下载成功.
28 | 书籍 %s 下载失败.
29 | 书签
30 | 下载管理
31 | Hello World from section: %1$d
32 | 下载管理
33 | 等待下载
34 | 下载中
35 | 下载完成
36 | 下载失败
37 | 是否取消下载?
38 | 取消
39 | 是否重新下载?
40 | 是否删除书籍 %s .
41 | 删除
42 | 类别
43 | 名称
44 | 检索
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/test/java/com/fanhl/doujinMoe/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.fanhl.doujinMoe;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/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:2.1.0'
9 | classpath 'me.tatarka:gradle-retrolambda:3.2.3'
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | jcenter()
16 | // maven { url "https://jcenter.bintray.com" }
17 | }
18 | }
19 |
20 | task clean(type: Delete) {
21 | delete rootProject.buildDir
22 | }
23 |
--------------------------------------------------------------------------------
/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/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun May 01 19:06:16 CST 2016
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.10-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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/graphics/device-2015-11-28-222059.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/graphics/device-2015-11-28-222059.png
--------------------------------------------------------------------------------
/graphics/face1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyguests/Doujin-moe-Android/84125a500c31ff30213108a1c4e722e5f09d43e9/graphics/face1.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------