├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── kaede │ │ └── frescosample │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── diskcachesetting.md │ │ ├── loadanimage.md │ │ ├── loadanimageindetail.md │ │ └── xmlattributes.md │ ├── java │ │ └── me │ │ │ └── kaede │ │ │ ├── frescosample │ │ │ ├── FrescoApplication.java │ │ │ ├── ImageApi.java │ │ │ ├── RecyclerView │ │ │ │ ├── MyAdapter.java │ │ │ │ ├── RecyclerViewActivity.java │ │ │ │ └── RecyclerViewFragment.java │ │ │ ├── basicusage │ │ │ │ └── BasicUsageActivity.java │ │ │ ├── gif │ │ │ │ └── GifActivity.java │ │ │ ├── gifimageview │ │ │ │ └── GifImageViewActivity.java │ │ │ ├── listener │ │ │ │ └── ListenerActivity.java │ │ │ ├── listview │ │ │ │ ├── ListViewActivity.java │ │ │ │ └── MyAdapter.java │ │ │ ├── lowres │ │ │ │ └── LowResActivity.java │ │ │ ├── photoview │ │ │ │ └── PhotoViewActivity.java │ │ │ ├── postprocessor │ │ │ │ └── PostprocessorActivity.java │ │ │ ├── progressivejpg │ │ │ │ └── ProgressiveJPGActivity.java │ │ │ ├── resize │ │ │ │ └── ResizeActivity.java │ │ │ ├── samplelist │ │ │ │ ├── ActivityHolder.java │ │ │ │ ├── DividerItemDecoration.java │ │ │ │ ├── SampleListActivity.java │ │ │ │ ├── SampleListFragment.java │ │ │ │ └── SnippetFragment.java │ │ │ ├── snippet │ │ │ │ └── SnippetActivity.java │ │ │ └── subsampling │ │ │ │ └── SubsamplingActvity.java │ │ │ ├── util │ │ │ ├── ImageHolder.java │ │ │ └── fresco │ │ │ │ ├── AndroidUtils.java │ │ │ │ ├── CustomProgressDrawable.java │ │ │ │ ├── CustomProgressbarDrawable.java │ │ │ │ ├── ImageDownloadListener.java │ │ │ │ ├── cache │ │ │ │ ├── FileCache.java │ │ │ │ └── FileUtils.java │ │ │ │ ├── gifimageview │ │ │ │ └── CustomGifImageView.java │ │ │ │ ├── photoview │ │ │ │ ├── Compat.java │ │ │ │ ├── DefaultOnDoubleTapListener.java │ │ │ │ ├── HackyViewPager.java │ │ │ │ ├── IPhotoView.java │ │ │ │ ├── PhotoView.java │ │ │ │ ├── PhotoViewAttacher.java │ │ │ │ ├── gestures │ │ │ │ │ ├── CupcakeGestureDetector.java │ │ │ │ │ ├── EclairGestureDetector.java │ │ │ │ │ ├── FroyoGestureDetector.java │ │ │ │ │ ├── GestureDetector.java │ │ │ │ │ ├── OnGestureListener.java │ │ │ │ │ └── VersionedGestureDetector.java │ │ │ │ ├── log │ │ │ │ │ ├── LogManager.java │ │ │ │ │ ├── Logger.java │ │ │ │ │ └── LoggerDefault.java │ │ │ │ └── scrollerproxy │ │ │ │ │ ├── GingerScroller.java │ │ │ │ │ ├── IcsScroller.java │ │ │ │ │ ├── PreGingerScroller.java │ │ │ │ │ └── ScrollerProxy.java │ │ │ │ └── subscaleview │ │ │ │ ├── ImageSource.java │ │ │ │ ├── ImageViewState.java │ │ │ │ ├── SubsamplingScaleImageView.java │ │ │ │ └── decoder │ │ │ │ ├── CompatDecoderFactory.java │ │ │ │ ├── DecoderFactory.java │ │ │ │ ├── ImageDecoder.java │ │ │ │ ├── ImageRegionDecoder.java │ │ │ │ ├── SkiaImageDecoder.java │ │ │ │ └── SkiaImageRegionDecoder.java │ │ │ └── widget │ │ │ └── markdownview │ │ │ ├── MarkdownView.java │ │ │ ├── markdownprocessor │ │ │ ├── CharacterProtector.java │ │ │ ├── HTMLDecoder.java │ │ │ ├── HTMLToken.java │ │ │ ├── LinkDefinition.java │ │ │ ├── MarkdownProcessor.java │ │ │ ├── Replacement.java │ │ │ └── TextEditor.java │ │ │ └── util │ │ │ └── HttpHelper.java │ └── res │ │ ├── drawable-xhdpi │ │ ├── image_background.jpg │ │ ├── image_failure.jpg │ │ ├── image_placeholder.jpg │ │ ├── image_retry.png │ │ └── pattern_tile.png │ │ ├── drawable-xxhdpi │ │ ├── image_failure.png │ │ ├── image_loading.png │ │ └── image_retry.png │ │ ├── drawable │ │ └── pattern.xml │ │ ├── layout │ │ ├── activity_basic_usage.xml │ │ ├── activity_listview.xml │ │ ├── activity_photo_view.xml │ │ ├── activity_recyclerview.xml │ │ ├── activity_samplelist.xml │ │ ├── activity_simple.xml │ │ ├── activity_snippet.xml │ │ ├── activity_subsampling_actvity.xml │ │ ├── fragment_recyclerview.xml │ │ ├── item_listview.xml │ │ ├── item_recyclerview.xml │ │ ├── item_samplelist_recycleview.xml │ │ └── layout_gifimageview.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ ├── attrs.xml │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── me │ └── kaede │ └── frescosample │ └── ExampleUnitTest.java ├── build.gradle ├── doc ├── app-release-1.0.apk ├── fresco-sample-01.jpg ├── fresco-sample-02.jpg ├── preview-fresco-sample.psd └── readme-cn.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | .DS_Store 6 | /build 7 | /captures 8 | /app/build 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "me.kaede.frescosample" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:appcompat-v7:23.1.0+' 24 | compile 'com.android.support:design:23+' 25 | compile 'com.android.support:cardview-v7:23+' 26 | compile 'com.android.support:recyclerview-v7:23+' 27 | compile 'com.facebook.fresco:fresco:0.7.0+' 28 | compile 'pl.droidsonroids.gif:android-gif-drawable:1.1.7+' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\ADT\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Keep our interfaces so they can be used by other ProGuard rules. 20 | # See http://sourceforge.net/p/proguard/bugs/466/ 21 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 22 | 23 | # Do not strip any method/class that is annotated with @DoNotStrip 24 | -keep @com.facebook.common.internal.DoNotStrip class * 25 | -keepclassmembers class * { 26 | @com.facebook.common.internal.DoNotStrip *; 27 | } 28 | 29 | # Keep native methods 30 | -keepclassmembers class * { 31 | native ; 32 | } 33 | 34 | -dontwarn okio.** 35 | -dontwarn javax.annotation.** 36 | -dontwarn com.android.volley.toolbox.** 37 | -------------------------------------------------------------------------------- /app/src/androidTest/java/me/kaede/frescosample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/assets/diskcachesetting.md: -------------------------------------------------------------------------------- 1 | ## Load An Image 2 | 3 | ### Java code 4 | DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder() 5 | .setBaseDirectoryPath(new File(Environment.getExternalStorageDirectory().getAbsoluteFile(),"Moe Studio")) 6 | .setBaseDirectoryName("fresco_sample") 7 | .setMaxCacheSize(200*1024*1024)//200MB 8 | .build(); 9 | ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig.newBuilder(this) 10 | .setMainDiskCacheConfig(diskCacheConfig) 11 | .build(); 12 | Fresco.initialize(this, imagePipelineConfig); 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/assets/loadanimage.md: -------------------------------------------------------------------------------- 1 | ## Load An Image 2 | 3 | ### XML code 4 | 9 | 10 | ### Java code 11 | SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view); 12 | draweeView.setImageURI(Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png")); 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/assets/loadanimageindetail.md: -------------------------------------------------------------------------------- 1 | ## Load An Image In Detail 2 | 3 | ### XML code 4 | 9 | 10 | ### Java code 11 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.my_image_view); 12 | 13 | Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png"); 14 | Uri lowResUri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo-low-quality.png"); 15 | 16 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri) 17 | .setAutoRotateEnabled(true) 18 | .setFirstAvailableImageRequests(requests) 19 | .setLocalThumbnailPreviewsEnabled(true) 20 | .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH) 21 | .setResizeOptions(newResizeOptions(width,height)) 22 | .setProgressiveRenderingEnabled(false) 23 | .setPostprocessor(postprocessor) 24 | .build(); 25 | 26 | DraweeController controller = Fresco.newDraweeControllerBuilder() 27 | .setImageRequest(request) 28 | .setTapToRetryEnabled(true) 29 | .setAutoPlayAnimations(true) 30 | .setLowResImageRequest(ImageRequest.fromUri(lowResUri)) 31 | .setOldController(mSimpleDraweeView.getController()) 32 | .setControllerListener(controllerListener) 33 | .build(); 34 | draweeView.setController(controller); 35 | 36 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 37 | GenericDraweeHierarchy hierarchy = builder 38 | .setProgressBarImage(new ProgressBarDrawable()) 39 | .build(); 40 | draweeView.setHierarchy(hierarchy); 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/assets/xmlattributes.md: -------------------------------------------------------------------------------- 1 | ## SimpleDraweeView's Attributes 2 | 3 | ### XML code 4 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/FrescoApplication.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample; 2 | 3 | import android.app.Application; 4 | import android.os.Environment; 5 | import com.facebook.cache.disk.DiskCacheConfig; 6 | import com.facebook.common.logging.FLog; 7 | import com.facebook.drawee.backends.pipeline.Fresco; 8 | import com.facebook.imagepipeline.core.ImagePipelineConfig; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * Created by kaede on 2015/10/20. 14 | */ 15 | public class FrescoApplication extends Application { 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | 20 | FLog.setMinimumLoggingLevel(FLog.VERBOSE); 21 | //Fresco.initialize(this); 22 | DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder() 23 | .setBaseDirectoryPath(new File(Environment.getExternalStorageDirectory().getAbsoluteFile(),"Moe Studio")) 24 | .setBaseDirectoryName("fresco_sample") 25 | .setMaxCacheSize(200*1024*1024)//200MB 26 | .build(); 27 | ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig.newBuilder(this) 28 | .setMainDiskCacheConfig(diskCacheConfig) 29 | .build(); 30 | Fresco.initialize(this, imagePipelineConfig); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/ImageApi.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample; 2 | 3 | import me.kaede.util.ImageHolder; 4 | 5 | /** 6 | * Created by kaede on 2015/10/21. 7 | * sample : http://dn-assets-gitcafe-com.qbox.me/Kaedea/Kaede-Assets/raw/gitcafe-pages/image/girly/jk-01.jpg 8 | */ 9 | public class ImageApi { 10 | public static final String DOMAIN = "http://dn-assets-gitcafe-com.qbox.me"; 11 | private static final String BASE_DIR = "Kaedea/Kaede-Assets/raw/gitcafe-pages/image"; 12 | public static ImageHolder girly = new ImageHolder(DOMAIN, BASE_DIR,"girly","jk-",".jpg",17,"00"); 13 | public static ImageHolder jk = new ImageHolder(DOMAIN, BASE_DIR,"jk","jk-",".jpg",30,"00"); 14 | public static ImageHolder legs = new ImageHolder(DOMAIN, BASE_DIR,"legs","legs-",".jpg",29,"00"); 15 | public static ImageHolder other = new ImageHolder(DOMAIN, BASE_DIR,"other","",".jpg",Integer.MAX_VALUE,"00"); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/RecyclerView/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.recyclerview; 2 | 3 | import android.graphics.drawable.Animatable; 4 | import android.net.Uri; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.CardView; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import com.facebook.common.logging.FLog; 12 | import com.facebook.drawee.backends.pipeline.Fresco; 13 | import com.facebook.drawee.controller.BaseControllerListener; 14 | import com.facebook.drawee.controller.ControllerListener; 15 | import com.facebook.drawee.interfaces.DraweeController; 16 | import com.facebook.drawee.view.SimpleDraweeView; 17 | import com.facebook.imagepipeline.image.ImageInfo; 18 | import com.facebook.imagepipeline.image.QualityInfo; 19 | import me.kaede.frescosample.R; 20 | 21 | import java.util.ArrayList; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | /** 27 | * Created by kaede on 2015/10/22. 28 | */ 29 | public class MyAdapter extends RecyclerView.Adapter { 30 | int index; 31 | 32 | List datas = new ArrayList<>(); 33 | Map heightMap = new HashMap<>(); 34 | static Map widthMap = new HashMap<>(); 35 | 36 | public MyAdapter(int index) { 37 | this.index = index; 38 | } 39 | 40 | public List getDatas() { 41 | return datas; 42 | } 43 | 44 | public void setDatas(List datas) { 45 | if (datas!=null&&datas.size()>0){ 46 | this.datas.clear(); 47 | this.datas.addAll(datas); 48 | notifyDataSetChanged(); 49 | } 50 | } 51 | 52 | @Override 53 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 54 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview, parent, false); 55 | return new ViewHolder(view); 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(final ViewHolder holder, int position) { 60 | final String url = getDatas().get(position); 61 | if (heightMap.containsKey(url)){ 62 | int height = heightMap.get(url); 63 | FLog.i("kaede", url+ "'s height = " + height); 64 | if (height>0){ 65 | updateItemtHeight(height,holder.itemView); 66 | holder.draweeView.setImageURI(Uri.parse(url)); 67 | return; 68 | } 69 | 70 | } 71 | ControllerListener controllerListener = new BaseControllerListener() { 72 | @Override 73 | public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable anim) { 74 | if (imageInfo == null) { 75 | return; 76 | } 77 | QualityInfo qualityInfo = imageInfo.getQualityInfo(); 78 | if (qualityInfo.isOfGoodEnoughQuality()){ 79 | int heightTarget = (int) getTargetHeight(imageInfo.getWidth(),imageInfo.getHeight(),holder.itemView,url); 80 | FLog.i("kaede", "heightTarget = " + heightTarget); 81 | if (heightTarget<=0)return; 82 | heightMap.put(url,heightTarget); 83 | updateItemtHeight(heightTarget, holder.itemView); 84 | } 85 | } 86 | 87 | @Override 88 | public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) { 89 | } 90 | 91 | @Override 92 | public void onFailure(String id, Throwable throwable) { 93 | } 94 | }; 95 | DraweeController controller = Fresco.newDraweeControllerBuilder() 96 | .setUri(Uri.parse(url)) 97 | .setControllerListener(controllerListener) 98 | .setTapToRetryEnabled(true) 99 | .build(); 100 | holder.draweeView.setController(controller); 101 | holder.itemView.setOnClickListener(new View.OnClickListener() { 102 | @Override 103 | public void onClick(View v) { 104 | 105 | } 106 | }); 107 | } 108 | 109 | private float getTargetHeight(float width,float height,View view, String url){ 110 | View child = view.findViewById(R.id.draweeview); 111 | float widthTarget; 112 | if (widthMap.containsKey(url)) widthTarget = widthMap.get(url); 113 | else { 114 | widthTarget = child.getMeasuredWidth(); 115 | if (widthTarget>0){ 116 | widthMap.put(url, (int) widthTarget); 117 | } 118 | } 119 | 120 | FLog.i("kaede","child.getMeasuredWidth() = " + widthTarget); 121 | /*int getWidth = child.getWidth(); 122 | int getMeasuredWidth = child.getMeasuredWidth(); 123 | int getLayoutParamsWidth = child.getLayoutParams().width; 124 | if (getWidth==0||getMeasuredWidth==0||getLayoutParamsWidth==0){ 125 | FLog.i("kaede","child.getWidth() = " + getWidth); 126 | FLog.i("kaede","child.getMeasuredWidth() = " + getMeasuredWidth); 127 | FLog.i("kaede","child.getLayoutParams().width = " + getLayoutParamsWidth); 128 | }*/ 129 | return height * (widthTarget /width); 130 | } 131 | 132 | private void updateItemtHeight(int height, View view) { 133 | CardView cardView = (CardView) view.findViewById(R.id.cardview); 134 | View child = view.findViewById(R.id.draweeview); 135 | CardView.LayoutParams layoutParams = (CardView.LayoutParams) child.getLayoutParams(); 136 | layoutParams.height = height; 137 | cardView.updateViewLayout(child,layoutParams); 138 | } 139 | 140 | @Override 141 | public int getItemCount() { 142 | return datas.size(); 143 | } 144 | 145 | public class ViewHolder extends RecyclerView.ViewHolder{ 146 | SimpleDraweeView draweeView; 147 | 148 | public ViewHolder(View itemView) { 149 | super(itemView); 150 | draweeView = (SimpleDraweeView) itemView.findViewById(R.id.draweeview); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/RecyclerView/RecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.recyclerview; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.os.Bundle; 10 | import android.support.v7.widget.Toolbar; 11 | import me.kaede.frescosample.R; 12 | 13 | public class RecyclerViewActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_recyclerview); 19 | 20 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 21 | setSupportActionBar(toolbar); 22 | 23 | TabLayout tabLayout = (TabLayout) this.findViewById(R.id.tablayout); 24 | ViewPager viewPager = (ViewPager) this.findViewById(R.id.viewpager); 25 | viewPager.setAdapter(new MyAdapter(getSupportFragmentManager())); 26 | viewPager.setOffscreenPageLimit(3); 27 | tabLayout.setupWithViewPager(viewPager); 28 | } 29 | 30 | public class MyAdapter extends FragmentStatePagerAdapter { 31 | public String[] pagers = new String[]{"ヒトツ","フタツ","ミツ"}; 32 | public MyAdapter(FragmentManager fm) { 33 | super(fm); 34 | } 35 | 36 | @Override 37 | public Fragment getItem(int position) { 38 | return RecyclerViewFragment.newInstance(position); 39 | } 40 | 41 | @Override 42 | public int getCount() { 43 | return pagers.length; 44 | } 45 | 46 | @Override 47 | public CharSequence getPageTitle(int position) { 48 | return pagers[position]; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/RecyclerView/RecyclerViewFragment.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.recyclerview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.StaggeredGridLayoutManager; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import me.kaede.frescosample.ImageApi; 11 | import me.kaede.frescosample.R; 12 | 13 | import java.util.List; 14 | 15 | 16 | public class RecyclerViewFragment extends Fragment{ 17 | private static final String BUNDLE_INDEX = "BUNDLE_INDEX"; 18 | 19 | private int index; 20 | 21 | 22 | 23 | public static RecyclerViewFragment newInstance(int index) { 24 | RecyclerViewFragment fragment = new RecyclerViewFragment(); 25 | Bundle args = new Bundle(); 26 | args.putInt(BUNDLE_INDEX, index); 27 | fragment.setArguments(args); 28 | return fragment; 29 | } 30 | 31 | 32 | @Override 33 | public void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | if (getArguments() != null) { 36 | index = getArguments().getInt(BUNDLE_INDEX); 37 | } 38 | } 39 | 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 42 | Bundle savedInstanceState) { 43 | View view = inflater.inflate(R.layout.fragment_recyclerview, container, false); 44 | 45 | 46 | //find view 47 | RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); 48 | 49 | //init 50 | StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(index+1,StaggeredGridLayoutManager.VERTICAL); 51 | recyclerView.setLayoutManager(layoutManager); 52 | MyAdapter adapter = new MyAdapter(index); 53 | recyclerView.setAdapter(adapter); 54 | recyclerView.setHasFixedSize(false); 55 | List datas; 56 | switch (index) { 57 | case 0: 58 | default: 59 | datas = ImageApi.jk.getUrls(); 60 | break; 61 | case 1: 62 | datas = ImageApi.girly.getUrls(); 63 | break; 64 | case 2: 65 | datas = ImageApi.legs.getUrls(); 66 | break; 67 | } 68 | adapter.setDatas(datas); 69 | 70 | return view; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/basicusage/BasicUsageActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.basicusage; 2 | 3 | import android.graphics.PointF; 4 | import android.net.Uri; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.support.v7.widget.Toolbar; 10 | import android.view.View; 11 | import com.facebook.common.util.UriUtil; 12 | import com.facebook.drawee.backends.pipeline.Fresco; 13 | import com.facebook.drawee.drawable.ProgressBarDrawable; 14 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 15 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 16 | import com.facebook.drawee.interfaces.DraweeController; 17 | import com.facebook.drawee.view.SimpleDraweeView; 18 | import me.kaede.frescosample.ImageApi; 19 | import me.kaede.frescosample.R; 20 | 21 | public class BasicUsageActivity extends AppCompatActivity { 22 | 23 | Handler handler = new Handler(Looper.getMainLooper()); 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_basic_usage); 29 | Toolbar toolbar = (Toolbar) this.findViewById(R.id.toolbar); 30 | this.setSupportActionBar(toolbar); 31 | 32 | SimpleDraweeView draweeView; 33 | DraweeController controller; 34 | 35 | // basic 36 | draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_basic); 37 | draweeView.setImageURI(Uri.parse(ImageApi.jk.getUrl(0))); 38 | 39 | // ScaleType FocusCrop 40 | draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_basic_focus); 41 | draweeView.getHierarchy().setActualImageFocusPoint(new PointF(0, 0)); 42 | draweeView.setImageURI(Uri.parse(ImageApi.jk.getUrl(0))); 43 | 44 | // ScaleType Tile 45 | Uri uri = new Uri.Builder() 46 | .scheme(UriUtil.LOCAL_RESOURCE_SCHEME) // "res" 47 | .path(String.valueOf(R.drawable.pattern)) 48 | .build(); 49 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_tile)).setImageURI(uri); 50 | 51 | // Placeholder Image 52 | handler.postDelayed(new Runnable() { 53 | @Override 54 | public void run() { 55 | ((SimpleDraweeView) BasicUsageActivity.this.findViewById(R.id.drawee_basic_placeholder)).setImageURI(Uri.parse(ImageApi.jk.getUrl(1))); 56 | } 57 | }, 2000); 58 | 59 | // Fade Duration 60 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_fade)).setImageURI(Uri.parse(ImageApi.jk.getUrl(2))); 61 | 62 | // Corner Radius 63 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_radius)).setImageURI(Uri.parse(ImageApi.jk.getUrl(3))); 64 | 65 | // Circle 66 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_circle)).setImageURI(Uri.parse(ImageApi.jk.getUrl(4))); 67 | 68 | // Failure Image 69 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_failure)).setImageURI(Uri.parse(ImageApi.other.getUrlByName("does-not-have-this-url"))); 70 | 71 | // Retry Image 72 | draweeView = ((SimpleDraweeView) findViewById(R.id.drawee_basic_retry)); 73 | controller = Fresco.newDraweeControllerBuilder() 74 | .setUri(Uri.parse(ImageApi.other.getUrlByName("does-not-have-this-url"))) 75 | .setTapToRetryEnabled(true) 76 | .build(); 77 | draweeView.setController(controller); 78 | 79 | // ProgressBar Image 80 | draweeView = ((SimpleDraweeView) findViewById(R.id.drawee_basic_progressbar)); 81 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 82 | GenericDraweeHierarchy hierarchy = builder 83 | .setProgressBarImage(new ProgressBarDrawable()) 84 | .build(); 85 | draweeView.setHierarchy(hierarchy); 86 | draweeView.setImageURI(Uri.parse(ImageApi.jk.getUrl(5))); 87 | 88 | // Background Image 89 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_backround)).setImageURI(Uri.parse(ImageApi.jk.getUrl(6))); 90 | 91 | // Overlay Image 92 | ((SimpleDraweeView) findViewById(R.id.drawee_basic_overlay)).setImageURI(Uri.parse(ImageApi.jk.getUrl(7))); 93 | 94 | // PressedStateOverlay Image 95 | draweeView = ((SimpleDraweeView) findViewById(R.id.drawee_basic_press)); 96 | draweeView.setImageURI(Uri.parse(ImageApi.jk.getUrl(8))); 97 | draweeView.setOnClickListener(new View.OnClickListener() { 98 | @Override 99 | public void onClick(View v) { 100 | 101 | } 102 | }); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/gif/GifActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.gif; 2 | 3 | import android.net.Uri; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | import com.facebook.drawee.drawable.ProgressBarDrawable; 8 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 9 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 10 | import com.facebook.drawee.interfaces.DraweeController; 11 | import com.facebook.drawee.view.SimpleDraweeView; 12 | import me.kaede.frescosample.ImageApi; 13 | import me.kaede.frescosample.R; 14 | 15 | public class GifActivity extends AppCompatActivity { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_simple); 21 | 22 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 23 | DraweeController controller = Fresco.newDraweeControllerBuilder() 24 | .setUri(Uri.parse(ImageApi.other.getUrlByName("animation2",".gif"))) 25 | .setTapToRetryEnabled(true) 26 | .setAutoPlayAnimations(true) 27 | .build(); 28 | draweeView.setController(controller); 29 | 30 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 31 | GenericDraweeHierarchy hierarchy = builder 32 | .setProgressBarImage(new ProgressBarDrawable()) 33 | .build(); 34 | draweeView.setHierarchy(hierarchy); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/gifimageview/GifImageViewActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.gifimageview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | 7 | import me.kaede.frescosample.ImageApi; 8 | import me.kaede.util.fresco.ImageDownloadListener; 9 | import me.kaede.util.fresco.gifimageview.CustomGifImageView; 10 | 11 | public class GifImageViewActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | 17 | CustomGifImageView gifView = new CustomGifImageView(this); 18 | gifView.setImageDownloadListener(new ImageDownloadListener() { 19 | @Override 20 | public void onUpdate(int progress) { 21 | Log.d("GifImageViewActivity","[onCreate][onUpdate] progress = " + progress ); 22 | } 23 | }); 24 | setContentView(gifView); 25 | gifView.setImageUrl(ImageApi.other.getUrlByName("animation2", ".gif")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/listener/ListenerActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.listener; 2 | 3 | import android.graphics.drawable.Animatable; 4 | import android.net.Uri; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | import android.widget.Toast; 9 | import com.facebook.common.logging.FLog; 10 | import com.facebook.drawee.backends.pipeline.Fresco; 11 | import com.facebook.drawee.controller.BaseControllerListener; 12 | import com.facebook.drawee.controller.ControllerListener; 13 | import com.facebook.drawee.drawable.ScalingUtils; 14 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 15 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 16 | import com.facebook.drawee.interfaces.DraweeController; 17 | import com.facebook.drawee.view.SimpleDraweeView; 18 | import com.facebook.imagepipeline.image.ImageInfo; 19 | import com.facebook.imagepipeline.image.QualityInfo; 20 | import me.kaede.frescosample.ImageApi; 21 | import me.kaede.frescosample.R; 22 | 23 | public class ListenerActivity extends AppCompatActivity { 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_simple); 29 | 30 | ControllerListener controllerListener = new BaseControllerListener() { 31 | @Override 32 | public void onFinalImageSet( 33 | String id, 34 | @Nullable ImageInfo imageInfo, 35 | @Nullable Animatable anim) { 36 | if (imageInfo == null) { 37 | return; 38 | } 39 | QualityInfo qualityInfo = imageInfo.getQualityInfo(); 40 | FLog.d("Final image received! " + 41 | "Size %d x %d", 42 | "Quality level %d, good enough: %s, full quality: %s", 43 | imageInfo.getWidth(), 44 | imageInfo.getHeight(), 45 | qualityInfo.getQuality(), 46 | qualityInfo.isOfGoodEnoughQuality(), 47 | qualityInfo.isOfFullQuality()); 48 | } 49 | 50 | @Override 51 | public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) { 52 | } 53 | 54 | @Override 55 | public void onFailure(String id, Throwable throwable) { 56 | FLog.e(getClass(), throwable, "Error loading %s", id); 57 | Toast.makeText(ListenerActivity.this,"Error loading, id = "+id,Toast.LENGTH_LONG).show(); 58 | } 59 | }; 60 | 61 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 62 | DraweeController controller = Fresco.newDraweeControllerBuilder() 63 | .setUri(Uri.parse(ImageApi.other.getUrlByName("does-not-have-this-url"))) 64 | .setControllerListener(controllerListener) 65 | .setTapToRetryEnabled(true) 66 | .build(); 67 | draweeView.setController(controller); 68 | 69 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 70 | GenericDraweeHierarchy hierarchy = builder 71 | .setFailureImage(getResources().getDrawable(R.drawable.image_failure), ScalingUtils.ScaleType.CENTER) 72 | .setRetryImage(getResources().getDrawable(R.drawable.image_retry), ScalingUtils.ScaleType.CENTER) 73 | .build(); 74 | draweeView.setHierarchy(hierarchy); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/listview/ListViewActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.listview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.ListView; 9 | import me.kaede.frescosample.ImageApi; 10 | import me.kaede.frescosample.R; 11 | 12 | public class ListViewActivity extends AppCompatActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_listview); 18 | 19 | ListView listView = (ListView) this.findViewById(R.id.list_main); 20 | MyAdapter adapter = new MyAdapter(); 21 | listView.setAdapter(adapter); 22 | 23 | adapter.setDatas(ImageApi.jk.getUrls()); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/listview/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.listview; 2 | 3 | import android.net.Uri; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import com.facebook.drawee.view.SimpleDraweeView; 9 | import me.kaede.frescosample.R; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by kaede on 2015/10/22. 16 | */ 17 | public class MyAdapter extends BaseAdapter { 18 | List datas = new ArrayList<>(); 19 | 20 | public List getDatas() { 21 | return datas; 22 | } 23 | 24 | public void setDatas(List datas) { 25 | if (datas!=null&&datas.size()>0){ 26 | this.datas.clear(); 27 | this.datas.addAll(datas); 28 | notifyDataSetChanged(); 29 | } 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | return datas.size(); 35 | } 36 | 37 | @Override 38 | public String getItem(int position) { 39 | return datas.get(position); 40 | } 41 | 42 | @Override 43 | public long getItemId(int position) { 44 | return position; 45 | } 46 | 47 | @Override 48 | public View getView(int position, View convertView, ViewGroup parent) { 49 | if (convertView == null){ 50 | convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_listview,parent,false); 51 | convertView.setTag(new ViewHolder((SimpleDraweeView) convertView.findViewById(R.id.draweeview))); 52 | } 53 | ViewHolder holder = (ViewHolder) convertView.getTag(); 54 | holder.draweeView.setImageURI(Uri.parse(getItem(position))); 55 | return convertView; 56 | } 57 | 58 | public class ViewHolder{ 59 | SimpleDraweeView draweeView; 60 | 61 | public ViewHolder(SimpleDraweeView draweeView) { 62 | this.draweeView = draweeView; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/lowres/LowResActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.lowres; 2 | 3 | import android.net.Uri; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | import com.facebook.drawee.drawable.ProgressBarDrawable; 8 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 9 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 10 | import com.facebook.drawee.interfaces.DraweeController; 11 | import com.facebook.drawee.view.SimpleDraweeView; 12 | import com.facebook.imagepipeline.request.ImageRequest; 13 | import me.kaede.frescosample.ImageApi; 14 | import me.kaede.frescosample.R; 15 | 16 | public class LowResActivity extends AppCompatActivity { 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_simple); 22 | 23 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 24 | DraweeController controller = Fresco.newDraweeControllerBuilder() 25 | .setUri(Uri.parse(ImageApi.other.getUrlByName("lowres-big", ".jpg"))) 26 | .setLowResImageRequest(ImageRequest.fromUri(Uri.parse(ImageApi.other.getUrlByName("lowres-small", ".jpg")))) 27 | .setTapToRetryEnabled(true) 28 | .build(); 29 | draweeView.setController(controller); 30 | 31 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 32 | GenericDraweeHierarchy hierarchy = builder 33 | .setProgressBarImage(new ProgressBarDrawable()) 34 | .build(); 35 | draweeView.setHierarchy(hierarchy); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/photoview/PhotoViewActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.photoview; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.support.v4.view.ViewPager; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import me.kaede.frescosample.ImageApi; 11 | import me.kaede.frescosample.R; 12 | import me.kaede.util.fresco.photoview.HackyViewPager; 13 | import me.kaede.util.fresco.photoview.PhotoView; 14 | 15 | import java.util.List; 16 | 17 | public class PhotoViewActivity extends AppCompatActivity { 18 | 19 | private static final String ISLOCKED_ARG = "isLocked"; 20 | private ViewPager mViewPager; 21 | private int position; 22 | 23 | @Override 24 | public void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_photo_view); 27 | mViewPager = (HackyViewPager) findViewById(R.id.viewpager); 28 | 29 | mViewPager.setAdapter(new SamplePagerAdapter()); 30 | if (getIntent() != null) { 31 | position = getIntent().getIntExtra("position", 0); 32 | mViewPager.setCurrentItem(position); 33 | } 34 | 35 | if (savedInstanceState != null) { 36 | boolean isLocked = savedInstanceState.getBoolean(ISLOCKED_ARG, false); 37 | ((HackyViewPager) mViewPager).setLocked(isLocked); 38 | } 39 | 40 | } 41 | 42 | static class SamplePagerAdapter extends PagerAdapter { 43 | 44 | List datas = ImageApi.jk.getUrls(); 45 | 46 | @Override 47 | public int getCount() { 48 | return datas.size(); 49 | } 50 | 51 | @Override 52 | public View instantiateItem(ViewGroup container, int position) { 53 | PhotoView photoView = new PhotoView(container.getContext()); 54 | photoView.setImageUri(datas.get(position)); 55 | 56 | // Now just add PhotoView to ViewPager and return it 57 | container.addView(photoView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 58 | 59 | return photoView; 60 | } 61 | 62 | @Override 63 | public void destroyItem(ViewGroup container, int position, Object object) { 64 | container.removeView((View) object); 65 | } 66 | 67 | @Override 68 | public boolean isViewFromObject(View view, Object object) { 69 | return view == object; 70 | } 71 | 72 | } 73 | 74 | private boolean isViewPagerActive() { 75 | return (mViewPager != null && mViewPager instanceof HackyViewPager); 76 | } 77 | 78 | @Override 79 | protected void onSaveInstanceState(@NonNull Bundle outState) { 80 | if (isViewPagerActive()) { 81 | outState.putBoolean(ISLOCKED_ARG, ((HackyViewPager) mViewPager).isLocked()); 82 | } 83 | super.onSaveInstanceState(outState); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/postprocessor/PostprocessorActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.postprocessor; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | import android.net.Uri; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | import com.facebook.drawee.backends.pipeline.Fresco; 9 | import com.facebook.drawee.drawable.ProgressBarDrawable; 10 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 11 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 12 | import com.facebook.drawee.interfaces.DraweeController; 13 | import com.facebook.drawee.view.SimpleDraweeView; 14 | import com.facebook.imagepipeline.request.BasePostprocessor; 15 | import com.facebook.imagepipeline.request.ImageRequest; 16 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 17 | import com.facebook.imagepipeline.request.Postprocessor; 18 | import me.kaede.frescosample.ImageApi; 19 | import me.kaede.frescosample.R; 20 | 21 | public class PostprocessorActivity extends AppCompatActivity { 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_simple); 27 | 28 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 29 | 30 | Postprocessor redMeshPostprocessor = new BasePostprocessor() { 31 | @Override 32 | public String getName() { 33 | return "redMeshPostprocessor"; 34 | } 35 | 36 | @Override 37 | public void process(Bitmap bitmap) { 38 | for (int x = 0; x < bitmap.getWidth(); x+=2) { 39 | for (int y = 0; y < bitmap.getHeight(); y+=2) { 40 | bitmap.setPixel(x, y, Color.RED); 41 | } 42 | } 43 | } 44 | }; 45 | 46 | Uri uri = Uri.parse(ImageApi.other.getUrlByName("lowres-small", ".jpg")); 47 | 48 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri) 49 | .setAutoRotateEnabled(true) 50 | .setLocalThumbnailPreviewsEnabled(true) 51 | .setProgressiveRenderingEnabled(false) 52 | .setPostprocessor(redMeshPostprocessor) 53 | .build(); 54 | 55 | DraweeController controller = Fresco.newDraweeControllerBuilder() 56 | .setImageRequest(request) 57 | .build(); 58 | draweeView.setController(controller); 59 | 60 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 61 | GenericDraweeHierarchy hierarchy = builder 62 | .setProgressBarImage(new ProgressBarDrawable()) 63 | .build(); 64 | draweeView.setHierarchy(hierarchy); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/progressivejpg/ProgressiveJPGActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.progressivejpg; 2 | 3 | import android.net.Uri; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | import com.facebook.drawee.drawable.ProgressBarDrawable; 8 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 9 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 10 | import com.facebook.drawee.interfaces.DraweeController; 11 | import com.facebook.drawee.view.SimpleDraweeView; 12 | import com.facebook.imagepipeline.request.ImageRequest; 13 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 14 | import me.kaede.frescosample.ImageApi; 15 | import me.kaede.frescosample.R; 16 | 17 | public class ProgressiveJPGActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_simple); 23 | 24 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 25 | 26 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(ImageApi.other.getUrlByName("lowres-big", ".jpg"))) 27 | .setAutoRotateEnabled(true) 28 | .setLocalThumbnailPreviewsEnabled(true) 29 | .setProgressiveRenderingEnabled(true) 30 | .build(); 31 | 32 | DraweeController controller = Fresco.newDraweeControllerBuilder() 33 | .setImageRequest(request) 34 | .build(); 35 | draweeView.setController(controller); 36 | 37 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 38 | GenericDraweeHierarchy hierarchy = builder 39 | .setProgressBarImage(new ProgressBarDrawable()) 40 | .setPlaceholderImage(getResources().getDrawable(R.drawable.image_loading)) 41 | .build(); 42 | draweeView.setHierarchy(hierarchy); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/resize/ResizeActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.resize; 2 | 3 | import android.net.Uri; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | import com.facebook.drawee.drawable.ProgressBarDrawable; 8 | import com.facebook.drawee.drawable.ScalingUtils; 9 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 10 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 11 | import com.facebook.drawee.interfaces.DraweeController; 12 | import com.facebook.drawee.view.SimpleDraweeView; 13 | import com.facebook.imagepipeline.common.ResizeOptions; 14 | import com.facebook.imagepipeline.request.ImageRequest; 15 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 16 | import me.kaede.frescosample.ImageApi; 17 | import me.kaede.frescosample.R; 18 | 19 | public class ResizeActivity extends AppCompatActivity { 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_simple); 25 | SimpleDraweeView draweeView = (SimpleDraweeView) this.findViewById(R.id.drawee_main); 26 | 27 | ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(ImageApi.other.getUrlByName("lowres-big", ".jpg"))) 28 | .setAutoRotateEnabled(true) 29 | .setLocalThumbnailPreviewsEnabled(true) 30 | .setResizeOptions(new ResizeOptions(450,800)) 31 | .setProgressiveRenderingEnabled(false) 32 | .build(); 33 | 34 | DraweeController controller = Fresco.newDraweeControllerBuilder() 35 | .setImageRequest(request) 36 | .build(); 37 | draweeView.setController(controller); 38 | 39 | GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(getResources()); 40 | GenericDraweeHierarchy hierarchy = builder 41 | .setProgressBarImage(new ProgressBarDrawable()) 42 | .setActualImageScaleType(ScalingUtils.ScaleType.CENTER) 43 | .build(); 44 | draweeView.setHierarchy(hierarchy); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/samplelist/ActivityHolder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.samplelist; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * 用于Demo项目中,管理各种Activity,以及Activity之间的跳转 14 | * Created by kaede on 2015/10/13. 15 | */ 16 | public class ActivityHolder { 17 | Map> activityMap; 18 | List nameList; 19 | 20 | public ActivityHolder(){ 21 | activityMap = new HashMap<>(); 22 | nameList = new ArrayList<>(); 23 | } 24 | 25 | public void addActivity(String name,Class activity){ 26 | if (!activityMap.containsKey(name)) { 27 | nameList.add(name); 28 | activityMap.put(name,activity); 29 | } 30 | } 31 | 32 | public List getNameList() { 33 | return nameList; 34 | } 35 | 36 | public String getActivityName(int position){ 37 | return getNameList().get(position); 38 | } 39 | 40 | public Map> getActivityMap() { 41 | return activityMap; 42 | } 43 | 44 | public Class getActivity(String name){ 45 | return activityMap.get(name); 46 | } 47 | 48 | public Class getActivity(int position){ 49 | return activityMap.get(getActivityName(position)); 50 | } 51 | 52 | public void startActivity(Context context, String activityName){ 53 | context.startActivity(new Intent(context,getActivity(activityName))); 54 | } 55 | 56 | public void startActivity(Context context, int position){ 57 | context.startActivity(new Intent(context,getActivity(position))); 58 | } 59 | 60 | public static void startActivity(Context context, Class activityClass){ 61 | context.startActivity(new Intent(context,activityClass)); 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/samplelist/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.samplelist; 2 | 3 | /* 4 | * Copyright (C) 2014 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * limitations under the License. 8 | */ 9 | 10 | import android.content.Context; 11 | import android.content.res.TypedArray; 12 | import android.graphics.Canvas; 13 | import android.graphics.Rect; 14 | import android.graphics.drawable.Drawable; 15 | import android.support.v7.widget.LinearLayoutManager; 16 | import android.support.v7.widget.RecyclerView; 17 | import android.util.Log; 18 | import android.view.View; 19 | 20 | 21 | /** 22 | * This class is from the v7 samples of the Android SDK. It's not by me! 23 | *

24 | * See the license above for details. 25 | */ 26 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 27 | 28 | private static final int[] ATTRS = new int[]{ 29 | android.R.attr.listDivider 30 | }; 31 | 32 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 33 | 34 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 35 | 36 | private Drawable mDivider; 37 | 38 | private int mOrientation; 39 | 40 | public DividerItemDecoration(Context context, int orientation) { 41 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 42 | mDivider = a.getDrawable(0); 43 | a.recycle(); 44 | setOrientation(orientation); 45 | } 46 | 47 | public void setOrientation(int orientation) { 48 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 49 | throw new IllegalArgumentException("invalid orientation"); 50 | } 51 | mOrientation = orientation; 52 | } 53 | 54 | @Override 55 | public void onDraw(Canvas c, RecyclerView parent) { 56 | Log.v("itemdecoration","onDraw()"); 57 | 58 | if (mOrientation == VERTICAL_LIST) { 59 | drawVertical(c, parent); 60 | } else { 61 | drawHorizontal(c, parent); 62 | } 63 | 64 | } 65 | 66 | 67 | public void drawVertical(Canvas c, RecyclerView parent) { 68 | final int left = parent.getPaddingLeft(); 69 | final int right = parent.getWidth() - parent.getPaddingRight(); 70 | 71 | final int childCount = parent.getChildCount(); 72 | for (int i = 0; i < childCount; i++) { 73 | final View child = parent.getChildAt(i); 74 | android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); 75 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 76 | .getLayoutParams(); 77 | final int top = child.getBottom() + params.bottomMargin; 78 | final int bottom = top + mDivider.getIntrinsicHeight(); 79 | mDivider.setBounds(left, top, right, bottom); 80 | mDivider.draw(c); 81 | } 82 | } 83 | 84 | public void drawHorizontal(Canvas c, RecyclerView parent) { 85 | final int top = parent.getPaddingTop(); 86 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 87 | 88 | final int childCount = parent.getChildCount(); 89 | for (int i = 0; i < childCount; i++) { 90 | final View child = parent.getChildAt(i); 91 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 92 | .getLayoutParams(); 93 | final int left = child.getRight() + params.rightMargin; 94 | final int right = left + mDivider.getIntrinsicHeight(); 95 | mDivider.setBounds(left, top, right, bottom); 96 | mDivider.draw(c); 97 | } 98 | } 99 | 100 | @Override 101 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { 102 | if (mOrientation == VERTICAL_LIST) { 103 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 104 | } else { 105 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/samplelist/SampleListActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.samplelist; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.TabLayout; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.app.FragmentStatePagerAdapter; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import me.kaede.frescosample.R; 12 | 13 | public class SampleListActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_recyclerview); 19 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 20 | setSupportActionBar(toolbar); 21 | getSupportActionBar().setTitle(R.string.app_name); 22 | 23 | TabLayout tabLayout = (TabLayout) this.findViewById(R.id.tablayout); 24 | ViewPager viewPager = (ViewPager) this.findViewById(R.id.viewpager); 25 | viewPager.setAdapter(new MyAdapter(getSupportFragmentManager())); 26 | viewPager.setOffscreenPageLimit(1); 27 | tabLayout.setupWithViewPager(viewPager); 28 | } 29 | 30 | public class MyAdapter extends FragmentStatePagerAdapter { 31 | public String[] pagers = new String[]{"DraweeView","CustomView","CodeSnippet"}; 32 | public MyAdapter(FragmentManager fm) { 33 | super(fm); 34 | } 35 | 36 | @Override 37 | public Fragment getItem(int position) { 38 | if (position==2)return SnippetFragment.newInstance(); 39 | return SampleListFragment.newInstance(position); 40 | } 41 | 42 | @Override 43 | public int getCount() { 44 | return pagers.length; 45 | } 46 | 47 | @Override 48 | public CharSequence getPageTitle(int position) { 49 | return pagers[position]; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/samplelist/SampleListFragment.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.samplelist; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import me.kaede.frescosample.R; 13 | import me.kaede.frescosample.basicusage.BasicUsageActivity; 14 | import me.kaede.frescosample.gif.GifActivity; 15 | import me.kaede.frescosample.gifimageview.GifImageViewActivity; 16 | import me.kaede.frescosample.listener.ListenerActivity; 17 | import me.kaede.frescosample.listview.ListViewActivity; 18 | import me.kaede.frescosample.lowres.LowResActivity; 19 | import me.kaede.frescosample.photoview.PhotoViewActivity; 20 | import me.kaede.frescosample.postprocessor.PostprocessorActivity; 21 | import me.kaede.frescosample.progressivejpg.ProgressiveJPGActivity; 22 | import me.kaede.frescosample.recyclerview.RecyclerViewActivity; 23 | import me.kaede.frescosample.resize.ResizeActivity; 24 | import me.kaede.frescosample.subsampling.SubsamplingActvity; 25 | 26 | /** 27 | * Created by kaede on 2015/10/23. 28 | */ 29 | public class SampleListFragment extends Fragment{ 30 | private static final String BUNDLE_INDEX = "BUNDLE_INDEX"; 31 | 32 | private int index; 33 | ActivityHolder activityHolder; 34 | 35 | 36 | public static SampleListFragment newInstance(int index) { 37 | SampleListFragment fragment = new SampleListFragment(); 38 | Bundle args = new Bundle(); 39 | args.putInt(BUNDLE_INDEX, index); 40 | fragment.setArguments(args); 41 | return fragment; 42 | } 43 | 44 | 45 | @Override 46 | public void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | if (getArguments() != null) { 49 | index = getArguments().getInt(BUNDLE_INDEX); 50 | } 51 | } 52 | 53 | @Override 54 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 55 | Bundle savedInstanceState) { 56 | View view = inflater.inflate(R.layout.fragment_recyclerview, container, false); 57 | 58 | 59 | //find view 60 | RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); 61 | 62 | 63 | activityHolder = new ActivityHolder(); 64 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); 65 | recyclerView.setLayoutManager(linearLayoutManager); 66 | MyAdapter adapter = new MyAdapter(); 67 | recyclerView.setAdapter(adapter); 68 | recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL_LIST)); 69 | 70 | switch (index) { 71 | case 0: 72 | default: 73 | activityHolder.addActivity("Basic Usage", BasicUsageActivity.class); 74 | activityHolder.addActivity("Gif/WebP Animation Image", GifActivity.class); 75 | activityHolder.addActivity("Low Resolution Image", LowResActivity.class); 76 | activityHolder.addActivity("Add Loading Listener", ListenerActivity.class); 77 | activityHolder.addActivity("Progressive JPG Streaming", ProgressiveJPGActivity.class); 78 | activityHolder.addActivity("Resize Image", ResizeActivity.class); 79 | activityHolder.addActivity("Use Postprocessor", PostprocessorActivity.class); 80 | activityHolder.addActivity("Usage with ListView", ListViewActivity.class); 81 | activityHolder.addActivity("Usage with RecyclerView", RecyclerViewActivity.class); 82 | 83 | break; 84 | case 1: 85 | activityHolder.addActivity("PhotoView", PhotoViewActivity.class); 86 | activityHolder.addActivity("SubsamplingScaleImageView", SubsamplingActvity.class); 87 | activityHolder.addActivity("GifImageView & GifDrawable", GifImageViewActivity.class); 88 | break; 89 | case 2: 90 | break; 91 | } 92 | 93 | adapter.notifyDataSetChanged(); 94 | 95 | 96 | return view; 97 | } 98 | 99 | public class MyAdapter extends RecyclerView.Adapter{ 100 | 101 | @Override 102 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 103 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_samplelist_recycleview, parent, false); 104 | ViewHolder vh = new ViewHolder(v); 105 | return vh; 106 | } 107 | 108 | @Override 109 | public void onBindViewHolder(ViewHolder holder, final int position) { 110 | holder.textView.setText(activityHolder.getNameList().get(position)); 111 | holder.itemView.setOnClickListener(new View.OnClickListener() { 112 | @Override 113 | public void onClick(View v) { 114 | activityHolder.startActivity(v.getContext(),position); 115 | } 116 | }); 117 | } 118 | 119 | @Override 120 | public int getItemCount() { 121 | return activityHolder.getNameList().size(); 122 | } 123 | } 124 | 125 | public class ViewHolder extends RecyclerView.ViewHolder{ 126 | public TextView textView; 127 | public ViewHolder(View itemView) { 128 | super(itemView); 129 | textView = (TextView) itemView.findViewById(R.id.tv_item_samplelist_recyclerview); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/samplelist/SnippetFragment.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.samplelist; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import me.kaede.frescosample.R; 17 | import me.kaede.frescosample.snippet.SnippetActivity; 18 | 19 | /** 20 | * Created by kaede on 2015/10/23. 21 | */ 22 | public class SnippetFragment extends Fragment{ 23 | 24 | List datas = new ArrayList<>(); 25 | 26 | public static SnippetFragment newInstance() { 27 | SnippetFragment fragment = new SnippetFragment(); 28 | return fragment; 29 | } 30 | 31 | 32 | @Override 33 | public void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | } 36 | 37 | @Override 38 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 39 | Bundle savedInstanceState) { 40 | View view = inflater.inflate(R.layout.fragment_recyclerview, container, false); 41 | 42 | 43 | //find view 44 | RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); 45 | 46 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); 47 | recyclerView.setLayoutManager(linearLayoutManager); 48 | MyAdapter adapter = new MyAdapter(); 49 | recyclerView.setAdapter(adapter); 50 | recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL_LIST)); 51 | datas.add(new CodeSnippet("Load an image simply", "loadanimage.md")); 52 | datas.add(new CodeSnippet("Load an image in detail", "loadanimageindetail.md")); 53 | datas.add(new CodeSnippet("XML Attributes","xmlattributes.md")); 54 | datas.add(new CodeSnippet("DickCache Setting","diskcachesetting.md")); 55 | adapter.notifyDataSetChanged(); 56 | return view; 57 | } 58 | 59 | public class MyAdapter extends RecyclerView.Adapter{ 60 | 61 | @Override 62 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 63 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_samplelist_recycleview, parent, false); 64 | ViewHolder vh = new ViewHolder(v); 65 | return vh; 66 | } 67 | 68 | @Override 69 | public void onBindViewHolder(ViewHolder holder, final int position) { 70 | holder.textView.setText(datas.get(position).name); 71 | holder.itemView.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | Intent intent = new Intent(getContext(),SnippetActivity.class); 75 | intent.putExtra(SnippetActivity.EXTRA_FILE,datas.get(position).file); 76 | getContext().startActivity(intent); 77 | } 78 | }); 79 | } 80 | 81 | @Override 82 | public int getItemCount() { 83 | return datas.size(); 84 | } 85 | } 86 | 87 | public class ViewHolder extends RecyclerView.ViewHolder{ 88 | public TextView textView; 89 | public ViewHolder(View itemView) { 90 | super(itemView); 91 | textView = (TextView) itemView.findViewById(R.id.tv_item_samplelist_recyclerview); 92 | } 93 | } 94 | 95 | public class CodeSnippet{ 96 | String name; 97 | String file; 98 | 99 | public CodeSnippet(String name, String file) { 100 | this.name = name; 101 | this.file = file; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/snippet/SnippetActivity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.snippet; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import me.kaede.frescosample.R; 7 | import me.kaede.widget.markdownview.MarkdownView; 8 | 9 | public class SnippetActivity extends AppCompatActivity { 10 | 11 | public static final String EXTRA_FILE = "EXTRA_FILE"; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_snippet); 17 | String file = getIntent().getStringExtra(EXTRA_FILE); 18 | if (file!=null&&file.length()>0){ 19 | MarkdownView markdownView = (MarkdownView) this.findViewById(R.id.markdownview); 20 | markdownView.loadMarkdownFile("file:///android_asset/"+file); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/frescosample/subsampling/SubsamplingActvity.java: -------------------------------------------------------------------------------- 1 | package me.kaede.frescosample.subsampling; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import me.kaede.frescosample.ImageApi; 7 | import me.kaede.frescosample.R; 8 | import me.kaede.util.fresco.subscaleview.SubsamplingScaleImageView; 9 | 10 | public class SubsamplingActvity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_subsampling_actvity); 16 | 17 | SubsamplingScaleImageView subsamplingScaleImageView = (SubsamplingScaleImageView) this.findViewById(R.id.scaleimageview); 18 | subsamplingScaleImageView.setImageUri(ImageApi.other.getUrlByName("longimage", ".jpg")); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/ImageHolder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util; 2 | 3 | import android.util.Log; 4 | 5 | import java.text.DecimalFormat; 6 | import java.text.NumberFormat; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Created by kaede on 2015/10/21. 14 | * sample url : http://gh.kaedea.com/fresco-sample-usage/assets/image/girly/jk-00.jpg 15 | */ 16 | public class ImageHolder { 17 | String domain; 18 | String baseDir; 19 | String categroy; 20 | String prefix; 21 | String extension = ".jpg"; 22 | int maxIndex = Integer.MAX_VALUE; 23 | String indexFormat = "00"; 24 | 25 | DecimalFormat formatter; 26 | 27 | public ImageHolder(String domain) { 28 | this.domain = domain; 29 | init(); 30 | 31 | } 32 | 33 | public ImageHolder(String domain, String baseDir, String categroy, String prefix, String extension, int maxIndex, String indexFormat) { 34 | this.domain = domain; 35 | this.baseDir = baseDir; 36 | this.categroy = categroy; 37 | this.prefix = prefix; 38 | this.extension = extension; 39 | this.maxIndex = maxIndex; 40 | this.indexFormat = indexFormat; 41 | init(); 42 | } 43 | 44 | private void init(){ 45 | formatter = new DecimalFormat(indexFormat); 46 | } 47 | 48 | public String getUrl(int index){ 49 | if (index>maxIndex)return null; 50 | if (domain==null)return null; 51 | StringBuilder sb = new StringBuilder(domain); 52 | if (baseDir!=null) sb.append("/").append(baseDir); 53 | if (categroy!=null) sb.append("/").append(categroy); 54 | if (prefix!=null) sb.append("/").append(prefix);else sb.append("/"); 55 | String url = sb.append(formatter.format(index)).append(extension).toString(); 56 | Log.i("ImageHolder","[getUrl] url = "+url); 57 | return url; 58 | } 59 | 60 | public List getUrls(){ 61 | List urls = new ArrayList<>(); 62 | if (maxIndex == Integer.MAX_VALUE) return urls; 63 | for (int i = 0; i<= maxIndex; i++){ 64 | urls.add(getUrl(i)); 65 | } 66 | return urls; 67 | } 68 | 69 | public String getUrlByName(String name){ 70 | if (name==null||name.length()<=0)return null; 71 | if (domain==null)return null; 72 | StringBuilder sb = new StringBuilder(domain); 73 | if (baseDir!=null) sb.append("/").append(baseDir); 74 | if (categroy!=null) sb.append("/").append(categroy); 75 | if (prefix!=null) sb.append("/").append(prefix);else sb.append("/"); 76 | String url = sb.append(name).append(extension).toString(); 77 | Log.i("ImageHolder", "[getUrlByName] url = " + url); 78 | return url; 79 | } 80 | 81 | public String getUrlByName(String name,String extension){ 82 | if (name==null||name.length()<=0)return null; 83 | if (extension==null||extension.length()<=0)return null; 84 | if (domain==null)return null; 85 | StringBuilder sb = new StringBuilder(domain); 86 | if (baseDir!=null) sb.append("/").append(baseDir); 87 | if (categroy!=null) sb.append("/").append(categroy); 88 | if (prefix!=null) sb.append("/").append(prefix);else sb.append("/"); 89 | String url = sb.append(name).append(extension).toString(); 90 | Log.i("ImageHolder","[getUrlByName] url = "+url); 91 | return url; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/AndroidUtils.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * Created by 06peng on 15/6/26. 9 | */ 10 | public class AndroidUtils { 11 | 12 | private static int width = 0; 13 | private static int height = 0; 14 | 15 | private static void getDisplay(Context context) { 16 | if (width <= 0 || height <= 0) { 17 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 18 | DisplayMetrics dm = new DisplayMetrics(); 19 | wm.getDefaultDisplay().getMetrics(dm); 20 | width = dm.widthPixels; 21 | height = dm.heightPixels; 22 | } 23 | } 24 | 25 | public static int getScreenWidth(Context context) { 26 | getDisplay(context); 27 | return width; 28 | } 29 | 30 | public static int getScreenHeight(Context context) { 31 | getDisplay(context); 32 | return height; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/CustomProgressDrawable.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.ColorFilter; 5 | import android.graphics.drawable.Drawable; 6 | 7 | /** 8 | * Created by 06peng on 15/6/26. 9 | * edited kaede 10 | */ 11 | public class CustomProgressDrawable extends Drawable { 12 | 13 | private ImageDownloadListener mListener; 14 | 15 | public CustomProgressDrawable(ImageDownloadListener listener) { 16 | mListener = listener; 17 | } 18 | 19 | @Override 20 | public void draw(Canvas canvas) { 21 | 22 | } 23 | 24 | @Override 25 | public void setAlpha(int alpha) { 26 | 27 | } 28 | 29 | @Override 30 | public void setColorFilter(ColorFilter cf) { 31 | 32 | } 33 | 34 | @Override 35 | public int getOpacity() { 36 | return 0; 37 | } 38 | 39 | @Override 40 | protected boolean onLevelChange(int level) { 41 | int progress = (int) ((level / 10000.0) * 100); 42 | if (mListener != null) { 43 | mListener.onUpdate(progress); 44 | } 45 | return super.onLevelChange(level); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/CustomProgressbarDrawable.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.ColorFilter; 5 | import com.facebook.drawee.drawable.ProgressBarDrawable; 6 | 7 | /** 8 | * Created by kaede on 2015/10/23. 9 | */ 10 | public class CustomProgressbarDrawable extends ProgressBarDrawable { 11 | 12 | private ImageDownloadListener mListener; 13 | 14 | public CustomProgressbarDrawable(ImageDownloadListener listener) { 15 | mListener = listener; 16 | } 17 | 18 | @Override 19 | protected boolean onLevelChange(int level) { 20 | int progress = (int) ((level / 10000.0) * 100); 21 | if (mListener != null) { 22 | mListener.onUpdate(progress); 23 | } 24 | return super.onLevelChange(level); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/ImageDownloadListener.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco; 2 | 3 | /** 4 | * Created by 06peng on 15/6/26. 5 | */ 6 | public interface ImageDownloadListener { 7 | void onUpdate(int progress); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/cache/FileCache.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.cache; 2 | 3 | /** 4 | * Created by 06peng on 2015-07-03. 5 | */ 6 | 7 | import android.content.Context; 8 | 9 | import java.io.File; 10 | 11 | public class FileCache { 12 | 13 | private File cacheDir; 14 | 15 | public FileCache(Context context) { 16 | //Find the dir to save cached images 17 | if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { 18 | cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), "fresco_cache"); 19 | } else { 20 | cacheDir = context.getCacheDir(); 21 | } 22 | if (!cacheDir.exists()) { 23 | cacheDir.mkdirs(); 24 | } 25 | } 26 | 27 | public File getCacheDir() { 28 | return cacheDir; 29 | } 30 | 31 | public File getFile(String url) { 32 | String filename = String.valueOf(url.hashCode()); 33 | File f = new File(cacheDir, filename); 34 | if (f.exists()) { 35 | return f; 36 | } 37 | return null; 38 | } 39 | 40 | public void clear() { 41 | File[] files = cacheDir.listFiles(); 42 | if (files == null) { 43 | return; 44 | } 45 | for (File f : files) { 46 | f.delete(); 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/cache/FileUtils.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.cache; 2 | 3 | /** 4 | * Created by 06peng on 2015-07-03. 5 | */ 6 | 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | public class FileUtils { 11 | public static void CopyStream(InputStream is, OutputStream os) { 12 | final int buffer_size = 1024; 13 | try { 14 | byte[] bytes = new byte[buffer_size]; 15 | for (; ; ) { 16 | int count = is.read(bytes, 0, buffer_size); 17 | if (count == -1) 18 | break; 19 | os.write(bytes, 0, count); 20 | } 21 | } catch (Exception ex) { 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/gifimageview/CustomGifImageView.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.gifimageview; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Animatable; 5 | import android.graphics.drawable.Drawable; 6 | import android.net.Uri; 7 | import android.support.annotation.Nullable; 8 | import android.util.AttributeSet; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.widget.LinearLayout; 12 | 13 | import com.facebook.common.references.CloseableReference; 14 | import com.facebook.datasource.DataSource; 15 | import com.facebook.drawee.backends.pipeline.Fresco; 16 | import com.facebook.drawee.controller.BaseControllerListener; 17 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 18 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 19 | import com.facebook.drawee.interfaces.DraweeController; 20 | import com.facebook.drawee.view.DraweeHolder; 21 | import com.facebook.imagepipeline.core.ImagePipeline; 22 | import com.facebook.imagepipeline.image.ImageInfo; 23 | import com.facebook.imagepipeline.memory.PooledByteBuffer; 24 | import com.facebook.imagepipeline.memory.PooledByteBufferInputStream; 25 | import com.facebook.imagepipeline.request.ImageRequest; 26 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 27 | 28 | import java.io.BufferedInputStream; 29 | import java.io.IOException; 30 | 31 | import me.kaede.frescosample.R; 32 | import me.kaede.util.fresco.CustomProgressbarDrawable; 33 | import me.kaede.util.fresco.ImageDownloadListener; 34 | import pl.droidsonroids.gif.GifDrawable; 35 | import pl.droidsonroids.gif.GifImageView; 36 | 37 | /** 38 | * Created by 06peng on 15/6/28. 39 | */ 40 | public class CustomGifImageView extends LinearLayout implements ImageDownloadListener { 41 | 42 | DraweeHolder mDraweeHolder; 43 | ImageDownloadListener imageDownloadListener; 44 | private CloseableReference bytes; 45 | private GifDrawable mGifDrawable; 46 | private GifImageView mGifView; 47 | 48 | public CustomGifImageView(Context context) { 49 | super(context); 50 | init(context); 51 | } 52 | 53 | public CustomGifImageView(Context context, AttributeSet attrs) { 54 | super(context, attrs); 55 | init(context); 56 | } 57 | 58 | public CustomGifImageView(Context context, AttributeSet attrs, int defStyleAttr) { 59 | super(context, attrs, defStyleAttr); 60 | init(context); 61 | } 62 | 63 | private void init(Context context) { 64 | View layout = LayoutInflater.from(context).inflate(R.layout.layout_gifimageview, null); 65 | setOrientation(LinearLayout.VERTICAL); 66 | LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 67 | addView(layout, layoutParams); 68 | mGifView = (GifImageView) findViewById(R.id.gifview); 69 | 70 | if (mDraweeHolder == null) { 71 | GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(getResources()) 72 | .setProgressBarImage(new CustomProgressbarDrawable(this)).build(); 73 | mDraweeHolder = DraweeHolder.create(hierarchy, getContext()); 74 | } 75 | } 76 | 77 | public void setImageUrl(String url) { 78 | ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)).build(); 79 | ImagePipeline imagePipeline = Fresco.getImagePipeline(); 80 | final DataSource> dataSource = imagePipeline.fetchEncodedImage(imageRequest, this); 81 | DraweeController controller = Fresco.newDraweeControllerBuilder() 82 | .setOldController(mDraweeHolder.getController()) 83 | .setImageRequest(imageRequest) 84 | .setControllerListener(new BaseControllerListener() { 85 | @Override 86 | public void onFinalImageSet(String s, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) { 87 | try { 88 | if (bytes == null) { 89 | bytes = dataSource.getResult(); 90 | } 91 | if (bytes != null) { 92 | PooledByteBuffer pooledByteBuffer = bytes.get(); 93 | PooledByteBufferInputStream sourceIs = new PooledByteBufferInputStream(pooledByteBuffer); 94 | BufferedInputStream bis = new BufferedInputStream(sourceIs); 95 | mGifDrawable = new GifDrawable(bis); 96 | mGifView.setImageDrawable(mGifDrawable); 97 | mGifView.setVisibility(View.VISIBLE); 98 | 99 | //mProgressTextView.setVisibility(View.INVISIBLE); 100 | } 101 | } catch (IOException e) { 102 | e.printStackTrace(); 103 | } finally { 104 | dataSource.close(); 105 | CloseableReference.closeSafely(bytes); 106 | } 107 | } 108 | }) 109 | .setTapToRetryEnabled(true) 110 | .build(); 111 | mDraweeHolder.setController(controller); 112 | } 113 | 114 | @Override 115 | protected void onDetachedFromWindow() { 116 | mDraweeHolder.onDetach(); 117 | close(); 118 | super.onDetachedFromWindow(); 119 | } 120 | 121 | @Override 122 | protected void onAttachedToWindow() { 123 | init(getContext()); 124 | mDraweeHolder.onAttach(); 125 | super.onAttachedToWindow(); 126 | } 127 | 128 | @Override 129 | protected boolean verifyDrawable(Drawable dr) { 130 | if (dr == mDraweeHolder.getHierarchy().getTopLevelDrawable()) { 131 | return true; 132 | } 133 | return super.verifyDrawable(dr); 134 | } 135 | 136 | @Override 137 | public void onStartTemporaryDetach() { 138 | super.onStartTemporaryDetach(); 139 | mDraweeHolder.onDetach(); 140 | } 141 | 142 | @Override 143 | public void onFinishTemporaryDetach() { 144 | super.onFinishTemporaryDetach(); 145 | mDraweeHolder.onAttach(); 146 | } 147 | 148 | public void setImageDownloadListener(ImageDownloadListener imageDownloadListener) { 149 | this.imageDownloadListener = imageDownloadListener; 150 | } 151 | 152 | @Override 153 | public void onUpdate(int progress) { 154 | if (imageDownloadListener !=null){ 155 | imageDownloadListener.onUpdate(progress); 156 | } 157 | } 158 | 159 | private void close() { 160 | try { 161 | if (mGifDrawable != null && !mGifDrawable.isRecycled()) { 162 | mGifDrawable.recycle(); 163 | } 164 | } catch (Exception e) { 165 | e.printStackTrace(); 166 | } 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/Compat.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview; 17 | 18 | import android.annotation.TargetApi; 19 | import android.os.Build; 20 | import android.os.Build.VERSION; 21 | import android.os.Build.VERSION_CODES; 22 | import android.view.MotionEvent; 23 | import android.view.View; 24 | 25 | public class Compat { 26 | 27 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60; 28 | 29 | public static void postOnAnimation(View view, Runnable runnable) { 30 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { 31 | postOnAnimationJellyBean(view, runnable); 32 | } else { 33 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL); 34 | } 35 | } 36 | 37 | @TargetApi(16) 38 | private static void postOnAnimationJellyBean(View view, Runnable runnable) { 39 | view.postOnAnimation(runnable); 40 | } 41 | 42 | public static int getPointerIndex(int action) { 43 | if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) 44 | return getPointerIndexHoneyComb(action); 45 | else 46 | return getPointerIndexEclair(action); 47 | } 48 | 49 | @SuppressWarnings("deprecation") 50 | @TargetApi(VERSION_CODES.ECLAIR) 51 | private static int getPointerIndexEclair(int action) { 52 | return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; 53 | } 54 | 55 | @TargetApi(VERSION_CODES.HONEYCOMB) 56 | private static int getPointerIndexHoneyComb(int action) { 57 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/DefaultOnDoubleTapListener.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.photoview; 2 | 3 | import android.graphics.RectF; 4 | import android.view.GestureDetector; 5 | import android.view.MotionEvent; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Provided default implementation of GestureDetector.OnDoubleTapListener, to be overriden with custom behavior, if needed 10 | *

 

11 | * To be used via {@link PhotoViewAttacher#setOnDoubleTapListener(GestureDetector.OnDoubleTapListener)} 12 | */ 13 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener { 14 | 15 | private PhotoViewAttacher photoViewAttacher; 16 | 17 | /** 18 | * Default constructor 19 | * 20 | * @param photoViewAttacher PhotoViewAttacher to bind to 21 | */ 22 | public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) { 23 | setPhotoViewAttacher(photoViewAttacher); 24 | } 25 | 26 | /** 27 | * Allows to change PhotoViewAttacher within range of single instance 28 | * 29 | * @param newPhotoViewAttacher PhotoViewAttacher to bind to 30 | */ 31 | public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) { 32 | this.photoViewAttacher = newPhotoViewAttacher; 33 | } 34 | 35 | @Override 36 | public boolean onSingleTapConfirmed(MotionEvent e) { 37 | if (this.photoViewAttacher == null) 38 | return false; 39 | 40 | ImageView imageView = photoViewAttacher.getImageView(); 41 | 42 | if (null != photoViewAttacher.getOnPhotoTapListener()) { 43 | final RectF displayRect = photoViewAttacher.getDisplayRect(); 44 | 45 | if (null != displayRect) { 46 | final float x = e.getX(), y = e.getY(); 47 | 48 | // Check to see if the user tapped on the photo 49 | if (displayRect.contains(x, y)) { 50 | 51 | float xResult = (x - displayRect.left) 52 | / displayRect.width(); 53 | float yResult = (y - displayRect.top) 54 | / displayRect.height(); 55 | 56 | photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult); 57 | return true; 58 | } 59 | } 60 | } 61 | if (null != photoViewAttacher.getOnViewTapListener()) { 62 | photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY()); 63 | } 64 | 65 | return false; 66 | } 67 | 68 | @Override 69 | public boolean onDoubleTap(MotionEvent ev) { 70 | if (photoViewAttacher == null) 71 | return false; 72 | 73 | try { 74 | float scale = photoViewAttacher.getScale(); 75 | float x = ev.getX(); 76 | float y = ev.getY(); 77 | 78 | if (scale < photoViewAttacher.getMediumScale()) { 79 | photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true); 80 | } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) { 81 | photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true); 82 | } else { 83 | photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true); 84 | } 85 | } catch (ArrayIndexOutOfBoundsException e) { 86 | // Can sometimes happen when getX() and getY() is called 87 | } 88 | 89 | return true; 90 | } 91 | 92 | @Override 93 | public boolean onDoubleTapEvent(MotionEvent e) { 94 | // Wait for the confirmed onDoubleTap() instead 95 | return false; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/HackyViewPager.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.photoview; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | 8 | /** 9 | * Found at http://stackoverflow.com/questions/7814017/is-it-possible-to-disable-scrolling-on-a-viewpager. 10 | * Convenient way to temporarily disable ViewPager navigation while interacting with ImageView. 11 | * 12 | * Julia Zudikova 13 | */ 14 | 15 | /** 16 | * Hacky fix for Issue #4 and 17 | * http://code.google.com/p/android/issues/detail?id=18990 18 | *

19 | * ScaleGestureDetector seems to mess up the touch events, which means that 20 | * ViewGroups which make use of onInterceptTouchEvent throw a lot of 21 | * IllegalArgumentException: pointerIndex out of range. 22 | *

23 | * There's not much I can do in my code for now, but we can mask the result by 24 | * just catching the problem and ignoring it. 25 | * 26 | * @author Chris Banes 27 | */ 28 | public class HackyViewPager extends ViewPager { 29 | 30 | private boolean isLocked; 31 | 32 | public HackyViewPager(Context context) { 33 | super(context); 34 | isLocked = false; 35 | } 36 | 37 | public HackyViewPager(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | isLocked = false; 40 | } 41 | 42 | @Override 43 | public boolean onInterceptTouchEvent(MotionEvent ev) { 44 | if (!isLocked) { 45 | try { 46 | return super.onInterceptTouchEvent(ev); 47 | } catch (IllegalArgumentException e) { 48 | return false; 49 | } 50 | } 51 | return false; 52 | } 53 | 54 | @Override 55 | public boolean onTouchEvent(MotionEvent event) { 56 | return !isLocked && super.onTouchEvent(event); 57 | } 58 | 59 | public void toggleLock() { 60 | isLocked = !isLocked; 61 | } 62 | 63 | public void setLocked(boolean isLocked) { 64 | this.isLocked = isLocked; 65 | } 66 | 67 | public boolean isLocked() { 68 | return isLocked; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/IPhotoView.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview; 17 | 18 | import android.graphics.Bitmap; 19 | import android.graphics.Matrix; 20 | import android.graphics.RectF; 21 | import android.view.GestureDetector; 22 | import android.view.View; 23 | import android.widget.ImageView; 24 | 25 | 26 | public interface IPhotoView { 27 | 28 | public static final float DEFAULT_MAX_SCALE = 3.0f; 29 | public static final float DEFAULT_MID_SCALE = 1.75f; 30 | public static final float DEFAULT_MIN_SCALE = 1.0f; 31 | public static final int DEFAULT_ZOOM_DURATION = 200; 32 | 33 | /** 34 | * Returns true if the PhotoView is set to allow zooming of Photos. 35 | * 36 | * @return true if the PhotoView allows zooming. 37 | */ 38 | boolean canZoom(); 39 | 40 | /** 41 | * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to 42 | * this View and includes all scaling and translations. 43 | * 44 | * @return - RectF of Displayed Drawable 45 | */ 46 | RectF getDisplayRect(); 47 | 48 | /** 49 | * Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered 50 | * relative to this View and includes all scaling and translations. 51 | * 52 | * @param finalMatrix target matrix to set PhotoView to 53 | * @return - true if rectangle was applied successfully 54 | */ 55 | boolean setDisplayMatrix(Matrix finalMatrix); 56 | 57 | /** 58 | * Gets the Display Matrix of the currently displayed Drawable. The Rectangle is considered 59 | * relative to this View and includes all scaling and translations. 60 | * 61 | * @return - true if rectangle was applied successfully 62 | */ 63 | Matrix getDisplayMatrix(); 64 | 65 | /** 66 | * Use {@link #getMinimumScale()} instead, this will be removed in future release 67 | * 68 | * @return The current minimum scale level. What this value represents depends on the current 69 | * {@link ImageView.ScaleType}. 70 | */ 71 | @Deprecated 72 | float getMinScale(); 73 | 74 | /** 75 | * @return The current minimum scale level. What this value represents depends on the current 76 | * {@link ImageView.ScaleType}. 77 | */ 78 | float getMinimumScale(); 79 | 80 | /** 81 | * Use {@link #getMediumScale()} instead, this will be removed in future release 82 | * 83 | * @return The current middle scale level. What this value represents depends on the current 84 | * {@link ImageView.ScaleType}. 85 | */ 86 | @Deprecated 87 | float getMidScale(); 88 | 89 | /** 90 | * @return The current medium scale level. What this value represents depends on the current 91 | * {@link ImageView.ScaleType}. 92 | */ 93 | float getMediumScale(); 94 | 95 | /** 96 | * Use {@link #getMaximumScale()} instead, this will be removed in future release 97 | * 98 | * @return The current maximum scale level. What this value represents depends on the current 99 | * {@link ImageView.ScaleType}. 100 | */ 101 | @Deprecated 102 | float getMaxScale(); 103 | 104 | /** 105 | * @return The current maximum scale level. What this value represents depends on the current 106 | * {@link ImageView.ScaleType}. 107 | */ 108 | float getMaximumScale(); 109 | 110 | /** 111 | * Returns the current scale value 112 | * 113 | * @return float - current scale value 114 | */ 115 | float getScale(); 116 | 117 | /** 118 | * Return the current scale type in use by the ImageView. 119 | * 120 | * @return current ImageView.ScaleType 121 | */ 122 | ImageView.ScaleType getScaleType(); 123 | 124 | /** 125 | * Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll 126 | * to it's horizontal edge. 127 | * 128 | * @param allow whether to allow intercepting by parent element or not 129 | */ 130 | void setAllowParentInterceptOnEdge(boolean allow); 131 | 132 | /** 133 | * Use {@link #setMinimumScale(float minimumScale)} instead, this will be removed in future 134 | * release 135 | *

 

136 | * Sets the minimum scale level. What this value represents depends on the current {@link 137 | * ImageView.ScaleType}. 138 | * 139 | * @param minScale minimum allowed scale 140 | */ 141 | @Deprecated 142 | void setMinScale(float minScale); 143 | 144 | /** 145 | * Sets the minimum scale level. What this value represents depends on the current {@link 146 | * ImageView.ScaleType}. 147 | * 148 | * @param minimumScale minimum allowed scale 149 | */ 150 | void setMinimumScale(float minimumScale); 151 | 152 | /** 153 | * Use {@link #setMediumScale(float mediumScale)} instead, this will be removed in future 154 | * release 155 | *

 

156 | * Sets the middle scale level. What this value represents depends on the current {@link 157 | * ImageView.ScaleType}. 158 | * 159 | * @param midScale medium scale preset 160 | */ 161 | @Deprecated 162 | void setMidScale(float midScale); 163 | 164 | /* 165 | * Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}. 166 | * 167 | * @param mediumScale medium scale preset 168 | */ 169 | void setMediumScale(float mediumScale); 170 | 171 | /** 172 | * Use {@link #setMaximumScale(float maximumScale)} instead, this will be removed in future 173 | * release 174 | *

 

175 | * Sets the maximum scale level. What this value represents depends on the current {@link 176 | * ImageView.ScaleType}. 177 | * 178 | * @param maxScale maximum allowed scale preset 179 | */ 180 | @Deprecated 181 | void setMaxScale(float maxScale); 182 | 183 | /** 184 | * Sets the maximum scale level. What this value represents depends on the current {@link 185 | * ImageView.ScaleType}. 186 | * 187 | * @param maximumScale maximum allowed scale preset 188 | */ 189 | void setMaximumScale(float maximumScale); 190 | 191 | /** 192 | * Allows to set all three scale levels at once, so you don't run into problem with setting 193 | * medium/minimum scale before the maximum one 194 | * 195 | * @param minimumScale minimum allowed scale 196 | * @param mediumScale medium allowed scale 197 | * @param maximumScale maximum allowed scale preset 198 | */ 199 | void setScaleLevels(float minimumScale, float mediumScale, float maximumScale); 200 | 201 | /** 202 | * Register a callback to be invoked when the Photo displayed by this view is long-pressed. 203 | * 204 | * @param listener - Listener to be registered. 205 | */ 206 | void setOnLongClickListener(View.OnLongClickListener listener); 207 | 208 | /** 209 | * Register a callback to be invoked when the Matrix has changed for this View. An example would 210 | * be the user panning or scaling the Photo. 211 | * 212 | * @param listener - Listener to be registered. 213 | */ 214 | void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener); 215 | 216 | /** 217 | * Register a callback to be invoked when the Photo displayed by this View is tapped with a 218 | * single tap. 219 | * 220 | * @param listener - Listener to be registered. 221 | */ 222 | void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener); 223 | 224 | /** 225 | * Returns a listener to be invoked when the Photo displayed by this View is tapped with a 226 | * single tap. 227 | * 228 | * @return PhotoViewAttacher.OnPhotoTapListener currently set, may be null 229 | */ 230 | PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener(); 231 | 232 | /** 233 | * Register a callback to be invoked when the View is tapped with a single tap. 234 | * 235 | * @param listener - Listener to be registered. 236 | */ 237 | void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener); 238 | 239 | /** 240 | * Enables rotation via PhotoView internal functions. 241 | * 242 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360 243 | */ 244 | void setRotationTo(float rotationDegree); 245 | 246 | /** 247 | * Enables rotation via PhotoView internal functions. 248 | * 249 | * @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360 250 | */ 251 | void setRotationBy(float rotationDegree); 252 | 253 | /** 254 | * Returns a callback listener to be invoked when the View is tapped with a single tap. 255 | * 256 | * @return PhotoViewAttacher.OnViewTapListener currently set, may be null 257 | */ 258 | PhotoViewAttacher.OnViewTapListener getOnViewTapListener(); 259 | 260 | /** 261 | * Changes the current scale to the specified value. 262 | * 263 | * @param scale - Value to scale to 264 | */ 265 | void setScale(float scale); 266 | 267 | /** 268 | * Changes the current scale to the specified value. 269 | * 270 | * @param scale - Value to scale to 271 | * @param animate - Whether to animate the scale 272 | */ 273 | void setScale(float scale, boolean animate); 274 | 275 | /** 276 | * Changes the current scale to the specified value, around the given focal point. 277 | * 278 | * @param scale - Value to scale to 279 | * @param focalX - X Focus Point 280 | * @param focalY - Y Focus Point 281 | * @param animate - Whether to animate the scale 282 | */ 283 | void setScale(float scale, float focalX, float focalY, boolean animate); 284 | 285 | /** 286 | * Controls how the image should be resized or moved to match the size of the ImageView. Any 287 | * scaling or panning will happen within the confines of this {@link 288 | * ImageView.ScaleType}. 289 | * 290 | * @param scaleType - The desired scaling mode. 291 | */ 292 | void setScaleType(ImageView.ScaleType scaleType); 293 | 294 | /** 295 | * Allows you to enable/disable the zoom functionality on the ImageView. When disable the 296 | * ImageView reverts to using the FIT_CENTER matrix. 297 | * 298 | * @param zoomable - Whether the zoom functionality is enabled. 299 | */ 300 | void setZoomable(boolean zoomable); 301 | 302 | /** 303 | * Enables rotation via PhotoView internal functions. Name is chosen so it won't collide with 304 | * View.setRotation(float) in API since 11 305 | * 306 | * @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360 307 | * @deprecated use {@link #setRotationTo(float)} 308 | */ 309 | void setPhotoViewRotation(float rotationDegree); 310 | 311 | /** 312 | * Extracts currently visible area to Bitmap object, if there is no image loaded yet or the 313 | * ImageView is already destroyed, returns {@code null} 314 | * 315 | * @return currently visible area as bitmap or null 316 | */ 317 | Bitmap getVisibleRectangleBitmap(); 318 | 319 | /** 320 | * Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION). 321 | * Will default to 200 if provided negative value 322 | * 323 | * @param milliseconds duration of zoom interpolation 324 | */ 325 | void setZoomTransitionDuration(int milliseconds); 326 | 327 | /** 328 | * Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better 329 | * integration 330 | * 331 | * @return IPhotoView implementation instance if available, null if not 332 | */ 333 | IPhotoView getIPhotoViewImplementation(); 334 | 335 | /** 336 | * Sets custom double tap listener, to intercept default given functions. To reset behavior to 337 | * default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener 338 | * 339 | * @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView 340 | */ 341 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener); 342 | 343 | /** 344 | * Will report back about scale changes 345 | * 346 | * @param onScaleChangeListener OnScaleChangeListener instance 347 | */ 348 | void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener); 349 | } 350 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/CupcakeGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.gestures; 17 | 18 | import android.content.Context; 19 | import android.view.MotionEvent; 20 | import android.view.VelocityTracker; 21 | import android.view.ViewConfiguration; 22 | 23 | import me.kaede.util.fresco.photoview.log.LogManager; 24 | 25 | public class CupcakeGestureDetector implements GestureDetector { 26 | 27 | protected OnGestureListener mListener; 28 | private static final String LOG_TAG = "CupcakeGestureDetector"; 29 | float mLastTouchX; 30 | float mLastTouchY; 31 | final float mTouchSlop; 32 | final float mMinimumVelocity; 33 | 34 | @Override 35 | public void setOnGestureListener(OnGestureListener listener) { 36 | this.mListener = listener; 37 | } 38 | 39 | public CupcakeGestureDetector(Context context) { 40 | final ViewConfiguration configuration = ViewConfiguration 41 | .get(context); 42 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 43 | mTouchSlop = configuration.getScaledTouchSlop(); 44 | } 45 | 46 | private VelocityTracker mVelocityTracker; 47 | private boolean mIsDragging; 48 | 49 | float getActiveX(MotionEvent ev) { 50 | return ev.getX(); 51 | } 52 | 53 | float getActiveY(MotionEvent ev) { 54 | return ev.getY(); 55 | } 56 | 57 | public boolean isScaling() { 58 | return false; 59 | } 60 | 61 | public boolean isDragging() { 62 | return mIsDragging; 63 | } 64 | 65 | @Override 66 | public boolean onTouchEvent(MotionEvent ev) { 67 | switch (ev.getAction()) { 68 | case MotionEvent.ACTION_DOWN: { 69 | mVelocityTracker = VelocityTracker.obtain(); 70 | if (null != mVelocityTracker) { 71 | mVelocityTracker.addMovement(ev); 72 | } else { 73 | LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null"); 74 | } 75 | 76 | mLastTouchX = getActiveX(ev); 77 | mLastTouchY = getActiveY(ev); 78 | mIsDragging = false; 79 | break; 80 | } 81 | 82 | case MotionEvent.ACTION_MOVE: { 83 | final float x = getActiveX(ev); 84 | final float y = getActiveY(ev); 85 | final float dx = x - mLastTouchX, dy = y - mLastTouchY; 86 | 87 | if (!mIsDragging) { 88 | // Use Pythagoras to see if drag length is larger than 89 | // touch slop 90 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; 91 | } 92 | 93 | if (mIsDragging) { 94 | mListener.onDrag(dx, dy); 95 | mLastTouchX = x; 96 | mLastTouchY = y; 97 | 98 | if (null != mVelocityTracker) { 99 | mVelocityTracker.addMovement(ev); 100 | } 101 | } 102 | break; 103 | } 104 | 105 | case MotionEvent.ACTION_CANCEL: { 106 | // Recycle Velocity Tracker 107 | if (null != mVelocityTracker) { 108 | mVelocityTracker.recycle(); 109 | mVelocityTracker = null; 110 | } 111 | break; 112 | } 113 | 114 | case MotionEvent.ACTION_UP: { 115 | if (mIsDragging) { 116 | if (null != mVelocityTracker) { 117 | mLastTouchX = getActiveX(ev); 118 | mLastTouchY = getActiveY(ev); 119 | 120 | // Compute velocity within the last 1000ms 121 | mVelocityTracker.addMovement(ev); 122 | mVelocityTracker.computeCurrentVelocity(1000); 123 | 124 | final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker 125 | .getYVelocity(); 126 | 127 | // If the velocity is greater than minVelocity, call 128 | // listener 129 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { 130 | mListener.onFling(mLastTouchX, mLastTouchY, -vX, 131 | -vY); 132 | } 133 | } 134 | } 135 | 136 | // Recycle Velocity Tracker 137 | if (null != mVelocityTracker) { 138 | mVelocityTracker.recycle(); 139 | mVelocityTracker = null; 140 | } 141 | break; 142 | } 143 | } 144 | 145 | return true; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/EclairGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | 22 | import me.kaede.util.fresco.photoview.Compat; 23 | 24 | @TargetApi(5) 25 | public class EclairGestureDetector extends CupcakeGestureDetector { 26 | 27 | private static final int INVALID_POINTER_ID = -1; 28 | private int mActivePointerId = INVALID_POINTER_ID; 29 | private int mActivePointerIndex = 0; 30 | 31 | public EclairGestureDetector(Context context) { 32 | super(context); 33 | } 34 | 35 | @Override 36 | float getActiveX(MotionEvent ev) { 37 | try { 38 | return ev.getX(mActivePointerIndex); 39 | } catch (Exception e) { 40 | return ev.getX(); 41 | } 42 | } 43 | 44 | @Override 45 | float getActiveY(MotionEvent ev) { 46 | try { 47 | return ev.getY(mActivePointerIndex); 48 | } catch (Exception e) { 49 | return ev.getY(); 50 | } 51 | } 52 | 53 | @Override 54 | public boolean onTouchEvent(MotionEvent ev) { 55 | final int action = ev.getAction(); 56 | switch (action & MotionEvent.ACTION_MASK) { 57 | case MotionEvent.ACTION_DOWN: 58 | mActivePointerId = ev.getPointerId(0); 59 | break; 60 | case MotionEvent.ACTION_CANCEL: 61 | case MotionEvent.ACTION_UP: 62 | mActivePointerId = INVALID_POINTER_ID; 63 | break; 64 | case MotionEvent.ACTION_POINTER_UP: 65 | // Ignore deprecation, ACTION_POINTER_ID_MASK and 66 | // ACTION_POINTER_ID_SHIFT has same value and are deprecated 67 | // You can have either deprecation or lint target api warning 68 | final int pointerIndex = Compat.getPointerIndex(ev.getAction()); 69 | final int pointerId = ev.getPointerId(pointerIndex); 70 | if (pointerId == mActivePointerId) { 71 | // This was our active pointer going up. Choose a new 72 | // active pointer and adjust accordingly. 73 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 74 | mActivePointerId = ev.getPointerId(newPointerIndex); 75 | mLastTouchX = ev.getX(newPointerIndex); 76 | mLastTouchY = ev.getY(newPointerIndex); 77 | } 78 | break; 79 | } 80 | 81 | mActivePointerIndex = ev 82 | .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId 83 | : 0); 84 | return super.onTouchEvent(ev); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/FroyoGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | import android.view.ScaleGestureDetector; 22 | 23 | @TargetApi(8) 24 | public class FroyoGestureDetector extends EclairGestureDetector { 25 | 26 | protected final ScaleGestureDetector mDetector; 27 | 28 | public FroyoGestureDetector(Context context) { 29 | super(context); 30 | ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() { 31 | 32 | @Override 33 | public boolean onScale(ScaleGestureDetector detector) { 34 | float scaleFactor = detector.getScaleFactor(); 35 | 36 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) 37 | return false; 38 | 39 | mListener.onScale(scaleFactor, 40 | detector.getFocusX(), detector.getFocusY()); 41 | return true; 42 | } 43 | 44 | @Override 45 | public boolean onScaleBegin(ScaleGestureDetector detector) { 46 | return true; 47 | } 48 | 49 | @Override 50 | public void onScaleEnd(ScaleGestureDetector detector) { 51 | // NO-OP 52 | } 53 | }; 54 | mDetector = new ScaleGestureDetector(context, mScaleListener); 55 | } 56 | 57 | @Override 58 | public boolean isScaling() { 59 | return mDetector.isInProgress(); 60 | } 61 | 62 | @Override 63 | public boolean onTouchEvent(MotionEvent ev) { 64 | mDetector.onTouchEvent(ev); 65 | return super.onTouchEvent(ev); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/GestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.gestures; 17 | 18 | import android.view.MotionEvent; 19 | 20 | public interface GestureDetector { 21 | 22 | public boolean onTouchEvent(MotionEvent ev); 23 | 24 | public boolean isScaling(); 25 | 26 | public boolean isDragging(); 27 | 28 | public void setOnGestureListener(OnGestureListener listener); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/OnGestureListener.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.gestures; 17 | 18 | public interface OnGestureListener { 19 | 20 | public void onDrag(float dx, float dy); 21 | 22 | public void onFling(float startX, float startY, float velocityX, 23 | float velocityY); 24 | 25 | public void onScale(float scaleFactor, float focusX, float focusY); 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/gestures/VersionedGestureDetector.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.photoview.gestures; 2 | 3 | /******************************************************************************* 4 | * Copyright 2011, 2012 Chris Banes. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | *******************************************************************************/ 18 | 19 | import android.content.Context; 20 | import android.os.Build; 21 | 22 | public final class VersionedGestureDetector { 23 | 24 | public static GestureDetector newInstance(Context context, 25 | OnGestureListener listener) { 26 | final int sdkVersion = Build.VERSION.SDK_INT; 27 | GestureDetector detector; 28 | 29 | if (sdkVersion < Build.VERSION_CODES.ECLAIR) { 30 | detector = new CupcakeGestureDetector(context); 31 | } else if (sdkVersion < Build.VERSION_CODES.FROYO) { 32 | detector = new EclairGestureDetector(context); 33 | } else { 34 | detector = new FroyoGestureDetector(context); 35 | } 36 | 37 | detector.setOnGestureListener(listener); 38 | 39 | return detector; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/log/LogManager.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.log; 17 | 18 | import android.util.Log; 19 | 20 | /** 21 | * class that holds the {@link Logger} for this library, defaults to {@link LoggerDefault} to send logs to android {@link Log} 22 | */ 23 | public final class LogManager { 24 | 25 | private static Logger logger = new LoggerDefault(); 26 | 27 | public static void setLogger(Logger newLogger) { 28 | logger = newLogger; 29 | } 30 | 31 | public static Logger getLogger() { 32 | return logger; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/log/Logger.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.log; 17 | 18 | /** 19 | * interface for a logger class to replace the static calls to {@link android.util.Log} 20 | */ 21 | public interface Logger { 22 | /** 23 | * Send a {@link android.util.Log#VERBOSE} log message. 24 | * 25 | * @param tag Used to identify the source of a log message. It usually identifies 26 | * the class or activity where the log call occurs. 27 | * @param msg The message you would like logged. 28 | */ 29 | int v(String tag, String msg); 30 | 31 | /** 32 | * Send a {@link android.util.Log#VERBOSE} log message and log the exception. 33 | * 34 | * @param tag Used to identify the source of a log message. It usually identifies 35 | * the class or activity where the log call occurs. 36 | * @param msg The message you would like logged. 37 | * @param tr An exception to log 38 | */ 39 | int v(String tag, String msg, Throwable tr); 40 | 41 | /** 42 | * Send a {@link android.util.Log#DEBUG} log message. 43 | * 44 | * @param tag Used to identify the source of a log message. It usually identifies 45 | * the class or activity where the log call occurs. 46 | * @param msg The message you would like logged. 47 | */ 48 | int d(String tag, String msg); 49 | 50 | /** 51 | * Send a {@link android.util.Log#DEBUG} log message and log the exception. 52 | * 53 | * @param tag Used to identify the source of a log message. It usually identifies 54 | * the class or activity where the log call occurs. 55 | * @param msg The message you would like logged. 56 | * @param tr An exception to log 57 | */ 58 | int d(String tag, String msg, Throwable tr); 59 | 60 | /** 61 | * Send an {@link android.util.Log#INFO} log message. 62 | * 63 | * @param tag Used to identify the source of a log message. It usually identifies 64 | * the class or activity where the log call occurs. 65 | * @param msg The message you would like logged. 66 | */ 67 | int i(String tag, String msg); 68 | 69 | /** 70 | * Send a {@link android.util.Log#INFO} log message and log the exception. 71 | * 72 | * @param tag Used to identify the source of a log message. It usually identifies 73 | * the class or activity where the log call occurs. 74 | * @param msg The message you would like logged. 75 | * @param tr An exception to log 76 | */ 77 | int i(String tag, String msg, Throwable tr); 78 | 79 | /** 80 | * Send a {@link android.util.Log#WARN} log message. 81 | * 82 | * @param tag Used to identify the source of a log message. It usually identifies 83 | * the class or activity where the log call occurs. 84 | * @param msg The message you would like logged. 85 | */ 86 | int w(String tag, String msg); 87 | 88 | /** 89 | * Send a {@link android.util.Log#WARN} log message and log the exception. 90 | * 91 | * @param tag Used to identify the source of a log message. It usually identifies 92 | * the class or activity where the log call occurs. 93 | * @param msg The message you would like logged. 94 | * @param tr An exception to log 95 | */ 96 | int w(String tag, String msg, Throwable tr); 97 | 98 | /** 99 | * Send an {@link android.util.Log#ERROR} log message. 100 | * 101 | * @param tag Used to identify the source of a log message. It usually identifies 102 | * the class or activity where the log call occurs. 103 | * @param msg The message you would like logged. 104 | */ 105 | int e(String tag, String msg); 106 | 107 | /** 108 | * Send a {@link android.util.Log#ERROR} log message and log the exception. 109 | * 110 | * @param tag Used to identify the source of a log message. It usually identifies 111 | * the class or activity where the log call occurs. 112 | * @param msg The message you would like logged. 113 | * @param tr An exception to log 114 | */ 115 | int e(String tag, String msg, Throwable tr); 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/log/LoggerDefault.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.log; 17 | 18 | import android.util.Log; 19 | 20 | /** 21 | * Helper class to redirect {@link LogManager#logger} to {@link Log} 22 | */ 23 | public class LoggerDefault implements Logger { 24 | 25 | @Override 26 | public int v(String tag, String msg) { 27 | return Log.v(tag, msg); 28 | } 29 | 30 | @Override 31 | public int v(String tag, String msg, Throwable tr) { 32 | return Log.v(tag, msg, tr); 33 | } 34 | 35 | @Override 36 | public int d(String tag, String msg) { 37 | return Log.d(tag, msg); 38 | } 39 | 40 | @Override 41 | public int d(String tag, String msg, Throwable tr) { 42 | return Log.d(tag, msg, tr); 43 | } 44 | 45 | @Override 46 | public int i(String tag, String msg) { 47 | return Log.i(tag, msg); 48 | } 49 | 50 | @Override 51 | public int i(String tag, String msg, Throwable tr) { 52 | return Log.i(tag, msg, tr); 53 | } 54 | 55 | @Override 56 | public int w(String tag, String msg) { 57 | return Log.w(tag, msg); 58 | } 59 | 60 | @Override 61 | public int w(String tag, String msg, Throwable tr) { 62 | return Log.w(tag, msg, tr); 63 | } 64 | 65 | @Override 66 | public int e(String tag, String msg) { 67 | return Log.e(tag, msg); 68 | } 69 | 70 | @Override 71 | public int e(String tag, String msg, Throwable tr) { 72 | return Log.e(tag, msg, tr); 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/scrollerproxy/GingerScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.widget.OverScroller; 21 | 22 | @TargetApi(9) 23 | public class GingerScroller extends ScrollerProxy { 24 | 25 | protected final OverScroller mScroller; 26 | private boolean mFirstScroll = false; 27 | 28 | public GingerScroller(Context context) { 29 | mScroller = new OverScroller(context); 30 | } 31 | 32 | @Override 33 | public boolean computeScrollOffset() { 34 | // Workaround for first scroll returning 0 for the direction of the edge it hits. 35 | // Simply recompute values. 36 | if (mFirstScroll) { 37 | mScroller.computeScrollOffset(); 38 | mFirstScroll = false; 39 | } 40 | return mScroller.computeScrollOffset(); 41 | } 42 | 43 | @Override 44 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 45 | int overX, int overY) { 46 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY); 47 | } 48 | 49 | @Override 50 | public void forceFinished(boolean finished) { 51 | mScroller.forceFinished(finished); 52 | } 53 | 54 | @Override 55 | public boolean isFinished() { 56 | return mScroller.isFinished(); 57 | } 58 | 59 | @Override 60 | public int getCurrX() { 61 | return mScroller.getCurrX(); 62 | } 63 | 64 | @Override 65 | public int getCurrY() { 66 | return mScroller.getCurrY(); 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/scrollerproxy/IcsScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | 21 | @TargetApi(14) 22 | public class IcsScroller extends GingerScroller { 23 | 24 | public IcsScroller(Context context) { 25 | super(context); 26 | } 27 | 28 | @Override 29 | public boolean computeScrollOffset() { 30 | return mScroller.computeScrollOffset(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/scrollerproxy/PreGingerScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.widget.Scroller; 20 | 21 | public class PreGingerScroller extends ScrollerProxy { 22 | 23 | private final Scroller mScroller; 24 | 25 | public PreGingerScroller(Context context) { 26 | mScroller = new Scroller(context); 27 | } 28 | 29 | @Override 30 | public boolean computeScrollOffset() { 31 | return mScroller.computeScrollOffset(); 32 | } 33 | 34 | @Override 35 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 36 | int overX, int overY) { 37 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); 38 | } 39 | 40 | @Override 41 | public void forceFinished(boolean finished) { 42 | mScroller.forceFinished(finished); 43 | } 44 | 45 | public boolean isFinished() { 46 | return mScroller.isFinished(); 47 | } 48 | 49 | @Override 50 | public int getCurrX() { 51 | return mScroller.getCurrX(); 52 | } 53 | 54 | @Override 55 | public int getCurrY() { 56 | return mScroller.getCurrY(); 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/photoview/scrollerproxy/ScrollerProxy.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package me.kaede.util.fresco.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.os.Build.VERSION; 20 | import android.os.Build.VERSION_CODES; 21 | 22 | public abstract class ScrollerProxy { 23 | 24 | public static ScrollerProxy getScroller(Context context) { 25 | if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) { 26 | return new PreGingerScroller(context); 27 | } else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) { 28 | return new GingerScroller(context); 29 | } else { 30 | return new IcsScroller(context); 31 | } 32 | } 33 | 34 | public abstract boolean computeScrollOffset(); 35 | 36 | public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, 37 | int maxY, int overX, int overY); 38 | 39 | public abstract void forceFinished(boolean finished); 40 | 41 | public abstract boolean isFinished(); 42 | 43 | public abstract int getCurrX(); 44 | 45 | public abstract int getCurrY(); 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/ImageSource.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Rect; 5 | import android.net.Uri; 6 | 7 | /** 8 | * Helper class used to set the source and additional attributes from a variety of sources. Supports 9 | * use of a bitmap, asset, resource, external file or any other URI. 10 | * 11 | * When you are using a preview image, you must set the dimensions of the full size image on the 12 | * ImageSource object for the full size image using the {@link #dimensions(int, int)} method. 13 | */ 14 | public final class ImageSource { 15 | 16 | static final String FILE_SCHEME = "file:///"; 17 | static final String ASSET_SCHEME = "file:///android_asset/"; 18 | 19 | private final Uri uri; 20 | private final Bitmap bitmap; 21 | private final Integer resource; 22 | private boolean tile; 23 | private int sWidth; 24 | private int sHeight; 25 | private Rect sRegion; 26 | 27 | private ImageSource(Bitmap bitmap) { 28 | this.bitmap = bitmap; 29 | this.uri = null; 30 | this.resource = null; 31 | this.tile = false; 32 | this.sWidth = bitmap.getWidth(); 33 | this.sHeight = bitmap.getHeight(); 34 | } 35 | 36 | private ImageSource(Uri uri) { 37 | this.bitmap = null; 38 | this.uri = uri; 39 | this.resource = null; 40 | this.tile = true; 41 | } 42 | 43 | private ImageSource(int resource) { 44 | this.bitmap = null; 45 | this.uri = null; 46 | this.resource = resource; 47 | this.tile = true; 48 | } 49 | 50 | /** 51 | * Create an instance from a resource. The correct resource for the device screen resolution will be used. 52 | * @param resId resource ID. 53 | */ 54 | public static ImageSource resource(int resId) { 55 | return new ImageSource(resId); 56 | } 57 | 58 | /** 59 | * Create an instance from an asset name. 60 | * @param assetName asset name. 61 | */ 62 | public static ImageSource asset(String assetName) { 63 | if (assetName == null) { 64 | throw new NullPointerException("Asset name must not be null"); 65 | } 66 | return uri(ASSET_SCHEME + assetName); 67 | } 68 | 69 | /** 70 | * Create an instance from a URI. If the URI does not start with a scheme, it's assumed to be the URI 71 | * of a file. 72 | * @param uri image URI. 73 | */ 74 | public static ImageSource uri(String uri) { 75 | if (uri == null) { 76 | throw new NullPointerException("Uri must not be null"); 77 | } 78 | if (!uri.contains("://")) { 79 | if (uri.startsWith("/")) { 80 | uri = uri.substring(1); 81 | } 82 | uri = FILE_SCHEME + uri; 83 | } 84 | return new ImageSource(Uri.parse(uri)); 85 | } 86 | 87 | /** 88 | * Create an instance from a URI. 89 | * @param uri image URI. 90 | */ 91 | public static ImageSource uri(Uri uri) { 92 | if (uri == null) { 93 | throw new NullPointerException("Uri must not be null"); 94 | } 95 | return new ImageSource(uri); 96 | } 97 | 98 | /** 99 | * Provide a loaded bitmap for display. 100 | * @param bitmap bitmap to be displayed. 101 | */ 102 | public static ImageSource bitmap(Bitmap bitmap) { 103 | if (bitmap == null) { 104 | throw new NullPointerException("Bitmap must not be null"); 105 | } 106 | return new ImageSource(bitmap); 107 | } 108 | 109 | /** 110 | * Enable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap., 111 | * and tiling cannot be disabled when displaying a region of the source image. 112 | * @return this instance for chaining. 113 | */ 114 | public ImageSource tilingEnabled() { 115 | return tiling(true); 116 | } 117 | 118 | /** 119 | * Disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap, 120 | * and tiling cannot be disabled when displaying a region of the source image. 121 | * @return this instance for chaining. 122 | */ 123 | public ImageSource tilingDisabled() { 124 | return tiling(false); 125 | } 126 | 127 | /** 128 | * Enable or disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap, 129 | * and tiling cannot be disabled when displaying a region of the source image. 130 | * @return this instance for chaining. 131 | */ 132 | public ImageSource tiling(boolean tile) { 133 | this.tile = tile; 134 | return this; 135 | } 136 | 137 | /** 138 | * Use a region of the source image. Region must be set independently for the full size image and the preview if 139 | * you are using one. 140 | * @return this instance for chaining. 141 | */ 142 | public ImageSource region(Rect sRegion) { 143 | this.sRegion = sRegion; 144 | setInvariants(); 145 | return this; 146 | } 147 | 148 | /** 149 | * Declare the dimensions of the image. This is only required for a full size image, when you are specifying a URI 150 | * and also a preview image. When displaying a bitmap object, or not using a preview, you do not need to declare 151 | * the image dimensions. Note if the declared dimensions are found to be incorrect, the view will reset. 152 | * @return this instance for chaining. 153 | */ 154 | public ImageSource dimensions(int sWidth, int sHeight) { 155 | if (bitmap == null) { 156 | this.sWidth = sWidth; 157 | this.sHeight = sHeight; 158 | } 159 | setInvariants(); 160 | return this; 161 | } 162 | 163 | private void setInvariants() { 164 | if (this.sRegion != null) { 165 | this.tile = true; 166 | this.sWidth = this.sRegion.width(); 167 | this.sHeight = this.sRegion.height(); 168 | } 169 | } 170 | 171 | protected final Uri getUri() { 172 | return uri; 173 | } 174 | 175 | protected final Bitmap getBitmap() { 176 | return bitmap; 177 | } 178 | 179 | protected final Integer getResource() { 180 | return resource; 181 | } 182 | 183 | protected final boolean getTile() { 184 | return tile; 185 | } 186 | 187 | protected final int getSWidth() { 188 | return sWidth; 189 | } 190 | 191 | protected final int getSHeight() { 192 | return sHeight; 193 | } 194 | 195 | protected final Rect getSRegion() { 196 | return sRegion; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/ImageViewState.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 David Morrissey 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package me.kaede.util.fresco.subscaleview; 18 | 19 | import android.graphics.PointF; 20 | 21 | import java.io.Serializable; 22 | 23 | /** 24 | * Wraps the scale, center and orientation of a displayed image for easy restoration on screen rotate. 25 | */ 26 | public class ImageViewState implements Serializable { 27 | 28 | private float scale; 29 | 30 | private float centerX; 31 | 32 | private float centerY; 33 | 34 | private int orientation; 35 | 36 | public ImageViewState(float scale, PointF center, int orientation) { 37 | this.scale = scale; 38 | this.centerX = center.x; 39 | this.centerY = center.y; 40 | this.orientation = orientation; 41 | } 42 | 43 | public float getScale() { 44 | return scale; 45 | } 46 | 47 | public PointF getCenter() { 48 | return new PointF(centerX, centerY); 49 | } 50 | 51 | public int getOrientation() { 52 | return orientation; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/CompatDecoderFactory.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | /** 6 | * Compatibility factory to instantiate decoders with empty public constructors. 7 | * @param The base type of the decoder this factory will produce. 8 | */ 9 | public class CompatDecoderFactory implements DecoderFactory { 10 | private Class clazz; 11 | 12 | public CompatDecoderFactory(@NonNull Class clazz) { 13 | this.clazz = clazz; 14 | } 15 | 16 | @Override 17 | public T make() throws IllegalAccessException, InstantiationException { 18 | return clazz.newInstance(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/DecoderFactory.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | /** 4 | * Interface for decoder (and region decoder) factories. 5 | * @param the class of decoder that will be produced. 6 | */ 7 | public interface DecoderFactory { 8 | /** 9 | * Produce a new instance of a decoder with type {@link T}. 10 | * @return a new instance of your decoder. 11 | */ 12 | T make() throws IllegalAccessException, InstantiationException; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/ImageDecoder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Point; 6 | import android.graphics.Rect; 7 | import android.net.Uri; 8 | 9 | /** 10 | * Interface for image decoding classes, allowing the default {@link android.graphics.BitmapRegionDecoder} 11 | * based on the Skia library to be replaced with a custom class. 12 | */ 13 | public interface ImageDecoder { 14 | 15 | /** 16 | * Decode an image. When possible, initial setup work once in this method. This method 17 | * must return the dimensions of the image. The URI can be in one of the following formats: 18 | * File: file:///scard/picture.jpg 19 | * Asset: file:///android_asset/picture.png 20 | * Resource: android.resource://com.example.app/drawable/picture 21 | * @param context Application context. A reference may be held, but must be cleared on recycle. 22 | * @param uri URI of the image. 23 | * @return Dimensions of the image. 24 | * @throws Exception if initialisation fails. 25 | */ 26 | Bitmap decode(Context context, Uri uri) throws Exception; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/ImageRegionDecoder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Point; 6 | import android.graphics.Rect; 7 | import android.net.Uri; 8 | 9 | /** 10 | * Interface for image decoding classes, allowing the default {@link android.graphics.BitmapRegionDecoder} 11 | * based on the Skia library to be replaced with a custom class. 12 | */ 13 | public interface ImageRegionDecoder { 14 | 15 | /** 16 | * Initialise the decoder. When possible, initial setup work once in this method. This method 17 | * must return the dimensions of the image. The URI can be in one of the following formats: 18 | * File: file:///scard/picture.jpg 19 | * Asset: file:///android_asset/picture.png 20 | * Resource: android.resource://com.example.app/drawable/picture 21 | * @param context Application context. A reference may be held, but must be cleared on recycle. 22 | * @param uri URI of the image. 23 | * @return Dimensions of the image. 24 | * @throws Exception if initialisation fails. 25 | */ 26 | Point init(Context context, Uri uri) throws Exception; 27 | 28 | /** 29 | * Decode a region of the image with the given sample size. This method is called off the UI thread so it can safely 30 | * load the image on the current thread. It is called from an {@link android.os.AsyncTask} running in a single 31 | * threaded executor, and while a synchronization lock is held on this object, so will never be called concurrently 32 | * even if the decoder implementation supports it. 33 | * @param sRect Source image rectangle to decode. 34 | * @param sampleSize Sample size. 35 | * @return The decoded region. It is safe to return null if decoding fails. 36 | */ 37 | Bitmap decodeRegion(Rect sRect, int sampleSize); 38 | 39 | /** 40 | * Status check. Should return false before initialisation and after recycle. 41 | * @return true if the decoder is ready to be used. 42 | */ 43 | boolean isReady(); 44 | 45 | /** 46 | * This method will be called when the decoder is no longer required. It should clean up any resources still in use. 47 | */ 48 | void recycle(); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/SkiaImageDecoder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.content.pm.PackageManager; 6 | import android.content.res.Resources; 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory; 9 | import android.net.Uri; 10 | import android.text.TextUtils; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Default implementation of {@link ImageDecoder} 16 | * using Android's {@link BitmapFactory}, based on the Skia library. This 17 | * works well in most circumstances and has reasonable performance, however it has some problems 18 | * with grayscale, indexed and CMYK images. 19 | */ 20 | public class SkiaImageDecoder implements ImageDecoder { 21 | 22 | private static final String FILE_PREFIX = "file://"; 23 | private static final String ASSET_PREFIX = FILE_PREFIX + "/android_asset/"; 24 | private static final String RESOURCE_PREFIX = ContentResolver.SCHEME_ANDROID_RESOURCE + "://"; 25 | 26 | @Override 27 | public Bitmap decode(Context context, Uri uri) throws Exception { 28 | String uriString = uri.toString(); 29 | BitmapFactory.Options options = new BitmapFactory.Options(); 30 | Bitmap bitmap; 31 | options.inPreferredConfig = Bitmap.Config.RGB_565; 32 | if (uriString.startsWith(RESOURCE_PREFIX)) { 33 | Resources res; 34 | String packageName = uri.getAuthority(); 35 | if (context.getPackageName().equals(packageName)) { 36 | res = context.getResources(); 37 | } else { 38 | PackageManager pm = context.getPackageManager(); 39 | res = pm.getResourcesForApplication(packageName); 40 | } 41 | 42 | int id = 0; 43 | List segments = uri.getPathSegments(); 44 | int size = segments.size(); 45 | if (size == 2 && segments.get(0).equals("drawable")) { 46 | String resName = segments.get(1); 47 | id = res.getIdentifier(resName, "drawable", packageName); 48 | } else if (size == 1 && TextUtils.isDigitsOnly(segments.get(0))) { 49 | try { 50 | id = Integer.parseInt(segments.get(0)); 51 | } catch (NumberFormatException ignored) { 52 | } 53 | } 54 | 55 | bitmap = BitmapFactory.decodeResource(context.getResources(), id, options); 56 | } else if (uriString.startsWith(ASSET_PREFIX)) { 57 | String assetName = uriString.substring(ASSET_PREFIX.length()); 58 | bitmap = BitmapFactory.decodeStream(context.getAssets().open(assetName), null, options); 59 | } else if (uriString.startsWith(FILE_PREFIX)) { 60 | bitmap = BitmapFactory.decodeFile(uriString.substring(FILE_PREFIX.length()), options); 61 | } else { 62 | ContentResolver contentResolver = context.getContentResolver(); 63 | bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri), null, options); 64 | } 65 | if (bitmap == null) { 66 | throw new RuntimeException("Skia image region decoder returned null bitmap - image format may not be supported"); 67 | } 68 | return bitmap; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/util/fresco/subscaleview/decoder/SkiaImageRegionDecoder.java: -------------------------------------------------------------------------------- 1 | package me.kaede.util.fresco.subscaleview.decoder; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.content.pm.PackageManager; 6 | import android.content.res.AssetManager; 7 | import android.content.res.Resources; 8 | import android.graphics.*; 9 | import android.graphics.Bitmap.Config; 10 | import android.net.Uri; 11 | import android.text.TextUtils; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * Default implementation of {@link ImageRegionDecoder} 17 | * using Android's {@link BitmapRegionDecoder}, based on the Skia library. This 18 | * works well in most circumstances and has reasonable performance due to the cached decoder instance, 19 | * however it has some problems with grayscale, indexed and CMYK images. 20 | */ 21 | public class SkiaImageRegionDecoder implements ImageRegionDecoder { 22 | 23 | private BitmapRegionDecoder decoder; 24 | private final Object decoderLock = new Object(); 25 | 26 | private static final String FILE_PREFIX = "file://"; 27 | private static final String ASSET_PREFIX = FILE_PREFIX + "/android_asset/"; 28 | private static final String RESOURCE_PREFIX = ContentResolver.SCHEME_ANDROID_RESOURCE + "://"; 29 | 30 | @Override 31 | public Point init(Context context, Uri uri) throws Exception { 32 | String uriString = uri.toString(); 33 | if (uriString.startsWith(RESOURCE_PREFIX)) { 34 | Resources res; 35 | String packageName = uri.getAuthority(); 36 | if (context.getPackageName().equals(packageName)) { 37 | res = context.getResources(); 38 | } else { 39 | PackageManager pm = context.getPackageManager(); 40 | res = pm.getResourcesForApplication(packageName); 41 | } 42 | 43 | int id = 0; 44 | List segments = uri.getPathSegments(); 45 | int size = segments.size(); 46 | if (size == 2 && segments.get(0).equals("drawable")) { 47 | String resName = segments.get(1); 48 | id = res.getIdentifier(resName, "drawable", packageName); 49 | } else if (size == 1 && TextUtils.isDigitsOnly(segments.get(0))) { 50 | try { 51 | id = Integer.parseInt(segments.get(0)); 52 | } catch (NumberFormatException ignored) { 53 | } 54 | } 55 | 56 | decoder = BitmapRegionDecoder.newInstance(context.getResources().openRawResource(id), false); 57 | } else if (uriString.startsWith(ASSET_PREFIX)) { 58 | String assetName = uriString.substring(ASSET_PREFIX.length()); 59 | decoder = BitmapRegionDecoder.newInstance(context.getAssets().open(assetName, AssetManager.ACCESS_RANDOM), false); 60 | } else if (uriString.startsWith(FILE_PREFIX)) { 61 | decoder = BitmapRegionDecoder.newInstance(uriString.substring(FILE_PREFIX.length()), false); 62 | } else { 63 | ContentResolver contentResolver = context.getContentResolver(); 64 | decoder = BitmapRegionDecoder.newInstance(contentResolver.openInputStream(uri), false); 65 | } 66 | return new Point(decoder.getWidth(), decoder.getHeight()); 67 | } 68 | 69 | @Override 70 | public Bitmap decodeRegion(Rect sRect, int sampleSize) { 71 | synchronized (decoderLock) { 72 | BitmapFactory.Options options = new BitmapFactory.Options(); 73 | options.inSampleSize = sampleSize; 74 | options.inPreferredConfig = Config.RGB_565; 75 | Bitmap bitmap = decoder.decodeRegion(sRect, options); 76 | if (bitmap == null) { 77 | throw new RuntimeException("Skia image decoder returned null bitmap - image format may not be supported"); 78 | } 79 | return bitmap; 80 | } 81 | } 82 | 83 | @Override 84 | public boolean isReady() { 85 | return decoder != null && !decoder.isRecycled(); 86 | } 87 | 88 | @Override 89 | public void recycle() { 90 | decoder.recycle(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/MarkdownView.java: -------------------------------------------------------------------------------- 1 | package me.kaede.widget.markdownview; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | 7 | import me.kaede.widget.markdownview.util.HttpHelper; 8 | 9 | import android.content.Context; 10 | import android.os.AsyncTask; 11 | import android.util.AttributeSet; 12 | import android.webkit.WebView; 13 | 14 | import me.kaede.widget.markdownview.markdownprocessor.MarkdownProcessor; 15 | 16 | /** 17 | * @author Feras Alnatsheh 18 | */ 19 | public class MarkdownView extends WebView { 20 | 21 | public MarkdownView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | } 24 | 25 | public MarkdownView(Context context) { 26 | super(context); 27 | } 28 | 29 | /** 30 | * Loads the given Markdown text to the view as rich formatted HTML. The 31 | * HTML output will be styled based on the given CSS file. 32 | * 33 | * @param txt 34 | * - input in markdown format 35 | * @param cssFileUrl 36 | * - a URL to css File. If the file located in the project assets 37 | * folder then the URL should start with "file:///android_asset/" 38 | */ 39 | public void loadMarkdown(String txt, String cssFileUrl) { 40 | loadMarkdownToView(txt, cssFileUrl); 41 | } 42 | 43 | /** 44 | * Loads the given Markdown text to the view as rich formatted HTML. 45 | * 46 | * @param txt 47 | * - input in Markdown format 48 | */ 49 | public void loadMarkdown(String txt) { 50 | loadMarkdown(txt, null); 51 | } 52 | 53 | /** 54 | * Loads the given Markdown file to the view as rich formatted HTML. The HTML 55 | * output will be styled based on the given CSS file. 56 | * 57 | * @param url 58 | * - a URL to the Markdown file. If the file located in the 59 | * project assets folder then the URL should start with 60 | * "file:///android_asset/" 61 | * @param cssFileUrl 62 | * - a URL to css File. If the file located in the project assets 63 | * folder then the URL should start with "file:///android_asset/" 64 | */ 65 | public void loadMarkdownFile(String url, String cssFileUrl) { 66 | new LoadMarkdownUrlTask().execute(url, cssFileUrl); 67 | } 68 | 69 | public void loadMarkdownFile(String url) { 70 | loadMarkdownFile(url, null); 71 | } 72 | 73 | private String readFileFromAsset(String url) throws IOException { 74 | BufferedReader input = null; 75 | StringBuilder contents = new StringBuilder(); 76 | try { 77 | String assetFileName = url.substring(url.lastIndexOf('/') + 1, 78 | url.length()); 79 | input = new BufferedReader(new InputStreamReader(getContext() 80 | .getAssets().open(assetFileName))); 81 | String line = null; 82 | while ((line = input.readLine()) != null) { 83 | contents.append(line); 84 | contents.append(System.getProperty("line.separator")); 85 | } 86 | return contents.toString(); 87 | } finally { 88 | try { 89 | input.close(); 90 | } catch (IOException e) { 91 | } 92 | } 93 | } 94 | 95 | private class LoadMarkdownUrlTask extends 96 | AsyncTask { 97 | private String cssFileUrl; 98 | 99 | protected String doInBackground(String... params) { 100 | try { 101 | String txt = ""; 102 | String url = params[0]; 103 | this.cssFileUrl = params[1]; 104 | if (url.startsWith("file:///android_asset")) { 105 | txt = readFileFromAsset(url); 106 | } else { 107 | txt = HttpHelper.get(url).getResponseMessage(); 108 | } 109 | return txt; 110 | } catch (Exception ex) { 111 | } 112 | return null; 113 | } 114 | 115 | protected void onProgressUpdate(Integer... progress) { 116 | // no-op 117 | } 118 | 119 | protected void onPostExecute(String result) { 120 | if (result != null) { 121 | loadMarkdownToView(result, cssFileUrl); 122 | } else { 123 | loadUrl("about:blank"); 124 | } 125 | } 126 | } 127 | 128 | private void loadMarkdownToView(String txt, String cssFileUrl) { 129 | MarkdownProcessor m = new MarkdownProcessor(); 130 | String html = m.markdown(txt); 131 | if (cssFileUrl != null) { 132 | html = String.format( 133 | "" 134 | + html, cssFileUrl); 135 | } 136 | loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null); 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/CharacterProtector.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005, Pete Bevin. 3 | 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | * Neither the name "Markdown" nor the names of its contributors may 19 | be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | This software is provided by the copyright holders and contributors "as 23 | is" and any express or implied warranties, including, but not limited 24 | to, the implied warranties of merchantability and fitness for a 25 | particular purpose are disclaimed. In no event shall the copyright owner 26 | or contributors be liable for any direct, indirect, incidental, special, 27 | exemplary, or consequential damages (including, but not limited to, 28 | procurement of substitute goods or services; loss of use, data, or 29 | profits; or business interruption) however caused and on any theory of 30 | liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this 32 | software, even if advised of the possibility of such damage. 33 | 34 | */ 35 | 36 | package me.kaede.widget.markdownview.markdownprocessor; 37 | 38 | import java.util.Collection; 39 | import java.util.HashMap; 40 | import java.util.Map; 41 | import java.util.Random; 42 | 43 | class CharacterProtector { 44 | private Map protectMap = new HashMap(); 45 | private Map unprotectMap = new HashMap(); 46 | private static final String GOOD_CHARS = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; 47 | private Random rnd = new Random(); 48 | 49 | 50 | public String encode(String literal) { 51 | if (!protectMap.containsKey(literal)) { 52 | addToken(literal); 53 | } 54 | return protectMap.get(literal); 55 | } 56 | 57 | public String decode(String coded) { 58 | return unprotectMap.get(coded); 59 | } 60 | 61 | public Collection getAllEncodedTokens() { 62 | return unprotectMap.keySet(); 63 | } 64 | 65 | private void addToken(String literal) { 66 | String encoded = longRandomString(); 67 | protectMap.put(literal, encoded); 68 | unprotectMap.put(encoded, literal); 69 | } 70 | 71 | private String longRandomString() { 72 | StringBuffer sb = new StringBuffer(); 73 | final int CHAR_MAX = GOOD_CHARS.length(); 74 | for (int i = 0; i < 20; i++) { 75 | sb.append(GOOD_CHARS.charAt(rnd.nextInt(CHAR_MAX))); 76 | } 77 | return sb.toString(); 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | return protectMap.toString(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/HTMLDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005, Pete Bevin. 3 | 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | * Neither the name "Markdown" nor the names of its contributors may 19 | be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | This software is provided by the copyright holders and contributors "as 23 | is" and any express or implied warranties, including, but not limited 24 | to, the implied warranties of merchantability and fitness for a 25 | particular purpose are disclaimed. In no event shall the copyright owner 26 | or contributors be liable for any direct, indirect, incidental, special, 27 | exemplary, or consequential damages (including, but not limited to, 28 | procurement of substitute goods or services; loss of use, data, or 29 | profits; or business interruption) however caused and on any theory of 30 | liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this 32 | software, even if advised of the possibility of such damage. 33 | 34 | */ 35 | 36 | package me.kaede.widget.markdownview.markdownprocessor; 37 | 38 | import java.util.regex.Matcher; 39 | import java.util.regex.Pattern; 40 | 41 | public class HTMLDecoder { 42 | public static String decode(String html) { 43 | TextEditor ed = new TextEditor(html); 44 | Pattern p1 = Pattern.compile("&#(\\d+);"); 45 | ed.replaceAll(p1, new Replacement() { 46 | public String replacement(Matcher m) { 47 | String charDecimal = m.group(1); 48 | char ch = (char) Integer.parseInt(charDecimal); 49 | return Character.toString(ch); 50 | } 51 | }); 52 | 53 | Pattern p2 = Pattern.compile("&#x([0-9a-fA-F]+);"); 54 | ed.replaceAll(p2, new Replacement() { 55 | public String replacement(Matcher m) { 56 | String charHex = m.group(1); 57 | char ch = (char) Integer.parseInt(charHex, 16); 58 | return Character.toString(ch); 59 | } 60 | }); 61 | 62 | return ed.toString(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/HTMLToken.java: -------------------------------------------------------------------------------- 1 | package me.kaede.widget.markdownview.markdownprocessor; 2 | 3 | public class HTMLToken { 4 | private boolean isTag; 5 | private String text; 6 | 7 | private HTMLToken(boolean tag, String value) { 8 | isTag = tag; 9 | text = value; 10 | } 11 | 12 | public static HTMLToken tag(String text) { 13 | return new HTMLToken(true, text); 14 | } 15 | 16 | public static HTMLToken text(String text) { 17 | return new HTMLToken(false, text); 18 | } 19 | 20 | /** 21 | * @return true if this is a tag, false if it's text. 22 | */ 23 | public boolean isTag() { 24 | return isTag; 25 | } 26 | 27 | public String getText() { 28 | return text; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | String type; 34 | if (isTag()) { 35 | type = "tag"; 36 | } else { 37 | type = "text"; 38 | } 39 | return type + ": " + getText(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/LinkDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005, Pete Bevin. 3 | 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | * Neither the name "Markdown" nor the names of its contributors may 19 | be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | This software is provided by the copyright holders and contributors "as 23 | is" and any express or implied warranties, including, but not limited 24 | to, the implied warranties of merchantability and fitness for a 25 | particular purpose are disclaimed. In no event shall the copyright owner 26 | or contributors be liable for any direct, indirect, incidental, special, 27 | exemplary, or consequential damages (including, but not limited to, 28 | procurement of substitute goods or services; loss of use, data, or 29 | profits; or business interruption) however caused and on any theory of 30 | liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this 32 | software, even if advised of the possibility of such damage. 33 | 34 | */ 35 | 36 | package me.kaede.widget.markdownview.markdownprocessor; 37 | 38 | public class LinkDefinition { 39 | private String url; 40 | private String title; 41 | 42 | public LinkDefinition(String url, String title) { 43 | this.url = url; 44 | this.title = title; 45 | } 46 | 47 | public String getUrl() { 48 | return url; 49 | } 50 | 51 | public String getTitle() { 52 | return title; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return url + " (" + title + ")"; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/Replacement.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005, Pete Bevin. 3 | 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | * Neither the name "Markdown" nor the names of its contributors may 19 | be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | This software is provided by the copyright holders and contributors "as 23 | is" and any express or implied warranties, including, but not limited 24 | to, the implied warranties of merchantability and fitness for a 25 | particular purpose are disclaimed. In no event shall the copyright owner 26 | or contributors be liable for any direct, indirect, incidental, special, 27 | exemplary, or consequential damages (including, but not limited to, 28 | procurement of substitute goods or services; loss of use, data, or 29 | profits; or business interruption) however caused and on any theory of 30 | liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this 32 | software, even if advised of the possibility of such damage. 33 | 34 | */ 35 | 36 | package me.kaede.widget.markdownview.markdownprocessor; 37 | 38 | import java.util.regex.Matcher; 39 | 40 | public interface Replacement { 41 | String replacement(Matcher m); 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/markdownprocessor/TextEditor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005, Pete Bevin. 3 | 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | * Neither the name "Markdown" nor the names of its contributors may 19 | be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | This software is provided by the copyright holders and contributors "as 23 | is" and any express or implied warranties, including, but not limited 24 | to, the implied warranties of merchantability and fitness for a 25 | particular purpose are disclaimed. In no event shall the copyright owner 26 | or contributors be liable for any direct, indirect, incidental, special, 27 | exemplary, or consequential damages (including, but not limited to, 28 | procurement of substitute goods or services; loss of use, data, or 29 | profits; or business interruption) however caused and on any theory of 30 | liability, whether in contract, strict liability, or tort (including 31 | negligence or otherwise) arising in any way out of the use of this 32 | software, even if advised of the possibility of such damage. 33 | 34 | */ 35 | 36 | package me.kaede.widget.markdownview.markdownprocessor; 37 | 38 | import java.util.regex.Matcher; 39 | import java.util.regex.Pattern; 40 | import java.util.Collection; 41 | import java.util.List; 42 | import java.util.ArrayList; 43 | 44 | 45 | /** 46 | * Mutable String with common operations used in Markdown processing. 47 | */ 48 | public class TextEditor { 49 | private StringBuffer text; 50 | 51 | /** 52 | * Create a new TextEditor based on the contents of a String or 53 | * StringBuffer. 54 | * 55 | * @param text 56 | */ 57 | public TextEditor(CharSequence text) { 58 | this.text = new StringBuffer(text.toString()); 59 | } 60 | 61 | /** 62 | * Give up the contents of the TextEditor. 63 | * @return 64 | */ 65 | @Override 66 | public String toString() { 67 | return text.toString(); 68 | } 69 | 70 | /** 71 | * Replace all occurrences of the regular expression with the replacement. The replacement string 72 | * can contain $1, $2 etc. referring to matched groups in the regular expression. 73 | * 74 | * @param regex 75 | * @param replacement 76 | * @return 77 | */ 78 | public TextEditor replaceAll(String regex, String replacement) { 79 | if (text.length() > 0) { 80 | final String r = replacement; 81 | Pattern p = Pattern.compile(regex, Pattern.MULTILINE); 82 | Matcher m = p.matcher(text); 83 | StringBuffer sb = new StringBuffer(); 84 | while (m.find()) { 85 | m.appendReplacement(sb, r); 86 | } 87 | m.appendTail(sb); 88 | text = sb; 89 | } 90 | return this; 91 | } 92 | 93 | /** 94 | * Same as replaceAll(String, String), but does not interpret 95 | * $1, $2 etc. in the replacement string. 96 | * @param regex 97 | * @param replacement 98 | * @return 99 | */ 100 | public TextEditor replaceAllLiteral(String regex, final String replacement) { 101 | return replaceAll(Pattern.compile(regex, Pattern.MULTILINE), new Replacement() { 102 | public String replacement(Matcher m) { 103 | return replacement; 104 | } 105 | }); 106 | } 107 | 108 | /** 109 | * Replace all occurrences of the Pattern. The Replacement object's replace() method is 110 | * called on each match, and it provides a replacement, which is placed literally 111 | * (i.e., without interpreting $1, $2 etc.) 112 | * 113 | * @param pattern 114 | * @param replacement 115 | * @return 116 | */ 117 | public TextEditor replaceAll(Pattern pattern, Replacement replacement) { 118 | Matcher m = pattern.matcher(text); 119 | int lastIndex = 0; 120 | StringBuffer sb = new StringBuffer(); 121 | while (m.find()) { 122 | sb.append(text.subSequence(lastIndex, m.start())); 123 | sb.append(replacement.replacement(m)); 124 | lastIndex = m.end(); 125 | } 126 | sb.append(text.subSequence(lastIndex, text.length())); 127 | text = sb; 128 | return this; 129 | } 130 | 131 | /** 132 | * Remove all occurrences of the given regex pattern, replacing them 133 | * with the empty string. 134 | * 135 | * @param pattern Regular expression 136 | * @return 137 | * @see java.util.regex.Pattern 138 | */ 139 | public TextEditor deleteAll(String pattern) { 140 | return replaceAll(pattern, ""); 141 | } 142 | 143 | /** 144 | * Convert tabs to spaces given the default tab width of 4 spaces. 145 | * @return 146 | */ 147 | public TextEditor detabify() { 148 | return detabify(4); 149 | } 150 | 151 | /** 152 | * Convert tabs to spaces. 153 | * 154 | * @param tabWidth Number of spaces per tab. 155 | * @return 156 | */ 157 | public TextEditor detabify(final int tabWidth) { 158 | replaceAll(Pattern.compile("(.*?)\\t"), new Replacement() { 159 | public String replacement(Matcher m) { 160 | String lineSoFar = m.group(1); 161 | int width = lineSoFar.length(); 162 | StringBuffer replacement = new StringBuffer(lineSoFar); 163 | do { 164 | replacement.append(' '); 165 | ++width; 166 | } while (width % tabWidth != 0); 167 | return replacement.toString(); 168 | } 169 | }); 170 | return this; 171 | } 172 | 173 | /** 174 | * Remove a number of spaces at the start of each line. 175 | * @param spaces 176 | * @return 177 | */ 178 | public TextEditor outdent(int spaces) { 179 | return deleteAll("^(\\t|[ ]{1," + spaces + "})"); 180 | } 181 | 182 | /** 183 | * Remove one tab width (4 spaces) from the start of each line. 184 | * @return 185 | */ 186 | public TextEditor outdent() { 187 | return outdent(4); 188 | } 189 | 190 | /** 191 | * Remove leading and trailing space from the start and end of the buffer. Intermediate 192 | * lines are not affected. 193 | * @return 194 | */ 195 | public TextEditor trim() { 196 | text = new StringBuffer(text.toString().trim()); 197 | return this; 198 | } 199 | 200 | /** 201 | * Introduce a number of spaces at the start of each line. 202 | * @param spaces 203 | * @return 204 | */ 205 | public TextEditor indent(int spaces) { 206 | StringBuffer sb = new StringBuffer(spaces); 207 | for (int i = 0; i < spaces; i++) { 208 | sb.append(' '); 209 | } 210 | return replaceAll("^", sb.toString()); 211 | } 212 | 213 | /** 214 | * Add a string to the end of the buffer. 215 | * @param s 216 | */ 217 | public void append(CharSequence s) { 218 | text.append(s); 219 | } 220 | 221 | /** 222 | * Parse HTML tags, returning a Collection of HTMLToken objects. 223 | * @return 224 | */ 225 | public Collection tokenizeHTML() { 226 | List tokens = new ArrayList(); 227 | String nestedTags = nestedTagsRegex(6); 228 | 229 | Pattern p = Pattern.compile("" + 230 | "(?s:)" + 231 | "|" + 232 | "(?s:<\\?.*?\\?>)" + 233 | "|" + 234 | nestedTags + 235 | "", Pattern.CASE_INSENSITIVE); 236 | 237 | Matcher m = p.matcher(text); 238 | int lastPos = 0; 239 | while (m.find()) { 240 | if (lastPos < m.start()) { 241 | tokens.add(HTMLToken.text(text.substring(lastPos, m.start()))); 242 | } 243 | tokens.add(HTMLToken.tag(text.substring(m.start(), m.end()))); 244 | lastPos = m.end(); 245 | } 246 | if (lastPos < text.length()) { 247 | tokens.add(HTMLToken.text(text.substring(lastPos, text.length()))); 248 | } 249 | 250 | return tokens; 251 | } 252 | 253 | /** 254 | * Regex to match a tag, possibly with nested tags such as . 255 | * 256 | * @param depth - How many levels of tags-within-tags to allow. The example has depth 2. 257 | */ 258 | private String nestedTagsRegex(int depth) { 259 | if (depth == 0) { 260 | return ""; 261 | } else { 262 | return "(?:<[a-z/!$](?:[^<>]|" + nestedTagsRegex(depth - 1) + ")*>)"; 263 | } 264 | } 265 | 266 | /** 267 | * Add a string to the start of the first line of the buffer. 268 | * @param s 269 | */ 270 | public void prepend(CharSequence s) { 271 | StringBuffer newText = new StringBuffer(); 272 | newText.append(s); 273 | newText.append(text); 274 | text = newText; 275 | } 276 | 277 | /** 278 | * Find out whether the buffer is empty. 279 | * @return 280 | */ 281 | public boolean isEmpty() { 282 | return text.length() == 0; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /app/src/main/java/me/kaede/widget/markdownview/util/HttpHelper.java: -------------------------------------------------------------------------------- 1 | package me.kaede.widget.markdownview.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.HttpURLConnection; 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | import java.net.URLConnection; 11 | import java.util.List; 12 | import java.util.Set; 13 | import java.util.Map.Entry; 14 | 15 | /** 16 | * @author Feras Alnatsheh 17 | */ 18 | 19 | public class HttpHelper { 20 | 21 | private static final String CHARSET_UTF8 = "UTF-8"; 22 | public static final String CONTENT_TYPE_JSON = "json"; 23 | public static final String CONTENT_TYPE_XML = "xml"; 24 | 25 | // Timeout when reading from Input stream when a connection is established 26 | // to a resource 27 | private static final int DEFULT_READ_TIMEOUT = 5000; 28 | // Timeout for establishing a connection. 29 | private static final int DEFULT_CONNECT_TIMEOUT = 5000; 30 | 31 | static public Response get(String url, String query) 32 | throws MalformedURLException, IOException { 33 | return get(url, query, DEFULT_CONNECT_TIMEOUT, DEFULT_READ_TIMEOUT); 34 | } 35 | 36 | static public Response get(String url) throws MalformedURLException, 37 | IOException { 38 | return get(url, null, DEFULT_CONNECT_TIMEOUT, DEFULT_READ_TIMEOUT); 39 | } 40 | 41 | static public Response get(String url, String query, int connectTimeout, 42 | int readTimeout) throws MalformedURLException, IOException { 43 | String fullUrl = url; 44 | if (query != null && !query.equals("")) { 45 | fullUrl += "?" + query; 46 | } 47 | URLConnection connection = new URL(fullUrl).openConnection(); 48 | connection.setReadTimeout(readTimeout); 49 | connection.setConnectTimeout(connectTimeout); 50 | connection.setRequestProperty("Accept-Charset", CHARSET_UTF8); 51 | return getResponse((HttpURLConnection) connection); 52 | } 53 | 54 | static public Response post(String url, String query, String contentType) 55 | throws MalformedURLException, IOException { 56 | return post(url, query, contentType, DEFULT_CONNECT_TIMEOUT, 57 | DEFULT_READ_TIMEOUT); 58 | } 59 | 60 | static public Response post(String url, String query, String contentType, 61 | int connectTimeout, int readTimeout) throws MalformedURLException, 62 | IOException { 63 | URLConnection connection = new URL(url).openConnection(); 64 | connection.setReadTimeout(readTimeout); 65 | connection.setConnectTimeout(connectTimeout); 66 | connection.setDoOutput(true); // Triggers POST. 67 | connection.setRequestProperty("Accept-Charset", CHARSET_UTF8); 68 | connection.setRequestProperty("Content-Type", "application/" 69 | + contentType); 70 | OutputStream output = null; 71 | try { 72 | output = connection.getOutputStream(); 73 | output.write(query.getBytes(CHARSET_UTF8)); 74 | } finally { 75 | closeSilently(output); 76 | } 77 | return getResponse((HttpURLConnection) connection); 78 | } 79 | 80 | /* 81 | * Open the input stream to get responses from the server. 82 | */ 83 | private static Response getResponse(HttpURLConnection connection) 84 | throws IOException { 85 | InputStream inputStream = connection.getInputStream(); 86 | Response response = new Response(); 87 | response.setHttpResponseCode(connection.getResponseCode()); 88 | response.setHttpResponseHeader(connection.getHeaderFields().entrySet()); 89 | response.setResponseMessage(getResponseMessage(inputStream, connection)); 90 | response.setHttpResponseMessage(connection.getResponseMessage()); 91 | return response; 92 | } 93 | 94 | /* 95 | * Get the HTTP response message from the server. 96 | */ 97 | private static String getResponseMessage(InputStream inputStream, 98 | HttpURLConnection connection) throws UnsupportedEncodingException, 99 | IOException { 100 | String responseMessage = null; 101 | StringBuffer sb = new StringBuffer(); 102 | InputStream dis = connection.getInputStream(); 103 | int chr; 104 | while ((chr = dis.read()) != -1) { 105 | sb.append((char) chr); 106 | } 107 | if (sb != null) { 108 | responseMessage = sb.toString(); 109 | } 110 | return responseMessage; 111 | } 112 | 113 | /* 114 | * Close the connection, if the connection could not be closed (probably 115 | * because its already closed) ignore the error. 116 | */ 117 | private static void closeSilently(OutputStream output) { 118 | if (output != null) { 119 | try { 120 | output.close(); 121 | } catch (IOException e) { 122 | } 123 | } 124 | } 125 | 126 | public static class Response { 127 | 128 | private Set>> httpResponseHeader; 129 | private int httpResponseCode; 130 | private String httpResponseMessage; 131 | private String serverResponseMessage; 132 | 133 | Response() { 134 | } 135 | 136 | Response(Set>> httpResponseHeader, 137 | int httpResponseCode, String httpResponseMessage, 138 | String responseMessage) { 139 | setHttpResponseHeader(httpResponseHeader); 140 | setHttpResponseCode(httpResponseCode); 141 | setHttpResponseMessage(httpResponseMessage); 142 | setResponseMessage(responseMessage); 143 | } 144 | 145 | public String getHttpResponseMessage() { 146 | return httpResponseMessage; 147 | } 148 | 149 | public void setHttpResponseMessage(String httpResponseMessage) { 150 | this.httpResponseMessage = httpResponseMessage; 151 | } 152 | 153 | public Set>> getHttpResponseHeader() { 154 | return httpResponseHeader; 155 | } 156 | 157 | public void setHttpResponseHeader( 158 | Set>> httpResponseHeader) { 159 | this.httpResponseHeader = httpResponseHeader; 160 | } 161 | 162 | public int getHttpResponseCode() { 163 | return httpResponseCode; 164 | } 165 | 166 | public void setHttpResponseCode(int httpResponseCode) { 167 | this.httpResponseCode = httpResponseCode; 168 | } 169 | 170 | public String getResponseMessage() { 171 | return serverResponseMessage; 172 | } 173 | 174 | public void setResponseMessage(String responseMessage) { 175 | this.serverResponseMessage = responseMessage; 176 | } 177 | 178 | public String toString() { 179 | return "httpResponseCode = " + httpResponseCode + " , " 180 | + "httpResponseMessage = " + httpResponseMessage + " , " 181 | + "serverResponseMessage = " + serverResponseMessage; 182 | } 183 | 184 | } 185 | 186 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/image_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xhdpi/image_background.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/image_failure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xhdpi/image_failure.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/image_placeholder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xhdpi/image_placeholder.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/image_retry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xhdpi/image_retry.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/pattern_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xhdpi/pattern_tile.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/image_failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xxhdpi/image_failure.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/image_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xxhdpi/image_loading.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/image_retry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/drawable-xxhdpi/image_retry.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/pattern.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_photo_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 23 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_samplelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 12 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_simple.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_snippet.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_subsampling_actvity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_recyclerview.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_samplelist_recycleview.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_gifimageview.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaedea/fresco-sample-usage/732a196cc45dc2dc989f5bdb83d758a4f7aebc99/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | @android:color/white 5 | #303F9F 6 | #FF4081 7 | 8 | #BDBDBD 9 | #553F51B5 10 | #55FF4081 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Fresco Sample 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 16 |