diff --git a/bin/EhViewer.apk b/bin/EhViewer.apk index 404a4951f..835206ca9 100644 Binary files a/bin/EhViewer.apk and b/bin/EhViewer.apk differ diff --git a/bin/classes.dex b/bin/classes.dex index 35b6144c9..fab876711 100644 Binary files a/bin/classes.dex and b/bin/classes.dex differ diff --git a/bin/resources.ap_ b/bin/resources.ap_ index 364e26cbf..95f18cf2c 100644 Binary files a/bin/resources.ap_ and b/bin/resources.ap_ differ diff --git a/res/raw/change_log b/res/raw/change_log index 05abdd771..666affe49 100644 --- a/res/raw/change_log +++ b/res/raw/change_log @@ -1,6 +1,6 @@ Version 0.4.1 (2014-??-??) * 修正单点触控缩放错误 - +* 修正下载完毕后无法读取最后一页 Version 0.4.0 (2014-04-01) * 全新的阅读界面 diff --git a/src/com/hippo/ehviewer/StartActivity.java b/src/com/hippo/ehviewer/StartActivity.java index cd9e74c64..95a46dd80 100644 --- a/src/com/hippo/ehviewer/StartActivity.java +++ b/src/com/hippo/ehviewer/StartActivity.java @@ -1,10 +1,11 @@ package com.hippo.ehviewer; import com.hippo.ehviewer.activity.MangaListActivity; -import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Crash; import com.hippo.ehviewer.view.AlertButton; +import com.hippo.ehviewer.widget.DialogBuilder; + import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/com/hippo/ehviewer/UpdateHelper.java b/src/com/hippo/ehviewer/UpdateHelper.java index 0d0c70c0e..b90b456d1 100644 --- a/src/com/hippo/ehviewer/UpdateHelper.java +++ b/src/com/hippo/ehviewer/UpdateHelper.java @@ -13,15 +13,16 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import android.view.View; -import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.network.Downloader; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.EhClient; import com.hippo.ehviewer.util.Util; import com.hippo.ehviewer.view.AlertButton; +import com.hippo.ehviewer.widget.DialogBuilder; public class UpdateHelper { private static final String TAG = "UpdateHelper"; + private static final int NOTIFICATION_ID = -1; // Update host private static final int GOOGLE = 0; @@ -141,10 +142,10 @@ public class UpdateHelper { @Override public void onDownloadStart(int totalSize) { - mBuilder.setContentTitle("正在下载更新") + mBuilder.setContentTitle("正在下载更新") // TODO .setContentText(null) .setProgress(0, 0, true).setOngoing(true); - mNotifyManager.notify(233, mBuilder.build()); + mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build()); } @Override public void onDownloadStatusUpdate( @@ -152,13 +153,13 @@ public class UpdateHelper { mBuilder.setContentTitle("正在下载更新") .setContentText(String.format("%.2f / %.2f KB", downloadSize/1024.0f, totalSize/1024.0f)) .setProgress(totalSize, downloadSize, false).setOngoing(true); - mNotifyManager.notify(233, mBuilder.build()); + mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build()); } @Override public void onDownloadOver(boolean ok, int eMesgId) { if (ok) { - mNotifyManager.cancel(233); + mNotifyManager.cancel(NOTIFICATION_ID); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(Config.getDownloadPath(), updateFileName)), "application/vnd.android.package-archive"); @@ -166,8 +167,9 @@ public class UpdateHelper { mActivity.getApplicationContext().startActivity(intent); } else { mBuilder.setContentTitle("下载更新失败") - .setContentText(null) - .setProgress(0, 0, false).setOngoing(false); + .setContentText(null) + .setProgress(0, 0, false).setOngoing(false); + mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build()); } } } diff --git a/src/com/hippo/ehviewer/activity/DownloadActivity.java b/src/com/hippo/ehviewer/activity/DownloadActivity.java index bb63572f7..fa859b978 100644 --- a/src/com/hippo/ehviewer/activity/DownloadActivity.java +++ b/src/com/hippo/ehviewer/activity/DownloadActivity.java @@ -8,7 +8,6 @@ import com.hippo.ehviewer.BeautifyScreen; import com.hippo.ehviewer.DownloadInfo; import com.hippo.ehviewer.ListMangaDetail; import com.hippo.ehviewer.R; -import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; @@ -20,6 +19,7 @@ import com.hippo.ehviewer.util.Util; import com.hippo.ehviewer.view.AlertButton; import com.hippo.ehviewer.view.DownloadItemLayout; import com.hippo.ehviewer.view.OlImageView; +import com.hippo.ehviewer.widget.DialogBuilder; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/com/hippo/ehviewer/activity/FavouriteActivity.java b/src/com/hippo/ehviewer/activity/FavouriteActivity.java index 23adca338..863400621 100644 --- a/src/com/hippo/ehviewer/activity/FavouriteActivity.java +++ b/src/com/hippo/ehviewer/activity/FavouriteActivity.java @@ -27,7 +27,6 @@ import com.hippo.ehviewer.BeautifyScreen; import com.hippo.ehviewer.ImageLoadManager; import com.hippo.ehviewer.ListMangaDetail; import com.hippo.ehviewer.R; -import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; @@ -37,6 +36,7 @@ import com.hippo.ehviewer.util.Favourite; import com.hippo.ehviewer.util.Ui; import com.hippo.ehviewer.view.AlertButton; import com.hippo.ehviewer.view.OlImageView; +import com.hippo.ehviewer.widget.DialogBuilder; import com.hippo.ehviewer.widget.LoadImageView; public class FavouriteActivity extends Activity{ diff --git a/src/com/hippo/ehviewer/activity/MangaActivity.java b/src/com/hippo/ehviewer/activity/MangaActivity.java index d75aad438..6dd162833 100644 --- a/src/com/hippo/ehviewer/activity/MangaActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaActivity.java @@ -5,6 +5,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -72,11 +74,12 @@ public class MangaActivity extends Activity { private File mFolder; private ImageSet mImageSet; - private Downloader mDownloader; // two element, first is web url, second is image url - private ArrayList imagesUrl; + private List imagesUrl; + // TODO use downloader to download image + // TODO combine it with MangaDownloadActivity private class MangaUrlGetListener implements EhClient.OnGetManagaUrlListener { @Override @@ -94,18 +97,18 @@ public class MangaActivity extends Activity { String[] urls = imagesUrl.get(index); if (urls == null) { - imagesUrl.add(index, urls = new String[2]); + imagesUrl.set(index, urls = new String[2]); } urls[1] = imageUrl; if (index == firstPage - 1 || (index == firstPage && allPrePageUrl == null)) { allPrePageUrl = prePageUrl; if (index > 0) - imagesUrl.add(index - 1, new String[]{allPrePageUrl, null}); + imagesUrl.set(index - 1, new String[]{allPrePageUrl, null}); } if (index == lastPage) { allNextPageUrl = nextPageUrl; if (index < pageSum - 1) - imagesUrl.add(index + 1, new String[]{allNextPageUrl, null}); + imagesUrl.set(index + 1, new String[]{allNextPageUrl, null}); } if (index != firstPage - 1 && (index == firstPage && allPrePageUrl == null) && index != lastPage) { Log.e(TAG, "targetPage != firstPage - 1 && (targetPage == firstPage && allPrePageUrl == null) && targetPage != lastPage"); @@ -113,8 +116,9 @@ public class MangaActivity extends Activity { final String imageName = String.format("%05d", index + 1) + "." + Util.getExtension(imageUrl); + final Downloader downloader = new Downloader(); try { - mDownloader.resetData(mFolder.getPath(), + downloader.resetData(mFolder.getPath(), imageName, imageUrl); } catch (MalformedURLException e) { @@ -131,8 +135,8 @@ public class MangaActivity extends Activity { onGetImage(index, Downloader.COMPLETED, nextPageUrl); } else { - mDownloader.run(); - onGetImage(index, mDownloader.getStatus(), nextPageUrl); + downloader.run(); + onGetImage(index, downloader.getStatus(), nextPageUrl); } } }.start(); @@ -329,9 +333,6 @@ public class MangaActivity extends Activity { GLRootView glrv= (GLRootView)findViewById(R.id.gl_root_view); glrv.setContentPane(isv); - // Start download - mDownloader = new Downloader(); - String url = intent.getStringExtra("url"); allNextPageUrl = url; allPrePageUrl = null; @@ -341,8 +342,8 @@ public class MangaActivity extends Activity { if (firstPage == pageSum - 1) allNextPageUrl = "last"; - imagesUrl = new ArrayList(pageSum); - imagesUrl.add(lastPage, new String[]{url, null}); + imagesUrl = new ArrayList(Collections.nCopies(pageSum, (String[])null)); + imagesUrl.set(lastPage, new String[]{url, null}); // Get image and next page EhClient.getManagaUrl(url, lastPage, new MangaUrlGetListener()); diff --git a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java index 1f661af10..1df26d17d 100644 --- a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java @@ -7,7 +7,6 @@ import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.MangaDetail; import com.hippo.ehviewer.PageList; import com.hippo.ehviewer.R; -import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; @@ -18,6 +17,7 @@ import com.hippo.ehviewer.util.Ui; import com.hippo.ehviewer.util.Util; import com.hippo.ehviewer.view.OlImageView; import com.hippo.ehviewer.widget.AutoWrapLayout; +import com.hippo.ehviewer.widget.DialogBuilder; import com.hippo.ehviewer.widget.AutoWrapLayout.BaseLine; import android.app.Activity; diff --git a/src/com/hippo/ehviewer/activity/MangaListActivity.java b/src/com/hippo/ehviewer/activity/MangaListActivity.java index 441a79c6f..4788ad235 100644 --- a/src/com/hippo/ehviewer/activity/MangaListActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaListActivity.java @@ -8,8 +8,6 @@ import com.hippo.ehviewer.ListMangaDetail; import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.R; import com.hippo.ehviewer.UpdateHelper; -import com.hippo.ehviewer.dialog.DialogBuilder; -import com.hippo.ehviewer.dialog.SuperDialogUtil; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; @@ -23,9 +21,11 @@ import com.hippo.ehviewer.view.CheckImage; import com.hippo.ehviewer.view.GetPaddingRelativeLayout; import com.hippo.ehviewer.view.TagListView; import com.hippo.ehviewer.view.TagsAdapter; +import com.hippo.ehviewer.widget.DialogBuilder; import com.hippo.ehviewer.widget.DrawerLayout; import com.hippo.ehviewer.widget.LoadImageView; import com.hippo.ehviewer.widget.PullListView; +import com.hippo.ehviewer.widget.SuperDialogUtil; import com.hippo.ehviewer.widget.PullListView.OnFooterRefreshListener; import com.hippo.ehviewer.widget.PullListView.OnHeaderRefreshListener; diff --git a/src/com/hippo/ehviewer/activity/SettingsActivity.java b/src/com/hippo/ehviewer/activity/SettingsActivity.java index 0c386e69d..cc64db822 100644 --- a/src/com/hippo/ehviewer/activity/SettingsActivity.java +++ b/src/com/hippo/ehviewer/activity/SettingsActivity.java @@ -10,7 +10,7 @@ import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Util; import com.hippo.ehviewer.view.MangaImage; -import com.hippo.ehviewer.dialog.DialogBuilder; +import com.hippo.ehviewer.widget.DialogBuilder; import com.hippo.ehviewer.preference.AutoListPreference; import android.annotation.SuppressLint; diff --git a/src/com/hippo/ehviewer/network/Downloader.java b/src/com/hippo/ehviewer/network/Downloader.java index b835cc33c..686e5cfba 100644 --- a/src/com/hippo/ehviewer/network/Downloader.java +++ b/src/com/hippo/ehviewer/network/Downloader.java @@ -1,22 +1,28 @@ package com.hippo.ehviewer.network; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.util.List; -import java.util.Map; import android.util.Log; -import com.hippo.ehviewer.DownloadInfo; import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Util; +// TODO 添加断点续传 +// TODO 添加检查次磁盘空间 + +/** + * Thread unsafe + * + * @author Hippo + * + */ public class Downloader implements Runnable { private static final String TAG = "Downloader"; @@ -41,6 +47,7 @@ public class Downloader implements Runnable { private Controlor mContorlor; private int mTotalSize; + // If support Content-Range, start from it private int mDownloadSize = 0; private int mRedirectionCount = 0; @@ -99,7 +106,6 @@ public class Downloader implements Runnable { try { if (mContorlor.isStop()) throw new StopRequestException(STOP, "Download is stopped"); - mDownloadSize = 0; mRedirectionCount = 0; status = COMPLETED; executeDownload(); @@ -131,7 +137,7 @@ public class Downloader implements Runnable { Log.d(TAG, "Get file " + mUrl.toString()); conn = (HttpURLConnection)mUrl.openConnection(); conn.setInstanceFollowRedirects(false); - conn.addRequestProperty("Range", "bytes=0-"); // TODO + conn.addRequestProperty("Range", "bytes=" + mDownloadSize + "-"); // TODO conn.setConnectTimeout(DEFAULT_TIMEOUT); conn.setReadTimeout(DEFAULT_TIMEOUT); conn.connect(); @@ -176,16 +182,38 @@ public class Downloader implements Runnable { */ private void processResponseHeaders(HttpURLConnection conn) { mTotalSize = conn.getContentLength(); + + // bytes 500-999/1234 String range; - int index; - if (mTotalSize == -1 - && (range = conn.getHeaderField("Content-Range")) != null - && (index = range.lastIndexOf('/')) != -1) { - try { - mTotalSize = Integer.parseInt(range.substring(index + 1)); - } catch (Exception e) { - e.printStackTrace(); + if ((range = conn.getHeaderField("Content-Range")) != null) { // Support Content-Range + boolean newNum = true; + int numIndex = 0; + int num = 0; + int length = range.length(); + char ch; + for (int i = 0; i < length; i++) { + ch = range.charAt(i); + if (ch >= '0' && ch <= '9') { + if (newNum) { + newNum = false; + num = ch - '0'; + } else + num = num * 10 + ch - '0'; + } else { + if (!newNum) { + newNum = true; + if (numIndex == 0) + mDownloadSize = num; + else if (numIndex == 2) + mTotalSize = num; + numIndex++; + } + } } + if (numIndex == 2) + mTotalSize = num; + } else { // Do not support Content-Range, restart download + mDownloadSize = 0; } } @@ -194,7 +222,7 @@ public class Downloader implements Runnable { */ private void transferData(HttpURLConnection conn) throws StopRequestException { InputStream in = null; - OutputStream out = null; + RandomAccessFile raf = null; File file = null; if (mContorlor.isStop()) @@ -210,29 +238,32 @@ public class Downloader implements Runnable { try { file = new File(mPath, mFileName); - out = new FileOutputStream(file); + raf = new RandomAccessFile(file, "rw"); + raf.seek(mDownloadSize); } catch (IOException e) { throw new StopRequestException(STATUS_FILE_ERROR, e); } // Start streaming data, periodically watch for pause/cancel // commands and checking disk space as needed. - transferData(in, out); + transferData(in, raf); } finally { Util.closeStreamQuietly(in); - try { - if (out != null) out.flush(); - } catch (IOException e) { - } finally { - Util.closeStreamQuietly(out); - } + if (raf != null) + try { + raf.close(); + } catch (IOException e) { + e.printStackTrace(); + } } } + /** * Transfer as much data as possible from the HTTP response to the * destination file. */ + @SuppressWarnings("unused") private void transferData(InputStream in, OutputStream out) throws StopRequestException { final byte data[] = new byte[BUFFER_SIZE]; @@ -253,6 +284,30 @@ public class Downloader implements Runnable { } } + /** + * Transfer as much data as possible from the HTTP response to the + * destination file. + */ + private void transferData(InputStream in, RandomAccessFile raf) + throws StopRequestException { + final byte data[] = new byte[BUFFER_SIZE]; + for (;;) { + int bytesRead = readFromResponse(data, in); + if (bytesRead == -1) { // success, end of stream already reached + return; + } + + writeDataToDestination(data, bytesRead, raf); + mDownloadSize += bytesRead; + if (mListener != null) + mListener.onDownloadStatusUpdate(mDownloadSize, mTotalSize); + + if (mContorlor.isStop()) + throw new StopRequestException(STOP, + "Download is stopped"); + } + } + /** * Read some data from the HTTP response stream, handling I/O errors. * @param data buffer to use to read data @@ -270,6 +325,7 @@ public class Downloader implements Runnable { } } + /** * Write a data buffer to the destination file. * @param data buffer containing the data to write @@ -287,4 +343,22 @@ public class Downloader implements Runnable { "Failed to write data: " + ex); } } + + /** + * Write a data buffer to the destination file. + * @param data buffer containing the data to write + * @param bytesRead how many bytes to write from the buffer + */ + private void writeDataToDestination(byte[] data, int bytesRead, RandomAccessFile raf) + throws StopRequestException { + try { + raf.write(data, 0, bytesRead); + return; + } catch (IOException ex) { + // TODO: better differentiate between DRM and disk failures + // TODO: check disk is full + throw new StopRequestException(STATUS_FILE_ERROR, + "Failed to write data: " + ex); + } + } } diff --git a/src/com/hippo/ehviewer/util/EhClient.java b/src/com/hippo/ehviewer/util/EhClient.java index a3b5c6151..91f3bf531 100644 --- a/src/com/hippo/ehviewer/util/EhClient.java +++ b/src/com/hippo/ehviewer/util/EhClient.java @@ -1334,6 +1334,8 @@ public class EhClient { public void onDownloadMangaAllOver(); } + // TODO 下载前检查文件是否已存在 + /****** DownloadMangaManager ******/ public static class DownloadMangaManager { private static DownloadInfo curDownloadInfo = null; @@ -1489,10 +1491,8 @@ public class EhClient { boolean mComplete = true; boolean mStop = false; // Get page - curDownloadInfo.lastStartIndex--; while (!nextPage.equals(curDownloadInfo.pageUrlStr)) { curDownloadInfo.pageUrlStr = nextPage; - curDownloadInfo.lastStartIndex++; Download.notify(String.valueOf(curDownloadInfo.gid)); listener.onDownloadPage(curDownloadInfo.gid, curDownloadInfo.pageSum, curDownloadInfo.lastStartIndex); mService.notifyUpdate(); @@ -1543,6 +1543,7 @@ public class EhClient { mComplete = false; break; } + curDownloadInfo.lastStartIndex++; } if (mComplete) { listener.onDownloadMangaOver(curDownloadInfo.gid, true); diff --git a/src/com/hippo/ehviewer/dialog/DialogBuilder.java b/src/com/hippo/ehviewer/widget/DialogBuilder.java similarity index 97% rename from src/com/hippo/ehviewer/dialog/DialogBuilder.java rename to src/com/hippo/ehviewer/widget/DialogBuilder.java index 66e07cbce..c15b9409e 100644 --- a/src/com/hippo/ehviewer/dialog/DialogBuilder.java +++ b/src/com/hippo/ehviewer/widget/DialogBuilder.java @@ -1,266 +1,266 @@ -package com.hippo.ehviewer.dialog; - -import com.hippo.ehviewer.R; -import com.hippo.ehviewer.view.AlertButton; - -import android.app.AlertDialog; -import android.content.Context; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.ScrollView; -import android.widget.TextView; - -public class DialogBuilder extends AlertDialog.Builder{ - private View mView; - private Context mContext; - public DialogBuilder(Context context) { - super(context); - mContext = context; - LayoutInflater inflater = (LayoutInflater)mContext.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - mView = inflater.inflate(R.layout.dialog, null); - super.setView(mView); - } - - /** - * Set the title using the given resource id. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - @Override - public DialogBuilder setTitle(int titleId) { - setTitle(mContext.getText(titleId)); - return this; - } - - /** - * Set the title displayed in the {@link Dialog}. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - @Override - public DialogBuilder setTitle(CharSequence title) { - TextView titleView = (TextView)mView.findViewById(R.id.title); - titleView.setVisibility(View.VISIBLE); - titleView.setText(title); - return this; - } - - /** - * Set the message to display using the given resource id. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - @Override - public DialogBuilder setMessage(int messageId) { - setMessage(mContext.getText(messageId)); - return this; - } - - /** - * Set the message to display. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - @Override - public DialogBuilder setMessage(CharSequence message) { - ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); - scrollView.setVisibility(View.VISIBLE); - TextView messageView = (TextView)mView.findViewById(R.id.message); - messageView.setVisibility(View.VISIBLE); - messageView.setText(message); - return this; - } - - public DialogBuilder setLongMessage(int messageId) { - setLongMessage(mContext.getText(messageId)); - return this; - } - - public DialogBuilder setLongMessage(CharSequence message) { - ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); - scrollView.setVisibility(View.VISIBLE); - TextView messageView = (TextView)mView.findViewById(R.id.message); - messageView.setVisibility(View.VISIBLE); - messageView.setText(message); - LinearLayout.LayoutParams lp = - (LinearLayout.LayoutParams)messageView.getLayoutParams(); - lp.setMargins(lp.leftMargin, lp.topMargin/3, - lp.rightMargin, lp.bottomMargin/3); - return this; - } - - /** - * Set the view to display in that dialog. - * @return - */ - public DialogBuilder setView(View view, boolean center) { - ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); - scrollView.setVisibility(View.VISIBLE); - LinearLayout customLayout = (LinearLayout)mView.findViewById(R.id.custom); - customLayout.setVisibility(View.VISIBLE); - if (center) { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - customLayout.addView(view, lp); - } else { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - customLayout.addView(view, lp); - } - return this; - } - - /** - * Set a listener to be invoked when the positive button of the dialog is pressed. - * @param textId The resource id of the text to display in the positive button - * @param listener The View.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setPositiveButton(int textId, final View.OnClickListener listener) { - setPositiveButton(mContext.getText(textId), listener); - return this; - } - - /** - * Set a listener to be invoked when the positive button of the dialog is pressed. - * @param text The text to display in the positive button - * @param listener The View.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setPositiveButton(CharSequence text, final View.OnClickListener listener) { - Button button = (Button)mView.findViewById(R.id.positive_button); - button.setVisibility(View.VISIBLE); - button.setText(text); - button.setOnClickListener(listener); - return this; - } - - /** - * Set a listener to be invoked when the negative button of the dialog is pressed. - * @param textId The resource id of the text to display in the negative button - * @param listener The DialogInterface.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setNegativeButton(int textId, final View.OnClickListener listener) { - setNegativeButton(mContext.getText(textId), listener); - return this; - } - - /** - * Set a listener to be invoked when the negative button of the dialog is pressed. - * @param text The text to display in the negative button - * @param listener The DialogInterface.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setNegativeButton(CharSequence text, final View.OnClickListener listener) { - Button button = (Button)mView.findViewById(R.id.negative_button); - button.setVisibility(View.VISIBLE); - button.setText(text); - button.setOnClickListener(listener); - return this; - } - - /** - * Set a listener to be invoked when the neutral button of the dialog is pressed. - * @param textId The resource id of the text to display in the neutral button - * @param listener The DialogInterface.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setNeutralButton(int textId, final View.OnClickListener listener) { - setNeutralButton(mContext.getText(textId), listener); - return this; - } - - /** - * Set a listener to be invoked when the neutral button of the dialog is pressed. - * @param text The text to display in the neutral button - * @param listener The View.DialogInterface.OnClickListener to use. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setNeutralButton(CharSequence text, final View.OnClickListener listener) { - Button button = (Button)mView.findViewById(R.id.neutral_button); - button.setVisibility(View.VISIBLE); - button.setText(text); - button.setOnClickListener(listener); - return this; - } - - /** - * Sets whether the dialog is cancelable or not. Default is true. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - @Override - public DialogBuilder setCancelable(boolean cancelable) { - super.setCancelable(cancelable); - return this; - } - - /** - * Set a list of items to be displayed in the dialog as the content, you will be notified of the - * selected item via the supplied listener. This should be an array type i.e. R.array.foo - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setItems(int itemsId, AdapterView.OnItemClickListener listener) { - setItems(mContext.getResources().getTextArray(itemsId), listener); - return this; - } - - /** - * Set a list of items to be displayed in the dialog as the content, you will be notified of the - * selected item via the supplied listener. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setItems(CharSequence[] items, AdapterView.OnItemClickListener listener) { - setAdapter(new ArrayAdapter(mContext, - R.layout.list_item_text, items), listener); - return this; - } - - /** - * Set a list of items, which are supplied by the given {@link ListAdapter}, to be - * displayed in the dialog as the content, you will be notified of the - * selected item via the supplied listener. - * - * @param adapter The {@link ListAdapter} to supply the list of items - * @param listener The listener that will be called when an item is clicked. - * - * @return This Builder object to allow for chaining of calls to set methods - */ - public DialogBuilder setAdapter(ListAdapter adapter, AdapterView.OnItemClickListener listener) { - ListView listView = (ListView)mView.findViewById(R.id.list); - listView.setVisibility(View.VISIBLE); - listView.setAdapter(adapter); - listView.setOnItemClickListener(listener); - return this; - } - - public AlertDialog create() { - AlertDialog dialog = super.create(); - AlertButton button = (AlertButton)mView.findViewById(R.id.positive_button); - button.dialog = dialog; - button = (AlertButton)mView.findViewById(R.id.negative_button); - button.dialog = dialog; - button = (AlertButton)mView.findViewById(R.id.neutral_button); - button.dialog = dialog; - return dialog; - } -} +package com.hippo.ehviewer.widget; + +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.view.AlertButton; + +import android.app.AlertDialog; +import android.content.Context; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.ScrollView; +import android.widget.TextView; + +public class DialogBuilder extends AlertDialog.Builder{ + private View mView; + private Context mContext; + public DialogBuilder(Context context) { + super(context); + mContext = context; + LayoutInflater inflater = (LayoutInflater)mContext.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + mView = inflater.inflate(R.layout.dialog, null); + super.setView(mView); + } + + /** + * Set the title using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + @Override + public DialogBuilder setTitle(int titleId) { + setTitle(mContext.getText(titleId)); + return this; + } + + /** + * Set the title displayed in the {@link Dialog}. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + @Override + public DialogBuilder setTitle(CharSequence title) { + TextView titleView = (TextView)mView.findViewById(R.id.title); + titleView.setVisibility(View.VISIBLE); + titleView.setText(title); + return this; + } + + /** + * Set the message to display using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + @Override + public DialogBuilder setMessage(int messageId) { + setMessage(mContext.getText(messageId)); + return this; + } + + /** + * Set the message to display. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + @Override + public DialogBuilder setMessage(CharSequence message) { + ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); + scrollView.setVisibility(View.VISIBLE); + TextView messageView = (TextView)mView.findViewById(R.id.message); + messageView.setVisibility(View.VISIBLE); + messageView.setText(message); + return this; + } + + public DialogBuilder setLongMessage(int messageId) { + setLongMessage(mContext.getText(messageId)); + return this; + } + + public DialogBuilder setLongMessage(CharSequence message) { + ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); + scrollView.setVisibility(View.VISIBLE); + TextView messageView = (TextView)mView.findViewById(R.id.message); + messageView.setVisibility(View.VISIBLE); + messageView.setText(message); + LinearLayout.LayoutParams lp = + (LinearLayout.LayoutParams)messageView.getLayoutParams(); + lp.setMargins(lp.leftMargin, lp.topMargin/3, + lp.rightMargin, lp.bottomMargin/3); + return this; + } + + /** + * Set the view to display in that dialog. + * @return + */ + public DialogBuilder setView(View view, boolean center) { + ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); + scrollView.setVisibility(View.VISIBLE); + LinearLayout customLayout = (LinearLayout)mView.findViewById(R.id.custom); + customLayout.setVisibility(View.VISIBLE); + if (center) { + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER; + customLayout.addView(view, lp); + } else { + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + customLayout.addView(view, lp); + } + return this; + } + + /** + * Set a listener to be invoked when the positive button of the dialog is pressed. + * @param textId The resource id of the text to display in the positive button + * @param listener The View.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setPositiveButton(int textId, final View.OnClickListener listener) { + setPositiveButton(mContext.getText(textId), listener); + return this; + } + + /** + * Set a listener to be invoked when the positive button of the dialog is pressed. + * @param text The text to display in the positive button + * @param listener The View.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setPositiveButton(CharSequence text, final View.OnClickListener listener) { + Button button = (Button)mView.findViewById(R.id.positive_button); + button.setVisibility(View.VISIBLE); + button.setText(text); + button.setOnClickListener(listener); + return this; + } + + /** + * Set a listener to be invoked when the negative button of the dialog is pressed. + * @param textId The resource id of the text to display in the negative button + * @param listener The DialogInterface.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setNegativeButton(int textId, final View.OnClickListener listener) { + setNegativeButton(mContext.getText(textId), listener); + return this; + } + + /** + * Set a listener to be invoked when the negative button of the dialog is pressed. + * @param text The text to display in the negative button + * @param listener The DialogInterface.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setNegativeButton(CharSequence text, final View.OnClickListener listener) { + Button button = (Button)mView.findViewById(R.id.negative_button); + button.setVisibility(View.VISIBLE); + button.setText(text); + button.setOnClickListener(listener); + return this; + } + + /** + * Set a listener to be invoked when the neutral button of the dialog is pressed. + * @param textId The resource id of the text to display in the neutral button + * @param listener The DialogInterface.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setNeutralButton(int textId, final View.OnClickListener listener) { + setNeutralButton(mContext.getText(textId), listener); + return this; + } + + /** + * Set a listener to be invoked when the neutral button of the dialog is pressed. + * @param text The text to display in the neutral button + * @param listener The View.DialogInterface.OnClickListener to use. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setNeutralButton(CharSequence text, final View.OnClickListener listener) { + Button button = (Button)mView.findViewById(R.id.neutral_button); + button.setVisibility(View.VISIBLE); + button.setText(text); + button.setOnClickListener(listener); + return this; + } + + /** + * Sets whether the dialog is cancelable or not. Default is true. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + @Override + public DialogBuilder setCancelable(boolean cancelable) { + super.setCancelable(cancelable); + return this; + } + + /** + * Set a list of items to be displayed in the dialog as the content, you will be notified of the + * selected item via the supplied listener. This should be an array type i.e. R.array.foo + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setItems(int itemsId, AdapterView.OnItemClickListener listener) { + setItems(mContext.getResources().getTextArray(itemsId), listener); + return this; + } + + /** + * Set a list of items to be displayed in the dialog as the content, you will be notified of the + * selected item via the supplied listener. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setItems(CharSequence[] items, AdapterView.OnItemClickListener listener) { + setAdapter(new ArrayAdapter(mContext, + R.layout.list_item_text, items), listener); + return this; + } + + /** + * Set a list of items, which are supplied by the given {@link ListAdapter}, to be + * displayed in the dialog as the content, you will be notified of the + * selected item via the supplied listener. + * + * @param adapter The {@link ListAdapter} to supply the list of items + * @param listener The listener that will be called when an item is clicked. + * + * @return This Builder object to allow for chaining of calls to set methods + */ + public DialogBuilder setAdapter(ListAdapter adapter, AdapterView.OnItemClickListener listener) { + ListView listView = (ListView)mView.findViewById(R.id.list); + listView.setVisibility(View.VISIBLE); + listView.setAdapter(adapter); + listView.setOnItemClickListener(listener); + return this; + } + + public AlertDialog create() { + AlertDialog dialog = super.create(); + AlertButton button = (AlertButton)mView.findViewById(R.id.positive_button); + button.dialog = dialog; + button = (AlertButton)mView.findViewById(R.id.negative_button); + button.dialog = dialog; + button = (AlertButton)mView.findViewById(R.id.neutral_button); + button.dialog = dialog; + return dialog; + } +} diff --git a/src/com/hippo/ehviewer/dialog/SuperDialogUtil.java b/src/com/hippo/ehviewer/widget/SuperDialogUtil.java similarity index 88% rename from src/com/hippo/ehviewer/dialog/SuperDialogUtil.java rename to src/com/hippo/ehviewer/widget/SuperDialogUtil.java index 3f5f76d89..4b8b74c85 100644 --- a/src/com/hippo/ehviewer/dialog/SuperDialogUtil.java +++ b/src/com/hippo/ehviewer/widget/SuperDialogUtil.java @@ -1,18 +1,18 @@ -package com.hippo.ehviewer.dialog; - -import com.hippo.ehviewer.R; - -import android.app.AlertDialog; -import android.content.Context; -import android.view.View; -import android.widget.TextView; - -public class SuperDialogUtil { - - public static void setTitle(AlertDialog dialog, String title) { - TextView titleView = (TextView)dialog.findViewById(R.id.title); - titleView.setVisibility(View.VISIBLE); - titleView.setText(title); - } - -} +package com.hippo.ehviewer.widget; + +import com.hippo.ehviewer.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +public class SuperDialogUtil { + + public static void setTitle(AlertDialog dialog, String title) { + TextView titleView = (TextView)dialog.findViewById(R.id.title); + titleView.setVisibility(View.VISIBLE); + titleView.setText(title); + } + +}