├── .gitignore
├── Azoft-Collage
├── .gitignore
├── build.gradle
├── libs
│ ├── injectorLib.jar
│ ├── licences.txt
│ └── loaderLib.jar
├── libssrc
│ ├── injectorLib-sources.jar
│ └── loaderLib-sources.jar
├── proguard-rules.txt
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ └── com
│ │ └── azoft
│ │ └── azoft
│ │ └── collage
│ │ ├── app
│ │ └── CollageApplication.java
│ │ ├── data
│ │ ├── Collage.java
│ │ ├── CollageFillData.java
│ │ ├── CollageRegionData.java
│ │ ├── Image.java
│ │ ├── Post.java
│ │ ├── User.java
│ │ └── results
│ │ │ ├── UserDataResult.java
│ │ │ ├── UserRecentFeedResult.java
│ │ │ └── UsersSearchResult.java
│ │ ├── exceptions
│ │ ├── CollageCreationException.java
│ │ ├── DiskWriteException.java
│ │ ├── InternalServerException.java
│ │ ├── NoHandleInBaseActivityException.java
│ │ └── NotAllowedException.java
│ │ ├── loaders
│ │ ├── CollageBigImageLoader.java
│ │ ├── CollagePreviewCreatorLoader.java
│ │ ├── UserDataLoader.java
│ │ ├── UserImageFeedLoader.java
│ │ └── UsersSearchLoader.java
│ │ ├── server
│ │ ├── InstagramService.java
│ │ ├── RetrofitHelper.java
│ │ ├── ServerConnector.java
│ │ └── responces
│ │ │ ├── SearchUserResponse.java
│ │ │ └── UserRecentFeedResponse.java
│ │ ├── ui
│ │ ├── activities
│ │ │ └── phone
│ │ │ │ ├── CollageActivity.java
│ │ │ │ ├── CollageAuthActivity.java
│ │ │ │ ├── CollageBuilderActivity.java
│ │ │ │ ├── CollagePreviewActivity.java
│ │ │ │ ├── ImageSelectionFromUserFeedActivity.java
│ │ │ │ ├── InstagramAuthActivity.java
│ │ │ │ ├── SingleFragmentActivity.java
│ │ │ │ ├── StartActivity.java
│ │ │ │ └── UserSelectionActivity.java
│ │ ├── adapters
│ │ │ ├── CollageAdapter.java
│ │ │ ├── UserFeedAdapter.java
│ │ │ └── UsersAdapter.java
│ │ ├── fragments
│ │ │ ├── ActionBarLoaderFragment.java
│ │ │ ├── CollageBuilderFragment.java
│ │ │ ├── CollagePreviewFragment.java
│ │ │ ├── CollageSelectionFragment.java
│ │ │ ├── ImageSelectionFromUserFeedFragment.java
│ │ │ └── UserSelectionFragment.java
│ │ └── widgets
│ │ │ ├── CollageItemView.java
│ │ │ ├── CollageViewGroup.java
│ │ │ └── SquareRelativeLayout.java
│ │ └── utils
│ │ ├── CollageRegion.java
│ │ ├── CommonUtils.java
│ │ ├── MediaUtils.java
│ │ └── collagegenerators
│ │ ├── CollageFactory.java
│ │ └── SimpleCollageGenerator.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_action_picture.png
│ ├── ic_action_refresh.png
│ ├── ic_action_share.png
│ ├── ic_action_user.png
│ ├── ic_launcher.png
│ └── selected_collage.png
│ ├── drawable-mdpi
│ ├── ic_action_picture.png
│ ├── ic_action_refresh.png
│ ├── ic_action_share.png
│ ├── ic_action_user.png
│ ├── ic_launcher.png
│ └── selected_collage.png
│ ├── drawable-xhdpi
│ ├── ic_action_picture.png
│ ├── ic_action_refresh.png
│ ├── ic_action_share.png
│ ├── ic_action_user.png
│ ├── ic_launcher.png
│ └── selected_collage.png
│ ├── drawable-xxhdpi
│ ├── ic_action_picture.png
│ ├── ic_action_refresh.png
│ ├── ic_action_share.png
│ └── ic_launcher.png
│ ├── drawable
│ └── ic_action_new.9.png
│ ├── layout
│ ├── activity_instagram_auth.xml
│ ├── activity_single_fragment.xml
│ ├── activity_start.xml
│ ├── fragment_collage_builder.xml
│ ├── fragment_collage_preview.xml
│ ├── fragment_collage_selection.xml
│ ├── fragment_image_selection_from_user_feed.xml
│ ├── fragment_user_selection.xml
│ ├── item_collage.xml
│ ├── item_user.xml
│ └── item_user_feed.xml
│ ├── menu
│ ├── collage_builder.xml
│ ├── collage_preview.xml
│ ├── image_selection_user_feed.xml
│ ├── start_collage.xml
│ └── user_account_selection.xml
│ ├── values-ru
│ └── strings.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── ids.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ └── filepaths.xml
├── build.gradle
├── device-2016-01-15-125125.mp4
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── privacy_policy.html
├── readme.md
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | gen
3 | workspace.xml
4 | build
5 | /.idea
6 | /*.iml
7 | /local.properties
8 |
--------------------------------------------------------------------------------
/Azoft-Collage/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Azoft-Collage/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion '21.1.2'
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | applicationId "com.azoft.azoft.collage"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
18 | }
19 | }
20 | lintOptions {
21 | abortOnError false
22 | }
23 | }
24 |
25 | dependencies {
26 | compile 'com.android.support:appcompat-v7:23.1.1'
27 | compile 'com.android.support:support-v4:23.1.1'
28 | compile 'com.squareup.okhttp:okhttp:2.0.0'
29 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
30 | compile 'com.squareup.retrofit:retrofit:1.9.0'
31 | compile 'com.squareup.picasso:picasso:2.4.0'
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | }
--------------------------------------------------------------------------------
/Azoft-Collage/libs/injectorLib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/libs/injectorLib.jar
--------------------------------------------------------------------------------
/Azoft-Collage/libs/licences.txt:
--------------------------------------------------------------------------------
1 | OkHttp (http://square.github.io/okhttp/)
2 |
3 |
4 | Copyright 2013 Square, Inc.
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 |
20 |
21 | Retrofit (http://square.github.io/retrofit/)
22 |
23 |
24 | Copyright 2013 Square, Inc.
25 |
26 | Licensed under the Apache License, Version 2.0 (the "License");
27 | you may not use this file except in compliance with the License.
28 | You may obtain a copy of the License at
29 |
30 | http://www.apache.org/licenses/LICENSE-2.0
31 |
32 | Unless required by applicable law or agreed to in writing, software
33 | distributed under the License is distributed on an "AS IS" BASIS,
34 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 | See the License for the specific language governing permissions and
36 | limitations under the License.
37 |
38 |
39 |
40 |
41 | Picasso (http://square.github.io/picasso/)
42 |
43 |
44 | Copyright 2013 Square, Inc.
45 |
46 | Licensed under the Apache License, Version 2.0 (the "License");
47 | you may not use this file except in compliance with the License.
48 | You may obtain a copy of the License at
49 |
50 | http://www.apache.org/licenses/LICENSE-2.0
51 |
52 | Unless required by applicable law or agreed to in writing, software
53 | distributed under the License is distributed on an "AS IS" BASIS,
54 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
55 | See the License for the specific language governing permissions and
56 | limitations under the License.
57 |
58 |
59 |
60 |
61 | Gson (https://code.google.com/p/google-gson/)
62 |
63 |
64 | Licensed under the Apache License, Version 2.0 (the "License");
65 | you may not use this file except in compliance with the License.
66 | You may obtain a copy of the License at
67 |
68 | http://www.apache.org/licenses/LICENSE-2.0
69 |
70 | Unless required by applicable law or agreed to in writing, software
71 | distributed under the License is distributed on an "AS IS" BASIS,
72 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
73 | See the License for the specific language governing permissions and
74 | limitations under the License.
75 |
76 |
77 |
78 |
79 | InjectorLib (https://github.com/mig35/LoaderLib)
80 |
81 |
82 | Licensed under the Apache License, Version 2.0 (the "License");
83 | you may not use this file except in compliance with the License.
84 | You may obtain a copy of the License at
85 |
86 | http://www.apache.org/licenses/LICENSE-2.0
87 |
88 | Unless required by applicable law or agreed to in writing, software
89 | distributed under the License is distributed on an "AS IS" BASIS,
90 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
91 | See the License for the specific language governing permissions and
92 | limitations under the License.
93 |
94 |
95 |
96 |
97 | LoaderLib (https://github.com/mig35/LoaderLib)
98 |
99 |
100 | Licensed under the Apache License, Version 2.0 (the "License");
101 | you may not use this file except in compliance with the License.
102 | You may obtain a copy of the License at
103 |
104 | http://www.apache.org/licenses/LICENSE-2.0
105 |
106 | Unless required by applicable law or agreed to in writing, software
107 | distributed under the License is distributed on an "AS IS" BASIS,
108 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
109 | See the License for the specific language governing permissions and
110 | limitations under the License.
--------------------------------------------------------------------------------
/Azoft-Collage/libs/loaderLib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/libs/loaderLib.jar
--------------------------------------------------------------------------------
/Azoft-Collage/libssrc/injectorLib-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/libssrc/injectorLib-sources.jar
--------------------------------------------------------------------------------
/Azoft-Collage/libssrc/loaderLib-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/libssrc/loaderLib-sources.jar
--------------------------------------------------------------------------------
/Azoft-Collage/proguard-rules.txt:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:/Users/Mikhail/Documents/tools/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the ProGuard
5 | # include property in project.properties.
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 | #}
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
36 |
37 |
40 |
41 |
44 |
45 |
50 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/app/CollageApplication.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.app;
2 |
3 | import android.app.Application;
4 | import android.os.Handler;
5 | import android.os.Looper;
6 | import android.widget.Toast;
7 |
8 | import com.squareup.picasso.Picasso;
9 |
10 | /**
11 | * Date: 4/7/2014
12 | * Time: 3:57 PM
13 | *
14 | * @author MiG35
15 | */
16 | public class CollageApplication extends Application {
17 |
18 | private static CollageApplication sInstance;
19 |
20 | private Toast mOldToast;
21 | private Handler mHandler;
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 |
27 | sInstance = this;
28 | mHandler = new Handler();
29 |
30 | final Picasso picasso = Picasso.with(this);
31 | picasso.setIndicatorsEnabled(true);
32 | picasso.setLoggingEnabled(false);
33 | }
34 |
35 | public static CollageApplication getInstance() {
36 | return sInstance;
37 | }
38 |
39 | /**
40 | * Show toast. Previous toast will be canceled.
41 | * Thread save.
42 | *
43 | * @param message data to show for toast
44 | * @param gravity if set, this gravity will be used for toast
45 | */
46 | public void showToast(final String message, final Integer gravity) {
47 | if (getMainLooper() == Looper.myLooper()) {
48 | if (null != mOldToast) {
49 | mOldToast.cancel();
50 | }
51 | mOldToast = Toast.makeText(this, message, Toast.LENGTH_LONG);
52 | if (null != gravity) {
53 | mOldToast.setGravity(gravity, 0, 0);
54 | }
55 | mOldToast.show();
56 | } else {
57 | mHandler.post(new Runnable() {
58 | @Override
59 | public void run() {
60 | showToast(message, gravity);
61 | }
62 | });
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/Collage.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import com.azoft.azoft.collage.utils.CollageRegion;
4 |
5 | import java.io.Serializable;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * Contains collage structure as CollageRegion's list.
11 | *
12 | * Date: 4/8/2014
13 | * Time: 4:12 PM
14 | *
15 | * @author MiG35
16 | */
17 | public class Collage implements Serializable {
18 |
19 | private static final long serialVersionUID = -3545166311422144328L;
20 |
21 | protected final List mCollageRegions;
22 | private final int mRegionsCount;
23 |
24 | /**
25 | * @param collageRegions - can't be null or empty
26 | */
27 | public Collage(final List collageRegions) {
28 | if (null == collageRegions || collageRegions.isEmpty()) {
29 | throw new IllegalArgumentException("collageRegions shouldn't be empty");
30 | }
31 | mCollageRegions = Collections.unmodifiableList(collageRegions);
32 | mRegionsCount = mCollageRegions.size();
33 | }
34 |
35 | public List getCollageRegions() {
36 | return mCollageRegions;
37 | }
38 |
39 | public int getRegionsCount() {
40 | return mRegionsCount;
41 | }
42 |
43 | @Override
44 | public boolean equals(final Object o) {
45 | if (this == o) {
46 | return true;
47 | }
48 | if (!(o instanceof Collage)) {
49 | return false;
50 | }
51 |
52 | final Collage collage = (Collage) o;
53 |
54 | return mCollageRegions.equals(collage.mCollageRegions);
55 | }
56 |
57 | @Override
58 | public int hashCode() {
59 | return mCollageRegions.hashCode();
60 | }
61 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/CollageFillData.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import com.azoft.azoft.collage.utils.CollageRegion;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * Contains collage fill data for all its regions.
10 | *
11 | * Date: 4/9/2014
12 | * Time: 11:40 AM
13 | *
14 | * @author MiG35
15 | */
16 | public class CollageFillData extends Collage {
17 |
18 | private static final long serialVersionUID = 9161249919940778595L;
19 |
20 | private final Map mRectangleDataMap;
21 |
22 | public CollageFillData(final Collage collage) {
23 | super(collage.getCollageRegions());
24 |
25 | mRectangleDataMap = new HashMap<>();
26 | }
27 |
28 | public void setRegionData(final CollageRegion collageRegion, final CollageRegionData collageRegionData) {
29 | if (mCollageRegions.contains(collageRegion)) {
30 | mRectangleDataMap.put(collageRegion, collageRegionData);
31 | } else {
32 | throw new IllegalArgumentException("wrong collageRegion entered");
33 | }
34 | }
35 |
36 | public CollageRegionData getRegionData(final CollageRegion collageRegion) {
37 | return mRectangleDataMap.get(collageRegion);
38 | }
39 |
40 | public boolean hasAllRegions() {
41 | if (mRectangleDataMap.size() == mCollageRegions.size()) {
42 | for (final Map.Entry entryItem : mRectangleDataMap.entrySet()) {
43 | if (null == entryItem.getValue()) {
44 | return false;
45 | }
46 | }
47 | return true;
48 | }
49 | return false;
50 | }
51 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/CollageRegionData.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import java.io.File;
4 | import java.io.Serializable;
5 |
6 | /**
7 | * Contains image data as source and it's position inside region.
8 | *
9 | * Date: 4/9/2014
10 | * Time: 11:42 AM
11 | *
12 | * @author MiG35
13 | */
14 | public class CollageRegionData implements Serializable {
15 |
16 | private static final long serialVersionUID = -7032708611705926844L;
17 |
18 | private final File mImageFile;
19 | private Float mImageLeft;
20 | private Float mImageTop;
21 | private float mImageScale;
22 | private int mImageRealSizeScale;
23 |
24 | public CollageRegionData(final File imageFile) {
25 | if (null == imageFile) {
26 | throw new IllegalArgumentException("imageFile can't be null");
27 | }
28 | mImageFile = imageFile;
29 | mImageScale = 1f;
30 | }
31 |
32 | public File getImageFile() {
33 | return mImageFile;
34 | }
35 |
36 | public Float getImageLeft() {
37 | return mImageLeft;
38 | }
39 |
40 | public void setImageLeft(final float imageLeft) {
41 | mImageLeft = imageLeft;
42 | }
43 |
44 | public Float getImageTop() {
45 | return mImageTop;
46 | }
47 |
48 | public void setImageTop(final float imageTop) {
49 | mImageTop = imageTop;
50 | }
51 |
52 | public float getImageScale() {
53 | return mImageScale;
54 | }
55 |
56 | public void setImageScale(final float imageScale) {
57 | mImageScale = imageScale;
58 | }
59 |
60 | @Override
61 | public boolean equals(final Object o) {
62 | if (this == o) {
63 | return true;
64 | }
65 | if (!(o instanceof CollageRegionData)) {
66 | return false;
67 | }
68 |
69 | final CollageRegionData collageRegionData = (CollageRegionData) o;
70 |
71 | return mImageFile.equals(collageRegionData.mImageFile);
72 | }
73 |
74 | @SuppressWarnings("NonFinalFieldReferencedInHashCode")
75 | @Override
76 | public int hashCode() {
77 | return mImageFile.hashCode();
78 | }
79 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/Image.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Date: 4/9/2014
7 | * Time: 9:40 AM
8 | *
9 | * @author MiG35
10 | */
11 | public class Image implements Serializable {
12 |
13 | private static final long serialVersionUID = 1238987802396038801L;
14 |
15 | private final int mWidth;
16 | private final int mHeight;
17 | private final String mUrl;
18 |
19 | public Image(final int width, final int height, final String url) {
20 | mWidth = width;
21 | mHeight = height;
22 | mUrl = url;
23 | }
24 |
25 | public int getWidth() {
26 | return mWidth;
27 | }
28 |
29 | public int getHeight() {
30 | return mHeight;
31 | }
32 |
33 | public String getUrl() {
34 | return mUrl;
35 | }
36 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/Post.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Date: 4/7/2014
9 | * Time: 5:29 PM
10 | *
11 | * @author MiG35
12 | */
13 | public class Post implements Serializable, Comparable {
14 |
15 | private static final long serialVersionUID = -506449273621003026L;
16 |
17 | private final String mId;
18 |
19 | private final String mType;
20 | private final int mLikesCount;
21 |
22 | private final Image mThumbnailImage;
23 | private final Image mLowResolutionImage;
24 | private final Image mStandardResolutionImage;
25 |
26 | public Post(final String id, final String type, final int likesCount, final Image thumbnailImage, final Image lowResolutionImage,
27 | final Image standardResolutionImage) {
28 | mId = id;
29 | mType = type;
30 | mLikesCount = likesCount;
31 | mThumbnailImage = thumbnailImage;
32 | mLowResolutionImage = lowResolutionImage;
33 | mStandardResolutionImage = standardResolutionImage;
34 | }
35 |
36 | public String getId() {
37 | return mId;
38 | }
39 |
40 | public String getType() {
41 | return mType;
42 | }
43 |
44 | public int getLikesCount() {
45 | return mLikesCount;
46 | }
47 |
48 | public Image getThumbnailImage() {
49 | return mThumbnailImage;
50 | }
51 |
52 | public Image getLowResolutionImage() {
53 | return mLowResolutionImage;
54 | }
55 |
56 | public Image getStandardResolutionImage() {
57 | return mStandardResolutionImage;
58 | }
59 |
60 | @Override
61 | public int compareTo(@NonNull final Post another) {
62 | return mLikesCount < another.mLikesCount ? 1 : -1;
63 | }
64 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/User.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Date: 4/8/2014
9 | * Time: 12:38 PM
10 | *
11 | * @author MiG35
12 | */
13 | public class User implements Serializable {
14 |
15 | private static final long serialVersionUID = 8758285803290081341L;
16 |
17 | @SerializedName("username")
18 | private String mNickName;
19 | @SerializedName("first_name")
20 | private String mFirstName;
21 | @SerializedName("last_name")
22 | private String mLastName;
23 | @SerializedName("profile_picture")
24 | private String mProfilePicture;
25 | @SerializedName("id")
26 | private String mId;
27 |
28 | public String getNickName() {
29 | return mNickName;
30 | }
31 |
32 | public String getFirstName() {
33 | return mFirstName;
34 | }
35 |
36 | public String getLastName() {
37 | return mLastName;
38 | }
39 |
40 | public String getProfilePicture() {
41 | return mProfilePicture;
42 | }
43 |
44 | public String getId() {
45 | return mId;
46 | }
47 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/results/UserDataResult.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data.results;
2 |
3 | import com.azoft.azoft.collage.data.User;
4 |
5 | /**
6 | * Date: 4/11/2014
7 | * Time: 3:55 PM
8 | *
9 | * @author MiG35
10 | */
11 | public class UserDataResult {
12 |
13 | private final User mUser;
14 | private final boolean mDataViewAllowed;
15 | private final boolean mHasImages;
16 |
17 | private UserDataResult(final User user, final boolean dataViewAllowed, final boolean hasImages) {
18 | mUser = user;
19 | mDataViewAllowed = dataViewAllowed;
20 | mHasImages = hasImages;
21 | }
22 |
23 | public User getUser() {
24 | return mUser;
25 | }
26 |
27 | public boolean isDataViewAllowed() {
28 | return mDataViewAllowed;
29 | }
30 |
31 | public boolean isHasImages() {
32 | return mHasImages;
33 | }
34 |
35 | public static UserDataResult getNotAllowed(final User user) {
36 | return new UserDataResult(user, false, false);
37 | }
38 |
39 | public static UserDataResult getHasNoData(final User user) {
40 | return new UserDataResult(user, true, false);
41 | }
42 |
43 | public static UserDataResult getHasData(final User user) {
44 | return new UserDataResult(user, true, true);
45 | }
46 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/results/UserRecentFeedResult.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data.results;
2 |
3 | import com.azoft.azoft.collage.data.Post;
4 |
5 | import java.io.Serializable;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * Date: 4/9/2014
11 | * Time: 9:31 AM
12 | *
13 | * @author MiG35
14 | */
15 | public class UserRecentFeedResult implements Serializable {
16 |
17 | private static final long serialVersionUID = 4293075867718694860L;
18 |
19 | private final String mUserId;
20 | private final List mPosts;
21 |
22 | public UserRecentFeedResult(final String userId, final List posts) {
23 | if (null == posts) {
24 | throw new IllegalArgumentException("posts can't be null");
25 | }
26 | mUserId = userId;
27 | mPosts = Collections.unmodifiableList(posts);
28 | }
29 |
30 | public String getUserId() {
31 | return mUserId;
32 | }
33 |
34 | public List getPosts() {
35 | return mPosts;
36 | }
37 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/data/results/UsersSearchResult.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.data.results;
2 |
3 | import com.azoft.azoft.collage.data.User;
4 |
5 | import java.io.Serializable;
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.List;
9 |
10 | /**
11 | * Date: 4/8/2014
12 | * Time: 1:04 PM
13 | *
14 | * @author MiG35
15 | */
16 | public class UsersSearchResult implements Serializable {
17 |
18 | private static final long serialVersionUID = -7231458361668713668L;
19 |
20 | private final String mNickName;
21 | private final List mUsers;
22 |
23 | public UsersSearchResult(final String nickName, final List users) {
24 | mNickName = nickName;
25 | if (null == users) {
26 | mUsers = Collections.emptyList();
27 | } else {
28 | mUsers = new ArrayList<>(users);
29 | }
30 | }
31 |
32 | public String getNickName() {
33 | return mNickName;
34 | }
35 |
36 | public List getUsers() {
37 | return mUsers;
38 | }
39 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/exceptions/CollageCreationException.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.exceptions;
2 |
3 | /**
4 | * Special exception for inner collage creation logic fails.
5 | *
6 | * Date: 4/9/2014
7 | * Time: 6:28 PM
8 | *
9 | * @author MiG35
10 | */
11 | public class CollageCreationException extends NoHandleInBaseActivityException {
12 |
13 | private static final long serialVersionUID = -8353694528536973759L;
14 |
15 | public CollageCreationException() {
16 | }
17 |
18 | public CollageCreationException(final String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public CollageCreationException(final String detailMessage, final Throwable throwable) {
23 | super(detailMessage, throwable);
24 | }
25 |
26 | public CollageCreationException(final Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/exceptions/DiskWriteException.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.exceptions;
2 |
3 | /**
4 | * Indicates some disk write/read errors.
5 | *
6 | * Date: 4/9/2014
7 | * Time: 12:29 PM
8 | *
9 | * @author MiG35
10 | */
11 | public class DiskWriteException extends Exception {
12 |
13 | private static final long serialVersionUID = -7962369698722370033L;
14 |
15 | public DiskWriteException() {
16 | }
17 |
18 | public DiskWriteException(final Throwable throwable) {
19 | super(throwable);
20 | }
21 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/exceptions/InternalServerException.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.exceptions;
2 |
3 | /**
4 | * Some exception in protocol or in server communication.
5 | *
6 | * Date: 4/8/2014
7 | * Time: 2:49 PM
8 | *
9 | * @author MiG35
10 | */
11 | public class InternalServerException extends Exception {
12 |
13 | private static final long serialVersionUID = 5180367710900570152L;
14 |
15 | public InternalServerException() {
16 | }
17 |
18 | public InternalServerException(final String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public InternalServerException(final String detailMessage, final Throwable throwable) {
23 | super(detailMessage, throwable);
24 | }
25 |
26 | public InternalServerException(final Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/exceptions/NoHandleInBaseActivityException.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.exceptions;
2 |
3 | /**
4 | * Indicates that this exception should be ignored by base activity exception handle.
5 | *
6 | * Date: 4/10/2014
7 | * Time: 1:02 PM
8 | *
9 | * @author MiG35
10 | */
11 | public class NoHandleInBaseActivityException extends Exception {
12 |
13 | private static final long serialVersionUID = 2439717201384478829L;
14 |
15 | public NoHandleInBaseActivityException() {
16 | }
17 |
18 | public NoHandleInBaseActivityException(final String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public NoHandleInBaseActivityException(final String detailMessage, final Throwable throwable) {
23 | super(detailMessage, throwable);
24 | }
25 |
26 | public NoHandleInBaseActivityException(final Throwable throwable) {
27 | super(throwable);
28 | }
29 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/exceptions/NotAllowedException.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.exceptions;
2 |
3 | /**
4 | * Indicates that our app is not allowed to access some data.
5 | *
6 | * Date: 4/9/2014
7 | * Time: 11:16 AM
8 | *
9 | * @author MiG35
10 | */
11 | public class NotAllowedException extends InternalServerException {
12 |
13 | private static final long serialVersionUID = -4873834503540566594L;
14 |
15 | public NotAllowedException() {
16 | }
17 |
18 | public NotAllowedException(final String detailMessage) {
19 | super(detailMessage);
20 | }
21 |
22 | public NotAllowedException(final String message, final Throwable cause) {
23 | super(message, cause);
24 | }
25 |
26 | public NotAllowedException(final Throwable cause) {
27 | super(cause);
28 | }
29 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/loaders/CollageBigImageLoader.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.loaders;
2 |
3 | import android.content.Context;
4 |
5 | import com.mig35.loaderlib.loaders.DataAsyncTaskLibLoader;
6 | import com.azoft.azoft.collage.data.CollageRegionData;
7 | import com.azoft.azoft.collage.data.Post;
8 | import com.azoft.azoft.collage.exceptions.DiskWriteException;
9 | import com.azoft.azoft.collage.exceptions.InternalServerException;
10 | import com.azoft.azoft.collage.utils.CollageRegion;
11 | import com.azoft.azoft.collage.utils.CommonUtils;
12 |
13 | import java.io.File;
14 | import java.io.FileOutputStream;
15 | import java.net.HttpURLConnection;
16 | import java.net.URL;
17 |
18 | /**
19 | * Will load big image for collage item from the Internet.
20 | * Stores it to external or internal cache dir.
21 | *
22 | * Date: 4/9/2014
23 | * Time: 12:08 PM
24 | *
25 | * @author MiG35
26 | */
27 | public class CollageBigImageLoader extends DataAsyncTaskLibLoader {
28 |
29 | private static final String IMAGE_NAME = "inst_img_%d.jpg";
30 |
31 | private final CollageRegion mCollageRegion;
32 | private final Post mPost;
33 |
34 | public CollageBigImageLoader(final Context context, final CollageRegion collageRegion, final Post post) {
35 | super(context);
36 | if (null == collageRegion || null == post) {
37 | throw new IllegalArgumentException("collageRegion and post can't be null");
38 | }
39 |
40 | mCollageRegion = collageRegion;
41 | mPost = post;
42 | }
43 |
44 | @Override
45 | protected CollageRegionData performLoad() throws Exception {
46 | final File filesDir = CommonUtils.getCacheFileDir();
47 | if (null == filesDir) {
48 | throw new DiskWriteException();
49 | }
50 | final File outputFile = new File(filesDir, String.format(IMAGE_NAME, mCollageRegion.getId()));
51 | if (outputFile.exists() && !outputFile.delete()) {
52 | throw new DiskWriteException();
53 | }
54 |
55 | final HttpURLConnection connection = (HttpURLConnection) new URL(mPost.getStandardResolutionImage().getUrl()).openConnection();
56 |
57 | connection.setUseCaches(true);
58 | final int responseCode = connection.getResponseCode();
59 | if (responseCode >= 300) {
60 | connection.disconnect();
61 | throw new InternalServerException();
62 | }
63 |
64 | CommonUtils.writeNetworkStreamToAnOtherStream(connection.getInputStream(), new FileOutputStream(outputFile));
65 | connection.disconnect();
66 |
67 | if (outputFile.exists()) {
68 | return new CollageRegionData(outputFile);
69 | } else {
70 | throw new DiskWriteException();
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/loaders/CollagePreviewCreatorLoader.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.loaders;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 |
8 | import com.azoft.azoft.collage.R;
9 | import com.azoft.azoft.collage.data.CollageFillData;
10 | import com.azoft.azoft.collage.data.CollageRegionData;
11 | import com.azoft.azoft.collage.exceptions.CollageCreationException;
12 | import com.azoft.azoft.collage.utils.CollageRegion;
13 | import com.azoft.azoft.collage.utils.MediaUtils;
14 | import com.mig35.loaderlib.loaders.DataAsyncTaskLibLoader;
15 |
16 | import java.io.File;
17 | import java.util.HashMap;
18 | import java.util.Map;
19 |
20 | /**
21 | * Construct result image. And store it to internal directory and return its path in FileProvider.
22 | *
23 | * Date: 4/9/2014
24 | * Time: 6:19 PM
25 | *
26 | * @author MiG35
27 | */
28 | public class CollagePreviewCreatorLoader extends DataAsyncTaskLibLoader {
29 |
30 | private final CollageFillData mCollageFillData;
31 |
32 | public CollagePreviewCreatorLoader(final Context context, final CollageFillData collageFillData) {
33 | super(context);
34 | if (null == collageFillData) {
35 | throw new IllegalArgumentException("collageFillData can't be null");
36 | }
37 |
38 | mCollageFillData = collageFillData;
39 | }
40 |
41 | @Override
42 | protected String performLoad() throws Exception {
43 | final Map collageDataMap = new HashMap<>();
44 |
45 | int maxSize = 0; // we need to know our result image size (as biggest image size).
46 | for (final CollageRegion collageRegion : mCollageFillData.getCollageRegions()) {
47 | final CollageRegionData regionData = mCollageFillData.getRegionData(collageRegion);
48 | maxSize = Math.max(maxSize, getImageSize(regionData.getImageFile()));
49 | collageDataMap.put(collageRegion, regionData);
50 | }
51 |
52 | int sampleSize = 1;
53 | Bitmap outBitmap = null;
54 | do {
55 | try {
56 | outBitmap = Bitmap.createBitmap(maxSize / sampleSize, maxSize / sampleSize, Bitmap.Config.ARGB_8888);
57 |
58 | final Canvas canvas = new Canvas(outBitmap);
59 | canvas.drawColor(getContext().getResources().getColor(R.color.collage_bg_color));
60 |
61 | for (final Map.Entry entryItem : collageDataMap.entrySet()) {
62 | drawCollageRegionOnCanvas(canvas, entryItem.getKey(), entryItem.getValue());
63 | }
64 | break;
65 | } catch (final OutOfMemoryError thr) {
66 | sampleSize *= 2;
67 | if (null != outBitmap) {
68 | outBitmap.recycle();
69 | }
70 | outBitmap = null;
71 | }
72 | } while (sampleSize < 100);
73 |
74 | if (null == outBitmap) {
75 | throw new CollageCreationException(new OutOfMemoryError());
76 | }
77 | try {
78 | return MediaUtils.insertImage(outBitmap, getContext().getString(R.string.text_image_collage_preview));
79 | } finally {
80 | outBitmap.recycle();
81 | }
82 | }
83 |
84 | private void drawCollageRegionOnCanvas(final Canvas canvas, final CollageRegion collageRegion, final CollageRegionData collageRegionData) throws CollageCreationException {
85 | for (int sampleSize = 1; sampleSize < 100; sampleSize *= 2) {
86 | try {
87 | drawCollageRegionOnCanvasOld(canvas, collageRegion, collageRegionData, sampleSize);
88 | return;
89 | } catch (final OutOfMemoryError error) {
90 | // pass
91 | }
92 | }
93 | throw new OutOfMemoryError();
94 | }
95 |
96 | private void drawCollageRegionOnCanvasOld(final Canvas canvas, final CollageRegion collageRegion, final CollageRegionData collageRegionData, final int sampleSize)
97 | throws CollageCreationException {
98 | // region visible width and height
99 | final int regionWidth = (int) (canvas.getWidth() * collageRegion.getWidth());
100 | final int regionHeight = (int) (canvas.getWidth() * collageRegion.getHeight());
101 |
102 | final BitmapFactory.Options options = new BitmapFactory.Options();
103 | options.inSampleSize = sampleSize;
104 | final Bitmap regionDecodedBitmap = BitmapFactory.decodeFile(collageRegionData.getImageFile().getAbsolutePath(), options);
105 | if (null == regionDecodedBitmap) {
106 | throw new CollageCreationException();
107 | }
108 | final Bitmap memoryOptimizedDecodedBitmap;
109 | if (regionDecodedBitmap.getWidth() == regionWidth && regionDecodedBitmap.getHeight() == regionHeight) {
110 | // decoded bitmap is the same as our region. nothing to do more
111 | memoryOptimizedDecodedBitmap = regionDecodedBitmap;
112 | } else {
113 | // we should make our decoded bitmap scaled for region. because region may be not square we use it's max size
114 | final float imageScale = Math.max(1f * regionWidth / regionDecodedBitmap.getWidth(), 1f * regionHeight / regionDecodedBitmap.getHeight());
115 | final Bitmap tmp = Bitmap.createScaledBitmap(regionDecodedBitmap, Math.round(imageScale * regionDecodedBitmap.getWidth()), Math
116 | .round(imageScale * regionDecodedBitmap.getHeight()), true);
117 | if (tmp != regionDecodedBitmap) {
118 | regionDecodedBitmap.recycle();
119 | }
120 | if (null == tmp) {
121 | memoryOptimizedDecodedBitmap = null;
122 | } else {
123 | memoryOptimizedDecodedBitmap = tmp;
124 | }
125 | }
126 | if (null == memoryOptimizedDecodedBitmap) {
127 | throw new CollageCreationException();
128 | }
129 | final float scale = collageRegionData.getImageScale();
130 | final float left = collageRegionData.getImageLeft() == null ? 0 : collageRegionData.getImageLeft();
131 | final float top = collageRegionData.getImageTop() == null ? 0 : collageRegionData.getImageTop();
132 |
133 | // we should crop image to be exactly as our scaled region (then we should scale it upper)
134 | final Bitmap scaledResultBitmap =
135 | Bitmap.createBitmap(memoryOptimizedDecodedBitmap, (int) (left * (memoryOptimizedDecodedBitmap.getWidth() - regionWidth / scale)),
136 | (int) (top * (memoryOptimizedDecodedBitmap.getHeight() - regionHeight / scale)), (int) (regionWidth / scale),
137 | (int) (regionHeight / scale));
138 | if (scaledResultBitmap != memoryOptimizedDecodedBitmap) {
139 | memoryOptimizedDecodedBitmap.recycle();
140 | }
141 | final Bitmap resultBitmap = Bitmap.createScaledBitmap(scaledResultBitmap, regionWidth, regionHeight, true);
142 | if (resultBitmap != scaledResultBitmap) {
143 | scaledResultBitmap.recycle();
144 | }
145 |
146 | canvas.drawBitmap(resultBitmap, (int) (collageRegion.getLeft() * canvas.getWidth()), (int) (collageRegion.getTop() * canvas.getHeight()),
147 | null);
148 | resultBitmap.recycle();
149 | }
150 |
151 | private int getImageSize(final File imageFile) {
152 | final BitmapFactory.Options options = new BitmapFactory.Options();
153 | options.inJustDecodeBounds = true;
154 | BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
155 | return Math.max(options.outWidth, options.outHeight);
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/loaders/UserDataLoader.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.loaders;
2 |
3 | import android.content.Context;
4 |
5 | import com.mig35.loaderlib.loaders.DataAsyncTaskLibLoader;
6 | import com.azoft.azoft.collage.data.User;
7 | import com.azoft.azoft.collage.data.results.UserDataResult;
8 | import com.azoft.azoft.collage.exceptions.InternalServerException;
9 | import com.azoft.azoft.collage.server.RetrofitHelper;
10 | import com.azoft.azoft.collage.server.ServerConnector;
11 | import com.azoft.azoft.collage.server.responces.UserRecentFeedResponse;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Date: 4/11/2014
17 | * Time: 3:54 PM
18 | *
19 | * @author MiG35
20 | */
21 | public class UserDataLoader extends DataAsyncTaskLibLoader {
22 |
23 | private final User mUser;
24 | private final String mAccessToken;
25 |
26 | public UserDataLoader(final Context context, final User user, final String accessToken) {
27 | super(context);
28 |
29 | mUser = user;
30 | mAccessToken = accessToken;
31 | }
32 |
33 | @Override
34 | protected UserDataResult performLoad() throws Exception {
35 | try {
36 | final UserRecentFeedResponse response = ServerConnector.getInstagramService().getUserRecentFeed(mUser.getId(), 1, mAccessToken);
37 | if (null == response) {
38 | throw new InternalServerException("Response is null");
39 | }
40 | final List postItems = response.getPostItems();
41 | if (null == postItems || postItems.isEmpty()) {
42 | return UserDataResult.getHasNoData(mUser);
43 | } else {
44 | return UserDataResult.getHasData(mUser);
45 | }
46 | } catch (final InternalServerException e) {
47 | // we should check is we don't have access to view user's posts. if so, we shouldn't try to load again
48 | if (RetrofitHelper.isAccessDeniedException(e)) {
49 | return UserDataResult.getNotAllowed(mUser);
50 | }
51 | throw e;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/loaders/UserImageFeedLoader.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.loaders;
2 |
3 | import android.content.Context;
4 |
5 | import com.mig35.loaderlib.exceptions.NoNetworkException;
6 | import com.mig35.loaderlib.loaders.DataAsyncTaskLibLoader;
7 | import com.azoft.azoft.collage.data.Image;
8 | import com.azoft.azoft.collage.data.Post;
9 | import com.azoft.azoft.collage.data.results.UserRecentFeedResult;
10 | import com.azoft.azoft.collage.exceptions.InternalServerException;
11 | import com.azoft.azoft.collage.exceptions.NotAllowedException;
12 | import com.azoft.azoft.collage.server.RetrofitHelper;
13 | import com.azoft.azoft.collage.server.ServerConnector;
14 | import com.azoft.azoft.collage.server.responces.UserRecentFeedResponse;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Collections;
18 | import java.util.List;
19 |
20 | /**
21 | * Will load last user's images posts. Has tries and feeds count parameters as static in this class.
22 | *
23 | * Date: 4/9/2014
24 | * Time: 9:29 AM
25 | *
26 | * @author MiG35
27 | */
28 | public class UserImageFeedLoader extends DataAsyncTaskLibLoader {
29 |
30 | private static final int TRIES_COUNT = 3;
31 | private static final int FEED_COUNT = 100;
32 | private static final String IMAGE_POST_TYPE_STRING = "image";
33 |
34 | private final String mUserId;
35 | private final String mAccessToken;
36 |
37 | public UserImageFeedLoader(final Context context, final String userId, final String accessToken) {
38 | super(context);
39 |
40 | mUserId = userId;
41 | mAccessToken = accessToken;
42 | }
43 |
44 | @Override
45 | protected UserRecentFeedResult performLoad() throws Exception {
46 | final List posts = new ArrayList<>();
47 | loadPosts(posts);
48 | Collections.sort(posts);
49 | return new UserRecentFeedResult(mUserId, posts);
50 | }
51 |
52 | private void loadPosts(final List posts) throws Exception {
53 | String currentMaxId = null;
54 |
55 | do {
56 | final UserRecentFeedResponse response = getUserRecentFeedResponse(currentMaxId);
57 |
58 | final UserRecentFeedResponse.Pagination pagination = response.getPagination();
59 | final List postItems = response.getPostItems();
60 | if (null != postItems) {
61 | for (final UserRecentFeedResponse.PostItem postItem : postItems) {
62 | if (IMAGE_POST_TYPE_STRING.equals(postItem.getType())) {
63 | final Post post = convertToPost(postItem);
64 | if (null != post && posts.size() < FEED_COUNT) {
65 | posts.add(post);
66 | }
67 | }
68 | }
69 | }
70 | currentMaxId = null == pagination ? null : pagination.getNextMaxId();
71 | } while (posts.size() < FEED_COUNT && null != currentMaxId);
72 | }
73 |
74 | private UserRecentFeedResponse getUserRecentFeedResponse(final String currentMaxId) throws Exception {
75 | Exception exception = new InternalServerException("Response is null");
76 | // because some times Internet is not good we should try to load this data some times, because this data is important.
77 | for (int i = 0; i < TRIES_COUNT; ++i) {
78 | try {
79 | final UserRecentFeedResponse response;
80 | if (null == currentMaxId) {
81 | response = ServerConnector.getInstagramService().getUserRecentFeed(mUserId, FEED_COUNT, mAccessToken);
82 | } else {
83 | response = ServerConnector.getInstagramService().getUserRecentFeed(mUserId, FEED_COUNT, currentMaxId, mAccessToken);
84 | }
85 | if (null != response) {
86 | return response;
87 | }
88 | } catch (final NoNetworkException e) {
89 | exception = e;
90 | } catch (final InternalServerException e) {
91 | exception = e;
92 | // we should check is we don't have access to view user's posts. if so, we shouldn't try to load again
93 | if (RetrofitHelper.isAccessDeniedException(e)) {
94 | throw new NotAllowedException(e);
95 | }
96 | }
97 | }
98 | // we have an error. throw it!
99 | throw exception;
100 | }
101 |
102 | private Post convertToPost(final UserRecentFeedResponse.PostItem postItem) {
103 | final UserRecentFeedResponse.PostImages postItemImages = postItem.getPostImages();
104 | if (null == postItemImages || !postItemImages.hasAllImages() || !postItemImages.hasDataInAllImages()) {
105 | // we need only images posts
106 | return null;
107 | }
108 | final int likesCount = null == postItem.getLikes() ? 0 : postItem.getLikes().getCount();
109 |
110 | return new Post(postItem.getId(), postItem.getType(), likesCount, convertToImage(postItemImages.getThumbnailImage()),
111 | convertToImage(postItemImages.getLowResolutionImage()), convertToImage(postItemImages.getStandardResolutionImage()));
112 | }
113 |
114 | private Image convertToImage(final UserRecentFeedResponse.PostImage postImage) {
115 | if (null == postImage) {
116 | return null;
117 | }
118 |
119 | return new Image(postImage.getWidth(), postImage.getHeight(), postImage.getUrl());
120 | }
121 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/loaders/UsersSearchLoader.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.loaders;
2 |
3 | import android.content.Context;
4 |
5 | import com.mig35.loaderlib.loaders.DataAsyncTaskLibLoader;
6 | import com.azoft.azoft.collage.data.results.UsersSearchResult;
7 | import com.azoft.azoft.collage.exceptions.InternalServerException;
8 | import com.azoft.azoft.collage.server.ServerConnector;
9 | import com.azoft.azoft.collage.server.responces.SearchUserResponse;
10 |
11 | /**
12 | * Will load users with parameter nickName
13 | *
14 | * Date: 4/8/2014
15 | * Time: 11:39 AM
16 | *
17 | * @author MiG35
18 | */
19 | public class UsersSearchLoader extends DataAsyncTaskLibLoader {
20 |
21 | private final String mNickName;
22 | private final String mAccessToken;
23 |
24 | public UsersSearchLoader(final Context context, final String nickName, final String accessToken) {
25 | super(context);
26 |
27 | mNickName = nickName;
28 | mAccessToken = accessToken;
29 | }
30 |
31 | @Override
32 | protected UsersSearchResult performLoad() throws Exception {
33 | final SearchUserResponse response = ServerConnector.getInstagramService().searchUser(mNickName, mAccessToken);
34 | if (null == response) {
35 | throw new InternalServerException("Response is null");
36 | }
37 | return new UsersSearchResult(mNickName, response.getUsers());
38 | }
39 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/server/InstagramService.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.server;
2 |
3 | import com.azoft.azoft.collage.server.responces.SearchUserResponse;
4 | import com.azoft.azoft.collage.server.responces.UserRecentFeedResponse;
5 |
6 | import retrofit.http.GET;
7 | import retrofit.http.Path;
8 | import retrofit.http.Query;
9 |
10 | /**
11 | * Date: 4/8/2014
12 | * Time: 2:28 PM
13 | *
14 | * @author MiG35
15 | */
16 | @SuppressWarnings("InterfaceNeverImplemented")
17 | public interface InstagramService {
18 |
19 | @GET("/users/search")
20 | SearchUserResponse searchUser(@Query("q") final String query, @Query("access_token") final String accessToken) throws Exception;
21 |
22 | @GET("/users/{user-id}/media/recent")
23 | UserRecentFeedResponse getUserRecentFeed(@Path("user-id") final String userId, @Query("count") final int count, @Query("access_token") final String accessToken) throws Exception;
24 |
25 | @GET("/users/{user-id}/media/recent")
26 | UserRecentFeedResponse getUserRecentFeed(@Path("user-id") final String userId, @Query("count") final int count,
27 | @Query("max_id") final String maxId, @Query("access_token") final String accessToken) throws Exception;
28 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/server/RetrofitHelper.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.server;
2 |
3 | import com.azoft.azoft.collage.exceptions.InternalServerException;
4 |
5 | import retrofit.RetrofitError;
6 | import retrofit.client.Response;
7 |
8 | /**
9 | * Date: 4/11/2014
10 | * Time: 3:57 PM
11 | *
12 | * @author MiG35
13 | */
14 | public final class RetrofitHelper {
15 |
16 | private static final int NOT_ALLOWED = 400;
17 |
18 | private RetrofitHelper() {
19 | }
20 |
21 | public static boolean isAccessDeniedException(final InternalServerException exception) {
22 | if (null == exception) {
23 | return false;
24 | }
25 | // we should check is we don't have access to view user's posts. if so, we shouldn't try to load again
26 | final Throwable cause = exception.getCause();
27 | if (cause instanceof RetrofitError) {
28 | final Response response = ((RetrofitError) cause).getResponse();
29 | if (null != response && response.getStatus() == NOT_ALLOWED) {
30 | return true;
31 | }
32 | }
33 | return false;
34 | }
35 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/server/ServerConnector.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.server;
2 |
3 | import com.google.gson.FieldNamingPolicy;
4 | import com.google.gson.Gson;
5 | import com.google.gson.GsonBuilder;
6 | import com.mig35.loaderlib.exceptions.NoNetworkException;
7 | import com.azoft.azoft.collage.exceptions.InternalServerException;
8 | import com.squareup.okhttp.OkHttpClient;
9 |
10 | import java.util.concurrent.TimeUnit;
11 |
12 | import retrofit.ErrorHandler;
13 | import retrofit.RestAdapter;
14 | import retrofit.RetrofitError;
15 | import retrofit.converter.GsonConverter;
16 |
17 | /**
18 | * Contains all service components such as Instgram and general Http Client. Thread safe singleton.
19 | *
20 | * Date: 6/28/13
21 | * Time: 7:24 PM
22 | *
23 | * @author MiG35
24 | */
25 | public final class ServerConnector {
26 |
27 | private static final String SERVER_URL = "https://api.instagram.com";
28 | private static final String VERSION = "/v1";
29 | private static final String SERVER_URL_WITH_VERSION = SERVER_URL + VERSION;
30 |
31 | private static final long TIMEOUT_TIME = 10;
32 |
33 | private final InstagramService mInstagramService;
34 | private final OkHttpClient mOkHttpClient;
35 |
36 | private ServerConnector() {
37 | final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.IDENTITY).create();
38 |
39 | final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(SERVER_URL_WITH_VERSION).setConverter(new GsonConverter(gson))
40 | .setErrorHandler(new ErrorHandler() {
41 | @Override
42 | public Throwable handleError(final RetrofitError cause) {
43 | if (RetrofitError.Kind.NETWORK == cause.getKind()) {
44 | return new NoNetworkException();
45 | } else {
46 | return new InternalServerException(cause);
47 | }
48 | }
49 | }).build();
50 |
51 | mInstagramService = restAdapter.create(InstagramService.class);
52 |
53 | mOkHttpClient = new OkHttpClient();
54 | mOkHttpClient.setConnectTimeout(TIMEOUT_TIME, TimeUnit.SECONDS);
55 | mOkHttpClient.setReadTimeout(TIMEOUT_TIME, TimeUnit.SECONDS);
56 | }
57 |
58 | public static InstagramService getInstagramService() {
59 | return Holder.SERVER_CONNECTOR.mInstagramService;
60 | }
61 |
62 | public static OkHttpClient getOkHttpClient() {
63 | return Holder.SERVER_CONNECTOR.mOkHttpClient;
64 | }
65 |
66 | private static final class Holder {
67 |
68 | private static final ServerConnector SERVER_CONNECTOR = new ServerConnector();
69 | }
70 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/server/responces/SearchUserResponse.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.server.responces;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.azoft.azoft.collage.data.User;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Date: 4/8/2014
10 | * Time: 2:38 PM
11 | *
12 | * @author MiG35
13 | */
14 | public class SearchUserResponse {
15 |
16 | @SerializedName("data")
17 | private List mUsers;
18 |
19 | public List getUsers() {
20 | return mUsers;
21 | }
22 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/server/responces/UserRecentFeedResponse.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.server.responces;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Date: 4/9/2014
9 | * Time: 9:34 AM
10 | *
11 | * @author MiG35
12 | */
13 | public class UserRecentFeedResponse {
14 |
15 | @SerializedName("pagination")
16 | private Pagination mPagination;
17 | @SerializedName("data")
18 | private List mPostItems;
19 |
20 | public Pagination getPagination() {
21 | return mPagination;
22 | }
23 |
24 | public List getPostItems() {
25 | return mPostItems;
26 | }
27 |
28 | public static class Pagination {
29 |
30 | @SerializedName("next_url")
31 | private String mNextUrl;
32 | @SerializedName("next_max_id")
33 | private String mNextMaxId;
34 |
35 | public String getNextUrl() {
36 | return mNextUrl;
37 | }
38 |
39 | public String getNextMaxId() {
40 | return mNextMaxId;
41 | }
42 | }
43 |
44 | public static class PostItem {
45 |
46 | @SerializedName("type")
47 | private String mType;
48 | @SerializedName("id")
49 | private String mId;
50 | @SerializedName("likes")
51 | private Likes mLikes;
52 | @SerializedName("images")
53 | private PostImages mPostImages;
54 |
55 | public String getType() {
56 | return mType;
57 | }
58 |
59 | public String getId() {
60 | return mId;
61 | }
62 |
63 | public PostImages getPostImages() {
64 | return mPostImages;
65 | }
66 |
67 | public Likes getLikes() {
68 | return mLikes;
69 | }
70 | }
71 |
72 | public static class Likes {
73 |
74 | @SerializedName("count")
75 | private int mCount;
76 |
77 | public int getCount() {
78 | return mCount;
79 | }
80 | }
81 |
82 | public static class PostImages {
83 |
84 | @SerializedName("low_resolution")
85 | private PostImage mLowResolutionImage;
86 | @SerializedName("thumbnail")
87 | private PostImage mThumbnailImage;
88 | @SerializedName("standard_resolution")
89 | private PostImage mStandardResolutionImage;
90 |
91 | public PostImage getLowResolutionImage() {
92 | return mLowResolutionImage;
93 | }
94 |
95 | public PostImage getThumbnailImage() {
96 | return mThumbnailImage;
97 | }
98 |
99 | public PostImage getStandardResolutionImage() {
100 | return mStandardResolutionImage;
101 | }
102 |
103 | public boolean hasAllImages() {
104 | return null != mLowResolutionImage && null != mThumbnailImage && null != mStandardResolutionImage;
105 | }
106 |
107 | public boolean hasDataInAllImages() {
108 | return mLowResolutionImage.hasData() && mThumbnailImage.hasData() && mStandardResolutionImage.hasData();
109 | }
110 | }
111 |
112 | public static class PostImage {
113 |
114 | @SerializedName("url")
115 | private String mUrl;
116 | @SerializedName("width")
117 | private int mWidth;
118 | @SerializedName("height")
119 | private int mHeight;
120 |
121 | public String getUrl() {
122 | return mUrl;
123 | }
124 |
125 | public int getWidth() {
126 | return mWidth;
127 | }
128 |
129 | public int getHeight() {
130 | return mHeight;
131 | }
132 |
133 | public boolean hasData() {
134 | return 0 != mWidth && 0 != mHeight && null != mUrl;
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/CollageActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.view.Window;
6 |
7 | import com.azoft.azoft.collage.R;
8 | import com.azoft.azoft.collage.app.CollageApplication;
9 | import com.azoft.azoft.collage.exceptions.DiskWriteException;
10 | import com.azoft.azoft.collage.exceptions.NoHandleInBaseActivityException;
11 | import com.azoft.azoft.collage.exceptions.NotAllowedException;
12 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
13 | import com.mig35.injectorlib.utils.inject.Injector;
14 | import com.mig35.loaderlib.exceptions.NoNetworkException;
15 | import com.mig35.loaderlib.utils.ActivityLoaderHelper;
16 | import com.mig35.loaderlib.utils.ActivityLoaderListener;
17 | import com.mig35.loaderlib.utils.FragmentToActivityLoaderTaskListener;
18 | import com.mig35.loaderlib.utils.LoaderHelper;
19 |
20 | /**
21 | * Base Activity class with action bar.
22 | *
23 | * Date: 4/8/2014
24 | * Time: 11:01 AM
25 | *
26 | * @author MiG35
27 | */
28 | public abstract class CollageActivity extends AppCompatActivity implements ActivityLoaderListener {
29 |
30 | private Injector mInjector;
31 |
32 | @InjectSavedState
33 | private ActivityLoaderHelper mActivityLoaderHelper;
34 |
35 | @Override
36 | protected void onCreate(final Bundle savedInstanceState) {
37 | mInjector = Injector.init(this);
38 |
39 | mInjector.applyOnActivityCreate(this, savedInstanceState);
40 |
41 | if (null == mActivityLoaderHelper) {
42 | mActivityLoaderHelper = new ActivityLoaderHelper();
43 | }
44 |
45 | super.onCreate(savedInstanceState);
46 |
47 | mActivityLoaderHelper.onCreate(this);
48 |
49 | supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
50 | }
51 |
52 | @Override
53 | public void onContentChanged() {
54 | super.onContentChanged();
55 |
56 | mInjector.applyOnActivityContentChange(this);
57 | }
58 |
59 | @Override
60 | protected void onStart() {
61 | mActivityLoaderHelper.onStart();
62 |
63 | super.onStart();
64 | }
65 |
66 | @Override
67 | protected void onResumeFragments() {
68 | super.onResumeFragments();
69 |
70 | mActivityLoaderHelper.onResumeFragments();
71 | }
72 |
73 | @Override
74 | protected void onDestroy() {
75 | super.onDestroy();
76 |
77 | mActivityLoaderHelper.onDestroy();
78 | mInjector.applyOnActivityDestroy(this);
79 | }
80 |
81 | @Override
82 | protected void onSaveInstanceState(final Bundle outState) {
83 | super.onSaveInstanceState(outState);
84 |
85 | mActivityLoaderHelper.onSaveInstanceState();
86 | mInjector.applyOnActivitySaveInstanceState(this, outState);
87 | }
88 |
89 | @Override
90 | protected void onPause() {
91 | super.onPause();
92 |
93 | mActivityLoaderHelper.onPause();
94 | }
95 |
96 | @Override
97 | protected void onStop() {
98 | super.onStop();
99 |
100 | mActivityLoaderHelper.onStop();
101 | }
102 |
103 | @Override
104 | public void showProgress(final boolean hasRunningLoaders) {
105 | // nothing to see here
106 | }
107 |
108 | @Override
109 | public void onLoaderResult(final int id, final Object result) {
110 | // nothing to see here
111 | }
112 |
113 | @Override
114 | public void onLoaderError(final int id, final Exception exception) {
115 | // general base activity exception handle
116 | if (exception instanceof NoNetworkException) {
117 | showToast(R.string.error_no_network);
118 | } else if (exception instanceof NotAllowedException) {
119 | showToast(R.string.error_not_allowed);
120 | } else if (exception instanceof DiskWriteException) {
121 | showToast(R.string.error_disk_error);
122 | } else if (!(exception instanceof NoHandleInBaseActivityException)) {
123 | showToast(R.string.error_unknown);
124 | }
125 | }
126 |
127 | public void showToast(final int toastMessage, final int gravity) {
128 | showToast(getString(toastMessage), gravity);
129 | }
130 |
131 | public void showToast(final int toastMessage) {
132 | showToast(getString(toastMessage));
133 | }
134 |
135 | public void showToast(final String message) {
136 | if (null == message) {
137 | return;
138 | }
139 |
140 | CollageApplication.getInstance().showToast(message, null);
141 | }
142 |
143 | private void showToast(final String message, final int gravity) {
144 | if (null == message) {
145 | return;
146 | }
147 |
148 | CollageApplication.getInstance().showToast(message, gravity);
149 | }
150 |
151 | @Override
152 | public LoaderHelper getLoaderHelper() {
153 | return mActivityLoaderHelper;
154 | }
155 |
156 | @Override
157 | public void addLoaderListener(final FragmentToActivityLoaderTaskListener loaderTaskListener) {
158 | mActivityLoaderHelper.addLoaderListener(loaderTaskListener);
159 | }
160 |
161 | @Override
162 | public void removeLoaderListener(final FragmentToActivityLoaderTaskListener loaderFragment) {
163 | mActivityLoaderHelper.removeLoaderListener(loaderFragment);
164 | }
165 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/CollageAuthActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.view.MenuItem;
8 |
9 | public abstract class CollageAuthActivity extends CollageActivity {
10 |
11 | private static final String EXTRA_ACCESS_TOKEN = "com.azoft.azoft.collage.ui.activities.phone.CollageAuthActivity.EXTRA_ACCESS_TOKEN";
12 |
13 | public static Intent createIntent(final Context context, final Class extends CollageAuthActivity> activityClass, final String accessToken) {
14 | return new Intent(context, activityClass).putExtra(EXTRA_ACCESS_TOKEN, accessToken);
15 | }
16 |
17 | public static Intent createIntent(final CollageAuthActivity collageAuthActivity, final Class extends CollageAuthActivity> activityClass) {
18 | return new Intent(collageAuthActivity, activityClass).putExtra(EXTRA_ACCESS_TOKEN, collageAuthActivity.getIntent().getStringExtra(EXTRA_ACCESS_TOKEN));
19 | }
20 |
21 | protected String mAccessToken;
22 |
23 | @Override
24 | protected final void onCreate(final Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 |
27 | mAccessToken = getIntent().getStringExtra(EXTRA_ACCESS_TOKEN);
28 | if (null == mAccessToken) {
29 | finish();
30 | } else {
31 | onCreate(savedInstanceState, mAccessToken);
32 | }
33 | }
34 |
35 | public String getAccessToken() {
36 | return mAccessToken;
37 | }
38 |
39 | @Override
40 | public boolean onOptionsItemSelected(final MenuItem item) {
41 | if (item.getItemId() == android.R.id.home) {
42 | // should return to start activity and clear all others
43 | final Intent intent = CollageAuthActivity.createIntent(this, StartActivity.class);
44 |
45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
46 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
47 | } else {
48 | intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
49 | }
50 |
51 | startActivity(intent);
52 | return true;
53 | }
54 | return super.onOptionsItemSelected(item);
55 | }
56 |
57 | protected abstract void onCreate(final Bundle savedInstanceState, final String accessToken);
58 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/CollageBuilderActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | import com.azoft.azoft.collage.data.Collage;
6 | import com.azoft.azoft.collage.data.User;
7 | import com.azoft.azoft.collage.ui.fragments.CollageBuilderFragment;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * Date: 4/8/2014
13 | * Time: 6:38 PM
14 | *
15 | * @author MiG35
16 | */
17 | public class CollageBuilderActivity extends SingleFragmentActivity {
18 |
19 | public static final String EXTRA_USER = "com.redmadrobot.azoft.collage.ui.activities.phone.CollageBuilderActivity.EXTRA_USER";
20 | public static final String EXTRA_KOLAJ = "com.redmadrobot.azoft.collage.ui.activities.phone.CollageBuilderActivity.EXTRA_KOLAJ";
21 |
22 | @Override
23 | protected Fragment createFragment() {
24 | final Serializable user = getIntent().getSerializableExtra(EXTRA_USER);
25 | final Serializable collage = getIntent().getSerializableExtra(EXTRA_KOLAJ);
26 | if (user instanceof User && collage instanceof Collage) {
27 | return CollageBuilderFragment.getInstance((User) user, (Collage) collage);
28 | }
29 | return null;
30 | }
31 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/CollagePreviewActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | import com.azoft.azoft.collage.data.CollageFillData;
6 | import com.azoft.azoft.collage.ui.fragments.CollagePreviewFragment;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * Date: 4/9/2014
12 | * Time: 5:56 PM
13 | *
14 | * @author MiG35
15 | */
16 | public class CollagePreviewActivity extends SingleFragmentActivity {
17 |
18 | public static final String EXTRA_KOLAJ_FILL_DATA =
19 | "com.redmadrobot.azoft.collage.ui.activities.phone.CollagePreviewActivity.EXTRA_KOLAJ_FILL_DATA";
20 |
21 | @Override
22 | protected Fragment createFragment() {
23 | final Serializable collageFillData = getIntent().getSerializableExtra(EXTRA_KOLAJ_FILL_DATA);
24 | if (collageFillData instanceof CollageFillData) {
25 | return CollagePreviewFragment.getInstance((CollageFillData) collageFillData);
26 | }
27 | return null;
28 | }
29 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/ImageSelectionFromUserFeedActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.content.Intent;
4 | import android.support.v4.app.Fragment;
5 |
6 | import com.azoft.azoft.collage.data.Post;
7 | import com.azoft.azoft.collage.data.User;
8 | import com.azoft.azoft.collage.ui.fragments.ImageSelectionFromUserFeedFragment;
9 |
10 | import java.io.Serializable;
11 |
12 | /**
13 | * Date: 4/8/2014
14 | * Time: 7:03 PM
15 | *
16 | * @author MiG35
17 | */
18 | public class ImageSelectionFromUserFeedActivity extends SingleFragmentActivity implements ImageSelectionFromUserFeedFragment.PostSelectionListener {
19 |
20 | public static final String RESULT_POST = "com.redmadrobot.azoft.collage.ui.fragments.ImageSelectionFromUserFeedFragment.RESULT_POST";
21 |
22 | public static final String EXTRA_USER = "com.redmadrobot.azoft.collage.ui.activities.phone.ImageSelectionFromUserFeedActivity.EXTRA_USER";
23 |
24 | @Override
25 | protected Fragment createFragment() {
26 | final Serializable user = getIntent().getSerializableExtra(EXTRA_USER);
27 | if (user instanceof User) {
28 | return ImageSelectionFromUserFeedFragment.getInstance((User) user);
29 | }
30 | return null;
31 | }
32 |
33 | @Override
34 | public void onPostSelected(final Post post) {
35 | final Intent intent = new Intent();
36 | intent.putExtra(RESULT_POST, post);
37 | setResult(RESULT_OK, intent);
38 | finish();
39 | }
40 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/InstagramAuthActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.webkit.CookieManager;
8 | import android.webkit.CookieSyncManager;
9 | import android.webkit.WebSettings;
10 | import android.webkit.WebView;
11 | import android.webkit.WebViewClient;
12 |
13 | import com.azoft.azoft.collage.R;
14 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
15 | import com.mig35.injectorlib.utils.inject.InjectView;
16 |
17 | public class InstagramAuthActivity extends CollageActivity {
18 |
19 | private static final String REDIRECT_URL = "http://www.azoft.com/";
20 | private static final String CLIENT_ID = "2679711ad9b14dd3afa52c5c35acb5cd";
21 | private static final String ACCESS_TOKEN_URL_PATH = "#access_token=";
22 |
23 | private static final String START_URL = "https://api.instagram.com/oauth/authorize/?client_id=%1$s&redirect_uri=%2$s&response_type=token&scope=public_content";
24 |
25 | @InjectView(R.id.web_view)
26 | private WebView mWebView;
27 | @InjectView(R.id.progress_bar)
28 | private View mProgressView;
29 |
30 | @InjectSavedState
31 | private Bundle mWebViewState;
32 |
33 | @Override
34 | protected void onCreate(final Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 |
37 | setContentView(R.layout.activity_instagram_auth);
38 |
39 | initWebView(null == savedInstanceState);
40 |
41 | mWebView.setWebViewClient(new AuthWebClient());
42 |
43 | if (null == mWebViewState) {
44 | mWebView.loadUrl(String.format(START_URL, CLIENT_ID, REDIRECT_URL));
45 | } else {
46 | mWebView.restoreState(mWebViewState);
47 | }
48 | }
49 |
50 | private void onTokenGranted(final String accessToken) {
51 | startActivity(CollageAuthActivity.createIntent(this, StartActivity.class, accessToken));
52 | }
53 |
54 | private void onTokenFailed() {
55 | showToast(R.string.error_no_access_token_instagram);
56 | initWebView(true);
57 | mWebView.loadUrl(String.format(START_URL, CLIENT_ID, REDIRECT_URL));
58 | }
59 |
60 | private void initWebView(final boolean clearSetup) {
61 | final WebSettings settings = mWebView.getSettings();
62 |
63 | settings.setJavaScriptEnabled(true);
64 | settings.setDomStorageEnabled(true);
65 | settings.setAppCacheEnabled(true);
66 | settings.setSaveFormData(false);
67 |
68 | if (clearSetup) {
69 | mWebView.clearCache(true);
70 | mWebView.clearHistory();
71 | clearCookies();
72 | }
73 | }
74 |
75 | @Override
76 | protected void onSaveInstanceState(final Bundle outState) {
77 | mWebViewState = new Bundle();
78 | mWebView.saveState(mWebViewState);
79 | super.onSaveInstanceState(outState);
80 | }
81 |
82 | @Override
83 | public void onBackPressed() {
84 | if (mWebView.canGoBack()) {
85 | mWebView.goBack();
86 | } else {
87 | super.onBackPressed();
88 | }
89 | }
90 |
91 | @SuppressWarnings("deprecation")
92 | public void clearCookies() {
93 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
94 | CookieManager.getInstance().removeAllCookies(null);
95 | CookieManager.getInstance().flush();
96 | } else {
97 | final CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(this);
98 | cookieSyncManager.startSync();
99 | final CookieManager cookieManager = CookieManager.getInstance();
100 | cookieManager.removeAllCookie();
101 | cookieManager.removeSessionCookie();
102 | cookieSyncManager.stopSync();
103 | cookieSyncManager.sync();
104 | }
105 | }
106 |
107 | private class AuthWebClient extends WebViewClient {
108 |
109 | @Override
110 | public void onPageStarted(final WebView view, final String url, final Bitmap favicon) {
111 | super.onPageStarted(view, url, favicon);
112 | mProgressView.setVisibility(View.VISIBLE);
113 | }
114 |
115 | @Override
116 | public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
117 | if (url.startsWith(REDIRECT_URL)) {
118 | final int accessTokenIndex = url.indexOf(ACCESS_TOKEN_URL_PATH);
119 | if (0 < accessTokenIndex) {
120 | final String accessToken = url.substring(accessTokenIndex + ACCESS_TOKEN_URL_PATH.length());
121 | onTokenGranted(accessToken);
122 | } else {
123 | onTokenFailed();
124 | }
125 |
126 | return true;
127 | } else {
128 | return false;
129 | }
130 | }
131 |
132 | @Override
133 | public void onPageFinished(final WebView view, final String url) {
134 | super.onPageFinished(view, url);
135 | mProgressView.setVisibility(View.GONE);
136 | }
137 | }
138 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/SingleFragmentActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentManager;
6 |
7 | import com.azoft.azoft.collage.R;
8 |
9 | /**
10 | * This activity will handle fragment creation and call createFragment when needed.
11 | *
12 | * Date: 4/8/2014
13 | * Time: 11:19 AM
14 | *
15 | * @author MiG35
16 | */
17 | public abstract class SingleFragmentActivity extends CollageAuthActivity {
18 |
19 | @Override
20 | protected void onCreate(final Bundle savedInstanceState, final String accessToken) {
21 | setContentView(R.layout.activity_single_fragment);
22 |
23 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
24 |
25 | final FragmentManager fm = getSupportFragmentManager();
26 | if (null == fm.findFragmentById(R.id.container)) {
27 | final Fragment fragment = createFragment();
28 | if (null == fragment) {
29 | finish();
30 | } else {
31 | fm.beginTransaction().add(R.id.container, fragment).commit();
32 | }
33 | }
34 | }
35 |
36 | protected abstract Fragment createFragment();
37 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/StartActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v4.app.FragmentManager;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 | import android.view.View;
9 | import android.widget.Button;
10 |
11 | import com.azoft.azoft.collage.R;
12 | import com.azoft.azoft.collage.data.Collage;
13 | import com.azoft.azoft.collage.data.User;
14 | import com.azoft.azoft.collage.ui.fragments.CollageSelectionFragment;
15 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
16 | import com.mig35.injectorlib.utils.inject.InjectView;
17 |
18 | /**
19 | * Date: 4/10/2014
20 | * Time: 11:57 AM
21 | *
22 | * @author MiG35
23 | */
24 | public class StartActivity extends CollageAuthActivity {
25 |
26 | private static final int USER_SELECTION_REQUEST_CODE = 14;
27 |
28 | @InjectView(R.id.b_current_user)
29 | private Button mCurrentUserButton;
30 |
31 | @InjectSavedState
32 | private User mCurrentUser;
33 |
34 | @Override
35 | protected void onCreate(final Bundle savedInstanceState, final String accessToken) {
36 | setContentView(R.layout.activity_start);
37 |
38 | mCurrentUserButton.setOnClickListener(new View.OnClickListener() {
39 | @Override
40 | public void onClick(final View v) {
41 | startActivityForResult(CollageAuthActivity.createIntent(StartActivity.this, UserSelectionActivity.class), USER_SELECTION_REQUEST_CODE);
42 | }
43 | });
44 | final FragmentManager fm = getSupportFragmentManager();
45 | if (null == fm.findFragmentById(R.id.container_collage_selection)) {
46 | fm.beginTransaction().add(R.id.container_collage_selection, new CollageSelectionFragment()).commit();
47 | }
48 |
49 | updateButtonText();
50 | getSupportActionBar().setDisplayShowHomeEnabled(false);
51 | getSupportActionBar().setDisplayShowTitleEnabled(false);
52 | }
53 |
54 | @Override
55 | public boolean onCreateOptionsMenu(final Menu menu) {
56 | getMenuInflater().inflate(R.menu.start_collage, menu);
57 |
58 | super.onCreateOptionsMenu(menu);
59 |
60 | return true;
61 | }
62 |
63 | @Override
64 | public boolean onOptionsItemSelected(final MenuItem item) {
65 | if (item.getItemId() == R.id.menu_create_collage) {
66 | final CollageSelectionFragment collageSelectionFragment =
67 | (CollageSelectionFragment) getSupportFragmentManager().findFragmentById(R.id.container_collage_selection);
68 | final Collage collage = collageSelectionFragment.getSelectedCollage();
69 | if (null == mCurrentUser) {
70 | showToast(R.string.error_select_user_first);
71 | } else if (null == collage) {
72 | showToast(R.string.error_select_collage_first);
73 | } else {
74 | openCollageBuilder(mCurrentUser, collage);
75 | }
76 | }
77 | return super.onOptionsItemSelected(item);
78 | }
79 |
80 | private void openCollageBuilder(final User currentUser, final Collage collage) {
81 | startActivity(CollageAuthActivity.createIntent(this, CollageBuilderActivity.class).putExtra(CollageBuilderActivity.EXTRA_USER, currentUser)
82 | .putExtra(CollageBuilderActivity.EXTRA_KOLAJ, collage));
83 | }
84 |
85 | private void updateButtonText() {
86 | if (null == mCurrentUser) {
87 | mCurrentUserButton.setText(R.string.text_select_current_user);
88 | } else {
89 | mCurrentUserButton.setText(getString(R.string.text_current_user_selected, mCurrentUser.getNickName()));
90 | }
91 | }
92 |
93 | @Override
94 | protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
95 | if (USER_SELECTION_REQUEST_CODE == requestCode && resultCode == RESULT_OK && null != data) {
96 | mCurrentUser = (User) data.getSerializableExtra(UserSelectionActivity.RESULT_USER);
97 | updateButtonText();
98 | } else {
99 | super.onActivityResult(requestCode, resultCode, data);
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/activities/phone/UserSelectionActivity.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.activities.phone;
2 |
3 | import android.content.Intent;
4 | import android.support.v4.app.Fragment;
5 |
6 | import com.azoft.azoft.collage.data.User;
7 | import com.azoft.azoft.collage.ui.fragments.UserSelectionFragment;
8 |
9 | public class UserSelectionActivity extends SingleFragmentActivity implements UserSelectionFragment.OnUserSelectedListener {
10 |
11 | public static final String RESULT_USER = "com.redmadrobot.azoft.collage.ui.activities.phone.UserSelectionActivity.RESULT_USER";
12 |
13 | @Override
14 | protected Fragment createFragment() {
15 | return new UserSelectionFragment();
16 | }
17 |
18 | @Override
19 | public void onUserSelected(final User user) {
20 | setResult(RESULT_OK, new Intent().putExtra(RESULT_USER, user));
21 | finish();
22 | }
23 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/adapters/CollageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.ImageView;
9 |
10 | import com.azoft.azoft.collage.R;
11 | import com.azoft.azoft.collage.data.Collage;
12 | import com.azoft.azoft.collage.ui.widgets.CollageViewGroup;
13 | import com.azoft.azoft.collage.utils.collagegenerators.CollageFactory;
14 |
15 | /**
16 | *
17 | * Date: 4/8/2014
18 | * Time: 5:22 PM
19 | *
20 | * @author MiG35
21 | */
22 | public class CollageAdapter extends BaseAdapter {
23 |
24 | private final CollageFactory mCollageFactory;
25 | private final LayoutInflater mLayoutInflater;
26 |
27 | private Integer mSelectedNumber;
28 |
29 | /**
30 | * Will show collage template items. Will use factory as collage generator.
31 | *
32 | * @param context application or activity context
33 | * @param collageFactory factory for collage creation
34 | * @param selectedNumber previously selected collage. may be null if nothing selected.
35 | */
36 | public CollageAdapter(final Context context, final CollageFactory collageFactory, final Integer selectedNumber) {
37 | mLayoutInflater = LayoutInflater.from(context);
38 | mCollageFactory = collageFactory;
39 | mSelectedNumber = selectedNumber;
40 | }
41 |
42 | @Override
43 | public int getCount() {
44 | return mCollageFactory.getCollageCount();
45 | }
46 |
47 | @Override
48 | public Collage getItem(final int position) {
49 | return mCollageFactory.getCollage(position);
50 | }
51 |
52 | @Override
53 | public long getItemId(final int position) {
54 | return position;
55 | }
56 |
57 | @Override
58 | public View getView(final int position, final View convertView, final ViewGroup parent) {
59 | final View resultView;
60 | final Holder holder;
61 | if (null == convertView) {
62 | resultView = mLayoutInflater.inflate(R.layout.item_collage, parent, false);
63 | holder = new Holder(resultView);
64 | //noinspection ConstantConditions
65 | resultView.setTag(R.id.holder, holder);
66 | } else {
67 | resultView = convertView;
68 | holder = (Holder) convertView.getTag(R.id.holder);
69 | }
70 |
71 | holder.mCollageViewGroup.setCollage(getItem(position));
72 | if (null == mSelectedNumber || mSelectedNumber != position) {
73 | holder.mCheckBox.setVisibility(View.GONE);
74 | } else {
75 | holder.mCheckBox.setVisibility(View.VISIBLE);
76 | }
77 |
78 | return resultView;
79 | }
80 |
81 | /**
82 | * Will set new selected collage
83 | */
84 | public void setSelected(final int position) {
85 | mSelectedNumber = position;
86 | notifyDataSetChanged();
87 | }
88 |
89 | private static class Holder {
90 |
91 | final ImageView mCheckBox;
92 | final CollageViewGroup mCollageViewGroup;
93 |
94 | Holder(final View resultView) {
95 | mCheckBox = (ImageView) resultView.findViewById(R.id.iv_selection_box);
96 | mCollageViewGroup = (CollageViewGroup) resultView.findViewById(R.id.collage_view_group);
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/adapters/UserFeedAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.ImageView;
9 |
10 | import com.azoft.azoft.collage.R;
11 | import com.azoft.azoft.collage.data.Post;
12 | import com.squareup.picasso.Callback;
13 | import com.squareup.picasso.Picasso;
14 |
15 | import java.lang.ref.WeakReference;
16 | import java.util.List;
17 |
18 | /**
19 | * Date: 4/9/2014
20 | * Time: 10:13 AM
21 | *
22 | * @author MiG35
23 | */
24 | public class UserFeedAdapter extends BaseAdapter {
25 |
26 | private final LayoutInflater mLayoutInflater;
27 | private final List mPosts;
28 |
29 | public UserFeedAdapter(final Context context, final List posts) {
30 | mLayoutInflater = LayoutInflater.from(context);
31 | mPosts = posts;
32 | }
33 |
34 | @Override
35 | public int getCount() {
36 | return null == mPosts ? 0 : mPosts.size();
37 | }
38 |
39 | @Override
40 | public Post getItem(final int position) {
41 | return mPosts.get(position);
42 | }
43 |
44 | @Override
45 | public long getItemId(final int position) {
46 | return position;
47 | }
48 |
49 | @Override
50 | public View getView(final int position, final View convertView, final ViewGroup parent) {
51 | final View resultView;
52 | final Holder holder;
53 | if (null == convertView) {
54 | resultView = mLayoutInflater.inflate(R.layout.item_user_feed, parent, false);
55 | holder = new Holder(resultView);
56 | //noinspection ConstantConditions
57 | resultView.setTag(R.id.holder, holder);
58 | } else {
59 | resultView = convertView;
60 | holder = (Holder) resultView.getTag(R.id.holder);
61 | }
62 | final Post post = getItem(position);
63 |
64 | holder.mProgressView.setVisibility(View.VISIBLE);
65 |
66 | Picasso.with(mLayoutInflater.getContext()).load(post.getLowResolutionImage().getUrl())
67 | .resizeDimen(R.dimen.item_image_selection_grid_size, R.dimen.item_image_selection_grid_size).centerInside()
68 | .error(R.drawable.ic_action_picture).into(holder.mImageView, new ProgressCallback(holder.mProgressView));
69 |
70 | return resultView;
71 | }
72 |
73 | private static class Holder {
74 |
75 | private final ImageView mImageView;
76 | private final View mProgressView;
77 |
78 | Holder(final View resultView) {
79 | mImageView = (ImageView) resultView.findViewById(R.id.iv_user_feed);
80 | mProgressView = resultView.findViewById(R.id.pb_user_feed);
81 | }
82 | }
83 |
84 | private static class ProgressCallback implements Callback {
85 |
86 | private final WeakReference mProgressViewRef;
87 |
88 | public ProgressCallback(final View progressView) {
89 | mProgressViewRef = new WeakReference<>(progressView);
90 | }
91 |
92 | @Override
93 | public void onSuccess() {
94 | doHide();
95 | }
96 |
97 | @Override
98 | public void onError() {
99 | doHide();
100 | }
101 |
102 | private void doHide() {
103 | final View view = mProgressViewRef.get();
104 | if (null != view) {
105 | view.setVisibility(View.GONE);
106 | }
107 | mProgressViewRef.clear();
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/adapters/UsersAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.BaseAdapter;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.azoft.azoft.collage.R;
13 | import com.azoft.azoft.collage.data.User;
14 | import com.squareup.picasso.Picasso;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Date: 4/8/2014
20 | * Time: 1:09 PM
21 | *
22 | * @author MiG35
23 | */
24 | public class UsersAdapter extends BaseAdapter {
25 |
26 | private final LayoutInflater mLayoutInflater;
27 | private List mUsers;
28 |
29 | public UsersAdapter(final Context context, final List users) {
30 | mLayoutInflater = LayoutInflater.from(context);
31 | mUsers = users;
32 | }
33 |
34 | @Override
35 | public int getCount() {
36 | return null == mUsers ? 0 : mUsers.size();
37 | }
38 |
39 | @Override
40 | public User getItem(final int position) {
41 | return mUsers.get(position);
42 | }
43 |
44 | @Override
45 | public long getItemId(final int position) {
46 | return position;
47 | }
48 |
49 | @Override
50 | public View getView(final int position, final View convertView, final ViewGroup parent) {
51 | final View resultView;
52 | final Holder holder;
53 | if (null == convertView) {
54 | resultView = mLayoutInflater.inflate(R.layout.item_user, parent, false);
55 | holder = new Holder(resultView);
56 | //noinspection ConstantConditions
57 | resultView.setTag(R.id.holder, holder);
58 | } else {
59 | resultView = convertView;
60 | holder = (Holder) resultView.getTag(R.id.holder);
61 | }
62 | final User user = getItem(position);
63 |
64 | final String userName = getUserName(user);
65 | holder.mNickNameTextView.setText(user.getNickName());
66 | holder.mNameTextView.setText(userName);
67 | holder.mNameTextView.setVisibility(null == userName ? View.GONE : View.VISIBLE);
68 |
69 | Picasso.with(mLayoutInflater.getContext()).load(user.getProfilePicture())
70 | .resizeDimen(R.dimen.item_user_picture_size, R.dimen.item_user_picture_size).centerInside().error(R.drawable.ic_action_user)
71 | .into(holder.mPictureImageView);
72 |
73 | return resultView;
74 | }
75 |
76 | private String getUserName(final User user) {
77 | final StringBuilder result = new StringBuilder(10);
78 | if (!TextUtils.isEmpty(user.getFirstName())) {
79 | result.append(user.getFirstName());
80 |
81 | }
82 | if (!TextUtils.isEmpty(user.getLastName())) {
83 | if (result.length() != 0) {
84 | result.append(' ');
85 | }
86 | result.append(user.getLastName());
87 | }
88 | if (result.length() == 0) {
89 | return null;
90 | }
91 | return result.toString();
92 | }
93 |
94 | public void setUsers(final List users) {
95 | mUsers = users;
96 | notifyDataSetChanged();
97 | }
98 |
99 | private static class Holder {
100 |
101 |
102 | final ImageView mPictureImageView;
103 | final TextView mNickNameTextView;
104 | final TextView mNameTextView;
105 |
106 | Holder(final View resultView) {
107 | mPictureImageView = (ImageView) resultView.findViewById(R.id.iv_picture);
108 | mNickNameTextView = (TextView) resultView.findViewById(R.id.tv_nickname);
109 | mNameTextView = (TextView) resultView.findViewById(R.id.tv_name);
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/ActionBarLoaderFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.app.Activity;
4 |
5 | import com.azoft.azoft.collage.ui.activities.phone.CollageAuthActivity;
6 | import com.mig35.loaderlib.ui.LoaderFragment;
7 | import com.azoft.azoft.collage.ui.activities.phone.CollageActivity;
8 |
9 | /**
10 | * Base fragment. Can be used only with CollageActivity.
11 | *
12 | * Date: 4/8/2014
13 | * Time: 4:51 PM
14 | *
15 | * @author MiG35
16 | */
17 | public abstract class ActionBarLoaderFragment extends LoaderFragment {
18 |
19 | @Override
20 | public void onAttach(final Activity activity) {
21 | super.onAttach(activity);
22 |
23 | if (!(activity instanceof CollageAuthActivity)) {
24 | throw new IllegalStateException("This fragment should be used only with CollageActivity");
25 | }
26 | }
27 |
28 | public CollageAuthActivity getActionBarActivity() {
29 | return (CollageAuthActivity) getActivity();
30 | }
31 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/CollageBuilderFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.Menu;
10 | import android.view.MenuInflater;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.azoft.azoft.collage.R;
16 | import com.azoft.azoft.collage.data.Collage;
17 | import com.azoft.azoft.collage.data.CollageFillData;
18 | import com.azoft.azoft.collage.data.CollageRegionData;
19 | import com.azoft.azoft.collage.data.Post;
20 | import com.azoft.azoft.collage.data.User;
21 | import com.azoft.azoft.collage.loaders.CollageBigImageLoader;
22 | import com.azoft.azoft.collage.ui.activities.phone.CollageAuthActivity;
23 | import com.azoft.azoft.collage.ui.activities.phone.CollagePreviewActivity;
24 | import com.azoft.azoft.collage.ui.activities.phone.ImageSelectionFromUserFeedActivity;
25 | import com.azoft.azoft.collage.ui.widgets.CollageViewGroup;
26 | import com.azoft.azoft.collage.utils.CollageRegion;
27 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
28 | import com.mig35.injectorlib.utils.inject.InjectView;
29 |
30 | import java.util.HashMap;
31 | import java.util.Map;
32 |
33 | /**
34 | * Will show collage and performs all actions for its filling.
35 | *
36 | * Date: 4/8/2014
37 | * Time: 6:41 PM
38 | *
39 | * @author MiG35
40 | */
41 | public class CollageBuilderFragment extends ActionBarLoaderFragment {
42 |
43 | private static final String BIG_IMAGE_LOADER = "com.redmadrobot.azoft.collage.ui.fragments.CollageBuilderFragment.BIG_IMAGE_LOADER_%d";
44 | private static final int REQUEST_CODE_IMAGE_SELECTION = 156;
45 |
46 | @InjectSavedState
47 | private User mUser;
48 | @InjectSavedState
49 | private CollageFillData mCollageFillData;
50 | @InjectSavedState
51 | private CollageRegion mSelectedCollageRegion;
52 |
53 | @InjectView(R.id.collage_view_group)
54 | private CollageViewGroup mCollageViewGroup;
55 |
56 | // this is waiting images. user ask as to load them to collage regions, but we may not load them because of full recreation (as if don't keep
57 | // activities set).
58 | @SuppressWarnings("FieldMayBeFinal")
59 | @InjectSavedState
60 | private Map mWaitingImages = new HashMap<>();
61 |
62 | public CollageBuilderFragment() {
63 | setHasOptionsMenu(true);
64 | setMenuVisibility(true);
65 | }
66 |
67 | @Override
68 | public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
69 | return inflater.inflate(R.layout.fragment_collage_builder, container, false);
70 | }
71 |
72 | @Override
73 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
74 | super.onViewCreated(view, savedInstanceState);
75 |
76 | mCollageViewGroup.setCollage(mCollageFillData);
77 | mCollageViewGroup.setRegionClickListener(new CollageViewGroup.RegionClickListener() {
78 | @Override
79 | public void onRegionClicked(final CollageRegion collageRegion) {
80 | mSelectedCollageRegion = collageRegion;
81 | startActivityForResult(CollageAuthActivity.createIntent(getActionBarActivity(), ImageSelectionFromUserFeedActivity.class)
82 | .putExtra(ImageSelectionFromUserFeedActivity.EXTRA_USER, mUser), REQUEST_CODE_IMAGE_SELECTION);
83 | }
84 | });
85 |
86 | for (final Map.Entry setItem : mWaitingImages.entrySet()) {
87 | // check if we have waiting images and they are not loaded yet
88 | if (!getLoaderHelper().hasLoader(getLoaderHelper().getLoaderId(createCollageRegionLoaderId(setItem.getKey())))) {
89 | // we should start this loader again
90 | //noinspection ObjectAllocationInLoop
91 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(createCollageRegionLoaderId(setItem.getKey())),
92 | new CollageBigImageLoader(getActivity(), setItem.getKey(), setItem.getValue()));
93 | }
94 | }
95 | }
96 |
97 | @Override
98 | public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
99 | super.onCreateOptionsMenu(menu, inflater);
100 |
101 | inflater.inflate(R.menu.collage_builder, menu);
102 | }
103 |
104 | @Override
105 | public boolean onOptionsItemSelected(final MenuItem item) {
106 | if (R.id.menu_preview_collage == item.getItemId()) {
107 | if (mCollageFillData.hasAllRegions()) {
108 | startActivity(CollageAuthActivity.createIntent(getActionBarActivity(), CollagePreviewActivity.class)
109 | .putExtra(CollagePreviewActivity.EXTRA_KOLAJ_FILL_DATA, mCollageFillData));
110 | } else {
111 | getActionBarActivity().showToast(R.string.error_fill_all_items_first);
112 | }
113 | return true;
114 | }
115 | return super.onOptionsItemSelected(item);
116 | }
117 |
118 | @Override
119 | public void onLoaderResult(final int id, final Object result) {
120 | super.onLoaderResult(id, result);
121 |
122 | for (final CollageRegion collageRegion : mCollageFillData.getCollageRegions()) {
123 | if (id == getLoaderHelper().getLoaderId(createCollageRegionLoaderId(collageRegion))) {
124 | getLoaderHelper().removeLoaderFromRunningLoaders(id);
125 |
126 | final CollageRegionData collageRegionData = (CollageRegionData) result;
127 | mCollageFillData.setRegionData(collageRegion, collageRegionData);
128 | mCollageViewGroup.invalidateRegionData();
129 |
130 | // now we finished our loading, so it will be saved in save state, so it is save to remove it from this list.
131 | mWaitingImages.remove(collageRegion);
132 |
133 | break;
134 | }
135 | }
136 | }
137 |
138 | @Override
139 | public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
140 | if (REQUEST_CODE_IMAGE_SELECTION == requestCode) {
141 | if (resultCode == Activity.RESULT_OK && null != data) {
142 | if (null == mSelectedCollageRegion) {
143 | Log.e(CollageBuilderFragment.class.getSimpleName(), "Wrong state! How does it happen?! =/");
144 | return;
145 | }
146 | final Post post = (Post) data.getSerializableExtra(ImageSelectionFromUserFeedActivity.RESULT_POST);
147 | // we should remember that this image is not loading
148 | mWaitingImages.put(mSelectedCollageRegion, post);
149 | getLoaderHelper().restartAsyncLoader(getLoaderHelper().getLoaderId(createCollageRegionLoaderId(mSelectedCollageRegion)),
150 | new CollageBigImageLoader(getActivity(), mSelectedCollageRegion, post));
151 | }
152 | mSelectedCollageRegion = null;
153 | } else {
154 | super.onActivityResult(requestCode, resultCode, data);
155 | }
156 | }
157 |
158 | private String createCollageRegionLoaderId(final CollageRegion collageRegion) {
159 | return String.format(BIG_IMAGE_LOADER, collageRegion.getId());
160 | }
161 |
162 | public static Fragment getInstance(final User user, final Collage collage) {
163 | if (null == user || null == collage) {
164 | throw new IllegalArgumentException("non user neither collage can be null");
165 | }
166 | final CollageBuilderFragment collageBuilderFragment = new CollageBuilderFragment();
167 | collageBuilderFragment.mUser = user;
168 | collageBuilderFragment.mCollageFillData = new CollageFillData(collage);
169 | return collageBuilderFragment;
170 | }
171 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/CollagePreviewFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.Dialog;
5 | import android.content.DialogInterface;
6 | import android.os.Bundle;
7 | import android.support.annotation.NonNull;
8 | import android.support.v4.app.DialogFragment;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.app.FragmentManager;
11 | import android.view.LayoutInflater;
12 | import android.view.Menu;
13 | import android.view.MenuInflater;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.ImageView;
18 |
19 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
20 | import com.mig35.injectorlib.utils.inject.InjectView;
21 | import com.azoft.azoft.collage.R;
22 | import com.azoft.azoft.collage.data.CollageFillData;
23 | import com.azoft.azoft.collage.exceptions.CollageCreationException;
24 | import com.azoft.azoft.collage.loaders.CollagePreviewCreatorLoader;
25 | import com.azoft.azoft.collage.utils.CommonUtils;
26 | import com.squareup.picasso.Picasso;
27 |
28 | /**
29 | * Date: 4/9/2014
30 | * Time: 5:57 PM
31 | *
32 | * @author MiG35
33 | */
34 | public class CollagePreviewFragment extends ActionBarLoaderFragment {
35 |
36 | private static final String KOLAJ_PREVIEW_LOADER = "com.redmadrobot.azoft.collage.ui.fragments.CollagePreviewFragment.KOLAJ_PREVIEW_LOADER";
37 | private static final String CREATION_PROBLEM_FRAGMENT =
38 | "com.redmadrobot.azoft.collage.ui.fragments.CollagePreviewFragment.CREATION_PROBLEM_FRAGMENT";
39 |
40 | @InjectSavedState
41 | private CollageFillData mCollageFillData;
42 |
43 | @InjectView(R.id.iv_collage)
44 | private ImageView mCollageImageView;
45 | @InjectView(R.id.progress_bar)
46 | private View mProgressView;
47 |
48 | @InjectSavedState
49 | private String mResultPath;
50 |
51 | public CollagePreviewFragment() {
52 | setHasOptionsMenu(true);
53 | setMenuVisibility(true);
54 | }
55 |
56 | @Override
57 | public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
58 | return inflater.inflate(R.layout.fragment_collage_preview, container, false);
59 | }
60 |
61 | @Override
62 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
63 | super.onViewCreated(view, savedInstanceState);
64 |
65 | // we should check if there is no big errors in previous image creation
66 | if (null == getFragmentManager().findFragmentByTag(CREATION_PROBLEM_FRAGMENT)) {
67 | // we should check if we already create image or not
68 | if (null == mResultPath) {
69 | mProgressView.setVisibility(View.VISIBLE);
70 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(KOLAJ_PREVIEW_LOADER),
71 | new CollagePreviewCreatorLoader(getActivity(), mCollageFillData));
72 | } else {
73 | setResultPath(mResultPath);
74 | }
75 | }
76 | }
77 |
78 | @Override
79 | public void onLoaderResult(final int id, final Object result) {
80 | super.onLoaderResult(id, result);
81 |
82 | if (id == getLoaderHelper().getLoaderId(KOLAJ_PREVIEW_LOADER)) {
83 | getLoaderHelper().removeLoaderFromRunningLoaders(id);
84 |
85 | setResultPath((String) result);
86 | }
87 | }
88 |
89 | @Override
90 | public void onLoaderError(final int id, final Exception exception) {
91 | super.onLoaderError(id, exception);
92 |
93 | if (id == getLoaderHelper().getLoaderId(KOLAJ_PREVIEW_LOADER) && exception instanceof CollageCreationException) {
94 | final FragmentManager fm = getFragmentManager();
95 | fm.beginTransaction().add(new CollageCreationProblemMessageFragment(), CREATION_PROBLEM_FRAGMENT).commitAllowingStateLoss();
96 | }
97 | }
98 |
99 | private void setResultPath(final String resultPath) {
100 | mResultPath = resultPath;
101 | mProgressView.setVisibility(View.GONE);
102 |
103 | Picasso.with(getActivity()).load(resultPath).fit().error(R.drawable.ic_action_new).skipMemoryCache().into(mCollageImageView);
104 | getActionBarActivity().supportInvalidateOptionsMenu();
105 | }
106 |
107 | @Override
108 | public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
109 | super.onCreateOptionsMenu(menu, inflater);
110 |
111 | if (null != mResultPath) {
112 | inflater.inflate(R.menu.collage_preview, menu);
113 | }
114 | }
115 |
116 | @Override
117 | public boolean onOptionsItemSelected(final MenuItem item) {
118 | if (item.getItemId() == R.id.menu_share_collage) {
119 | if (null != mResultPath) {
120 | // because we use internal storage and provider, we should grand other apps permissions and so on...
121 | CommonUtils.sendEmailWithAttachment(getActivity(), mResultPath, getString(R.string.text_email_subject));
122 | }
123 | return true;
124 | }
125 | return super.onOptionsItemSelected(item);
126 | }
127 |
128 | public static Fragment getInstance(final CollageFillData collageFillData) {
129 | if (null == collageFillData) {
130 | throw new IllegalArgumentException("collageFillData can't be null");
131 | }
132 | final CollagePreviewFragment collagePreviewFragment = new CollagePreviewFragment();
133 | collagePreviewFragment.mCollageFillData = collageFillData;
134 | return collagePreviewFragment;
135 | }
136 |
137 | public static class CollageCreationProblemMessageFragment extends DialogFragment {
138 |
139 | @NonNull
140 | @Override
141 | public Dialog onCreateDialog(final Bundle savedInstanceState) {
142 | final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
143 | builder.setTitle(R.string.dialog_collage_creation_problem_title);
144 | builder.setMessage(R.string.dialog_collage_creation_problem_message);
145 | builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
146 | @Override
147 | public void onClick(final DialogInterface dialog, final int which) {
148 | getActivity().finish();
149 | }
150 | });
151 |
152 | return builder.create();
153 | }
154 |
155 | @Override
156 | public void onCancel(final DialogInterface dialog) {
157 | super.onCancel(dialog);
158 |
159 | getActivity().finish();
160 | }
161 | }
162 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/CollageSelectionFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.AdapterView;
8 | import android.widget.GridView;
9 |
10 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
11 | import com.mig35.injectorlib.utils.inject.InjectView;
12 | import com.azoft.azoft.collage.R;
13 | import com.azoft.azoft.collage.data.Collage;
14 | import com.azoft.azoft.collage.ui.adapters.CollageAdapter;
15 | import com.azoft.azoft.collage.utils.collagegenerators.CollageFactory;
16 | import com.azoft.azoft.collage.utils.collagegenerators.SimpleCollageGenerator;
17 |
18 | /**
19 | * Date: 4/8/2014
20 | * Time: 4:05 PM
21 | *
22 | * @author MiG35
23 | */
24 | public class CollageSelectionFragment extends ActionBarLoaderFragment {
25 |
26 | private static final CollageFactory COLLAGE_FACTORY = new SimpleCollageGenerator();
27 |
28 | @InjectSavedState
29 | private Integer mSelectedCollage;
30 |
31 | @InjectView(R.id.gv_collagees)
32 | private GridView mCollageGridView;
33 |
34 | @Override
35 | public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
36 | return inflater.inflate(R.layout.fragment_collage_selection, container, false);
37 | }
38 |
39 | @Override
40 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
41 | super.onViewCreated(view, savedInstanceState);
42 |
43 | final CollageAdapter collageAdapter = new CollageAdapter(getActivity(), COLLAGE_FACTORY, mSelectedCollage);
44 | mCollageGridView.setAdapter(collageAdapter);
45 | mCollageGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
46 | @Override
47 | public void onItemClick(final AdapterView> parent, final View view, final int position, final long id) {
48 | collageAdapter.setSelected(position);
49 | mSelectedCollage = position;
50 | }
51 | });
52 | }
53 |
54 | public Collage getSelectedCollage() {
55 | if (null == mSelectedCollage) {
56 | return null;
57 | }
58 | return COLLAGE_FACTORY.getCollage(mSelectedCollage);
59 | }
60 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/ImageSelectionFromUserFeedFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.view.Menu;
9 | import android.view.MenuInflater;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.AdapterView;
14 | import android.widget.GridView;
15 | import android.widget.TextView;
16 |
17 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
18 | import com.mig35.injectorlib.utils.inject.InjectView;
19 | import com.azoft.azoft.collage.R;
20 | import com.azoft.azoft.collage.data.Post;
21 | import com.azoft.azoft.collage.data.User;
22 | import com.azoft.azoft.collage.data.results.UserRecentFeedResult;
23 | import com.azoft.azoft.collage.loaders.UserImageFeedLoader;
24 | import com.azoft.azoft.collage.ui.adapters.UserFeedAdapter;
25 |
26 | /**
27 | * Will load and show user's image feed. Will notify ParentFragment or Activity if post is clicked if they implement PostSelectionListener
28 | * interface.
29 | *
30 | * Date: 4/8/2014
31 | * Time: 7:13 PM
32 | *
33 | * @author MiG35
34 | */
35 | public class ImageSelectionFromUserFeedFragment extends ActionBarLoaderFragment {
36 |
37 | private static final String USER_FEED_LOADER = "com.redmadrobot.azoft.collage.ui.fragments.ImageSelectionFromUserFeedFragment.USER_FEED_LOADER";
38 |
39 | // we use aggressive cache method. see readme for details
40 | @SuppressWarnings("StaticNonFinalField")
41 | private static UserRecentFeedResult sUserRecentFeedResult;
42 |
43 | @InjectView(R.id.gv_image_selection)
44 | private GridView mImageSelectionGridView;
45 | @InjectView(R.id.tv_empty)
46 | private TextView mEmptyTextView;
47 | @InjectView(R.id.progress_bar)
48 | private View mProgressBar;
49 |
50 | @InjectSavedState
51 | private User mUser;
52 |
53 | public ImageSelectionFromUserFeedFragment() {
54 | setHasOptionsMenu(true);
55 | setMenuVisibility(true);
56 | }
57 |
58 | @Override
59 | public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
60 | return inflater.inflate(R.layout.fragment_image_selection_from_user_feed, container, false);
61 | }
62 |
63 | @Override
64 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
65 | super.onViewCreated(view, savedInstanceState);
66 |
67 | mImageSelectionGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
68 | @Override
69 | public void onItemClick(final AdapterView> parent, final View view, final int position, final long id) {
70 | final Object postObj = parent.getItemAtPosition(position);
71 | if (postObj instanceof Post) {
72 | final Post post = (Post) postObj;
73 | // we should check our parent fragment and then activity if they are listening for post selection
74 | final Fragment parentFragment = getParentFragment();
75 | final Activity activity = getActivity();
76 | if (parentFragment instanceof PostSelectionListener) {
77 | ((PostSelectionListener) parentFragment).onPostSelected(post);
78 | } else if (activity instanceof PostSelectionListener) {
79 | ((PostSelectionListener) activity).onPostSelected(post);
80 | } else {
81 | Log.e(ImageSelectionFromUserFeedFragment.class.getSimpleName(), "post selected, but no listener found");
82 | }
83 | }
84 | }
85 | });
86 | // we use aggressive user feed cache in static variable
87 | if (null != sUserRecentFeedResult && mUser.getId().equals(sUserRecentFeedResult.getUserId())) {
88 | setUserRecentFeedResult(sUserRecentFeedResult);
89 | } else {
90 | State.PROGRESS.apply(this);
91 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(USER_FEED_LOADER), new UserImageFeedLoader(getActivity(), mUser.getId(), getActionBarActivity().getAccessToken()));
92 | }
93 | }
94 |
95 | @Override
96 | public void onLoaderResult(final int id, final Object result) {
97 | super.onLoaderResult(id, result);
98 |
99 | if (id == getLoaderHelper().getLoaderId(USER_FEED_LOADER)) {
100 | getLoaderHelper().removeLoaderFromRunningLoaders(id);
101 |
102 | setUserRecentFeedResult((UserRecentFeedResult) result);
103 |
104 | getActionBarActivity().supportInvalidateOptionsMenu();
105 | }
106 | }
107 |
108 | @Override
109 | public void onLoaderError(final int id, final Exception exception) {
110 | super.onLoaderError(id, exception);
111 |
112 | getLoaderHelper().destroyAsyncLoader(id);
113 | getActionBarActivity().supportInvalidateOptionsMenu();
114 | }
115 |
116 | private void setUserRecentFeedResult(final UserRecentFeedResult userRecentFeedResult) {
117 | // we use aggressive cache method. see readme for details
118 | //noinspection AssignmentToStaticFieldFromInstanceMethod
119 | sUserRecentFeedResult = userRecentFeedResult;
120 |
121 | final UserFeedAdapter adapter = new UserFeedAdapter(getActivity(), userRecentFeedResult.getPosts());
122 |
123 | if (0 == adapter.getCount()) {
124 | State.EMPTY.apply(this);
125 | } else {
126 | mImageSelectionGridView.setAdapter(adapter);
127 | State.DATA.apply(this);
128 | }
129 | }
130 |
131 | @Override
132 | public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
133 | super.onCreateOptionsMenu(menu, inflater);
134 |
135 | if (!getLoaderHelper().hasRunningLoaders()) {
136 | inflater.inflate(R.menu.image_selection_user_feed, menu);
137 | }
138 | }
139 |
140 | @Override
141 | public boolean onOptionsItemSelected(final MenuItem item) {
142 | if (item.getItemId() == R.id.menu_update) {
143 | getLoaderHelper()
144 | .restartAsyncLoader(getLoaderHelper().getLoaderId(USER_FEED_LOADER), new UserImageFeedLoader(getActivity(), mUser.getId(), getActionBarActivity().getAccessToken()));
145 | getActionBarActivity().supportInvalidateOptionsMenu();
146 | return true;
147 | }
148 | return super.onOptionsItemSelected(item);
149 | }
150 |
151 | public static Fragment getInstance(final User user) {
152 | if (null == user) {
153 | throw new IllegalArgumentException("user can't be null");
154 | }
155 | final ImageSelectionFromUserFeedFragment imageSelectionFromUserFeedFragment = new ImageSelectionFromUserFeedFragment();
156 | imageSelectionFromUserFeedFragment.mUser = user;
157 | return imageSelectionFromUserFeedFragment;
158 | }
159 |
160 | public interface PostSelectionListener {
161 |
162 | void onPostSelected(final Post post);
163 | }
164 |
165 | private enum State {
166 | DATA {
167 | @Override
168 | public void apply(final ImageSelectionFromUserFeedFragment fragment) {
169 | fragment.mImageSelectionGridView.setVisibility(View.VISIBLE);
170 | fragment.mEmptyTextView.setVisibility(View.GONE);
171 | fragment.mProgressBar.setVisibility(View.GONE);
172 | }
173 | },
174 | PROGRESS {
175 | @Override
176 | public void apply(final ImageSelectionFromUserFeedFragment fragment) {
177 | fragment.mImageSelectionGridView.setVisibility(View.GONE);
178 | fragment.mEmptyTextView.setVisibility(View.GONE);
179 | fragment.mProgressBar.setVisibility(View.VISIBLE);
180 | }
181 | },
182 | EMPTY {
183 | @Override
184 | public void apply(final ImageSelectionFromUserFeedFragment fragment) {
185 | fragment.mImageSelectionGridView.setVisibility(View.GONE);
186 | fragment.mEmptyTextView.setVisibility(View.VISIBLE);
187 | fragment.mProgressBar.setVisibility(View.GONE);
188 | fragment.mEmptyTextView.setText(fragment.getString(R.string.text_user_no_images, fragment.mUser.getNickName()));
189 | }
190 | };
191 |
192 | public abstract void apply(final ImageSelectionFromUserFeedFragment fragment);
193 | }
194 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/fragments/UserSelectionFragment.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.fragments;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.view.MenuItemCompat;
8 | import android.support.v7.widget.SearchView;
9 | import android.util.Log;
10 | import android.view.Gravity;
11 | import android.view.LayoutInflater;
12 | import android.view.Menu;
13 | import android.view.MenuInflater;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.view.inputmethod.InputMethodManager;
18 | import android.widget.AdapterView;
19 | import android.widget.ListView;
20 | import android.widget.TextView;
21 |
22 | import com.mig35.injectorlib.utils.inject.InjectSavedState;
23 | import com.mig35.injectorlib.utils.inject.InjectView;
24 | import com.azoft.azoft.collage.R;
25 | import com.azoft.azoft.collage.data.User;
26 | import com.azoft.azoft.collage.data.results.UserDataResult;
27 | import com.azoft.azoft.collage.data.results.UsersSearchResult;
28 | import com.azoft.azoft.collage.loaders.UserDataLoader;
29 | import com.azoft.azoft.collage.loaders.UsersSearchLoader;
30 | import com.azoft.azoft.collage.ui.adapters.UsersAdapter;
31 |
32 | import java.util.regex.Pattern;
33 |
34 | /**
35 | * Will load and show users for selected nickname. Will notify ParentFragment or Activity if user is clicked if they implement OnUserSelectedListener
36 | * interface.
37 | * Will use user's name pattern as Instagram has.
38 | * Date: 4/8/2014
39 | * Time: 4:49 PM
40 | *
41 | * @author MiG35
42 | */
43 | public class UserSelectionFragment extends ActionBarLoaderFragment {
44 |
45 | private static final String LOADER_USER_HAS_DATA = "com.redmadrobot.azoft.collage.ui.activities.phone.UserSelectionActivity.LOADER_USER_HAS_DATA";
46 | private static final String LOADER_USERS = "com.redmadrobot.azoft.collage.ui.activities.phone.UserSelectionActivity.LOADER_USERS";
47 |
48 | private static final Pattern USER_NAME_PATTERN = Pattern.compile("[\\w]+");
49 |
50 | @InjectView(R.id.lv_user_accounts)
51 | private ListView mUserAccountsListView;
52 | @InjectView(R.id.tv_empty)
53 | private TextView mEmptyTextView;
54 |
55 | @InjectSavedState
56 | private boolean mExpandMenu = true;
57 | @InjectSavedState
58 | private String mSearchString;
59 |
60 | @InjectSavedState
61 | private UsersSearchResult mUsersSearchResult;
62 |
63 | private UsersAdapter mUsersAdapter;
64 |
65 | public UserSelectionFragment() {
66 | setHasOptionsMenu(true);
67 | setMenuVisibility(true);
68 | }
69 |
70 | @Override
71 | public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
72 | return inflater.inflate(R.layout.fragment_user_selection, container, false);
73 | }
74 |
75 | @Override
76 | public void onViewCreated(final View view, final Bundle savedInstanceState) {
77 | super.onViewCreated(view, savedInstanceState);
78 |
79 | mUserAccountsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
80 |
81 | private User mPrevSelectedUser;
82 |
83 | @Override
84 | public void onItemClick(final AdapterView> parent, final View view, final int position, final long id) {
85 | final User user = mUsersAdapter.getItem(position);
86 | if (mPrevSelectedUser == user) {
87 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(LOADER_USER_HAS_DATA), new UserDataLoader(getActivity(), user, getActionBarActivity().getAccessToken()));
88 | } else {
89 | mPrevSelectedUser = user;
90 | getLoaderHelper()
91 | .restartAsyncLoader(getLoaderHelper().getLoaderId(LOADER_USER_HAS_DATA), new UserDataLoader(getActivity(), user, getActionBarActivity().getAccessToken()));
92 | }
93 | }
94 | });
95 |
96 | if (getLoaderHelper().hasLoader(getLoaderHelper().getLoaderId(LOADER_USERS))) {
97 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(LOADER_USERS), null);
98 | } else if (null != mSearchString) {
99 | onUserNickSelected(mSearchString);
100 | } else {
101 | getActionBarActivity().getSupportActionBar().setTitle(R.string.title_user_nick_selection);
102 | }
103 | }
104 |
105 | private void onUserNickSelected(final String nickName) {
106 | if (nickName.equals(mSearchString) && null != mUsersSearchResult) {
107 | // if we have all information for this input, simply show it
108 | setUserSearchResult(mUsersSearchResult);
109 | } else if (nickName.equals(mSearchString)) {
110 | // is we already enter it, but don't have data, we should connect to last loader
111 | getLoaderHelper().initAsyncLoader(getLoaderHelper().getLoaderId(LOADER_USERS), new UsersSearchLoader(getActivity(), nickName, getActionBarActivity().getAccessToken()));
112 | } else {
113 | // or we should load new data
114 | mUsersSearchResult = null;
115 | mSearchString = nickName;
116 | getLoaderHelper().restartAsyncLoader(getLoaderHelper().getLoaderId(LOADER_USERS), new UsersSearchLoader(getActivity(), nickName, getActionBarActivity().getAccessToken()));
117 | }
118 | }
119 |
120 | @Override
121 | public void onLoaderResult(final int id, final Object result) {
122 | super.onLoaderResult(id, result);
123 |
124 | if (id == getLoaderHelper().getLoaderId(LOADER_USERS)) {
125 | getLoaderHelper().removeLoaderFromRunningLoaders(id);
126 |
127 | setUserSearchResult((UsersSearchResult) result);
128 | } else if (id == getLoaderHelper().getLoaderId(LOADER_USER_HAS_DATA)) {
129 | getLoaderHelper().destroyAsyncLoader(id);
130 |
131 | final UserDataResult userDataResult = (UserDataResult) result;
132 |
133 | if (userDataResult.isHasImages()) {
134 | final User user = userDataResult.getUser();
135 | final Fragment parentFragment = getParentFragment();
136 | final Activity activity = getActivity();
137 | if (parentFragment instanceof OnUserSelectedListener) {
138 | ((OnUserSelectedListener) parentFragment).onUserSelected(user);
139 | } else if (activity instanceof OnUserSelectedListener) {
140 | ((OnUserSelectedListener) activity).onUserSelected(user);
141 | } else {
142 | Log.e(UserSelectionFragment.class.getSimpleName(), "user selected, but no listener found");
143 | }
144 | } else if (userDataResult.isDataViewAllowed()) {
145 | getActionBarActivity().showToast(R.string.error_user_no_images, Gravity.CENTER);
146 | } else {
147 | getActionBarActivity().showToast(R.string.error_not_allowed, Gravity.CENTER);
148 | }
149 | }
150 | }
151 |
152 | private void setUserSearchResult(final UsersSearchResult userSearchResult) {
153 | mUsersSearchResult = userSearchResult;
154 | getActionBarActivity().getSupportActionBar().setTitle(getString(R.string.title_user_nick_selection_result, userSearchResult.getNickName()));
155 |
156 | if (null == mUsersAdapter) {
157 | mUsersAdapter = new UsersAdapter(getActivity(), userSearchResult.getUsers());
158 | } else {
159 | mUsersAdapter.setUsers(userSearchResult.getUsers());
160 | }
161 | if (null == mUserAccountsListView.getAdapter()) {
162 | mUserAccountsListView.setAdapter(mUsersAdapter);
163 | }
164 | mUserAccountsListView.setVisibility(mUsersAdapter.getCount() == 0 ? View.GONE : View.VISIBLE);
165 | mEmptyTextView.setVisibility(mUsersAdapter.getCount() == 0 ? View.VISIBLE : View.GONE);
166 | mEmptyTextView.setText(getString(R.string.text_no_users_found_for, userSearchResult.getNickName()));
167 | }
168 |
169 | @Override
170 | public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
171 | super.onCreateOptionsMenu(menu, inflater);
172 |
173 | inflater.inflate(R.menu.user_account_selection, menu);
174 |
175 | initSearchView(menu.findItem(R.id.menu_search));
176 | }
177 |
178 | @SuppressWarnings("ConstantConditions")
179 | private void initSearchView(final MenuItem searchMenuItem) {
180 | final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
181 | searchView.setQueryHint(getString(R.string.hint_enter_user_name));
182 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
183 |
184 | @Override
185 | public boolean onQueryTextSubmit(final String s) {
186 | final String nickName = s.trim();
187 | if (USER_NAME_PATTERN.matcher(nickName).matches()) {
188 | MenuItemCompat.collapseActionView(searchMenuItem);
189 | onUserNickSelected(nickName);
190 | }
191 | return true;
192 | }
193 |
194 | @Override
195 | public boolean onQueryTextChange(final String s) {
196 | final String nickName = s.trim();
197 | if (USER_NAME_PATTERN.matcher(nickName).matches()) {
198 | onUserNickSelected(nickName);
199 | }
200 | return true;
201 | }
202 | });
203 | MenuItemCompat.setOnActionExpandListener(searchMenuItem, new MenuItemCompat.OnActionExpandListener() {
204 | @Override
205 | public boolean onMenuItemActionExpand(final MenuItem item) {
206 | mExpandMenu = true;
207 | return true;
208 | }
209 |
210 | @Override
211 | public boolean onMenuItemActionCollapse(final MenuItem item) {
212 | mExpandMenu = false;
213 | return true;
214 | }
215 | });
216 | if (mExpandMenu) {
217 | MenuItemCompat.expandActionView(searchMenuItem);
218 | ((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).
219 | toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_NOT_ALWAYS);
220 | } else {
221 | MenuItemCompat.collapseActionView(searchMenuItem);
222 | }
223 | }
224 |
225 | public interface OnUserSelectedListener {
226 |
227 | void onUserSelected(final User user);
228 | }
229 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/widgets/CollageItemView.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.widgets;
2 |
3 | import android.content.Context;
4 | import android.graphics.BitmapFactory;
5 | import android.graphics.Matrix;
6 | import android.graphics.drawable.Drawable;
7 | import android.os.Handler;
8 | import android.support.v4.view.GestureDetectorCompat;
9 | import android.util.AttributeSet;
10 | import android.view.GestureDetector;
11 | import android.view.MotionEvent;
12 | import android.view.ScaleGestureDetector;
13 | import android.widget.ImageView;
14 |
15 | import com.azoft.azoft.collage.R;
16 | import com.azoft.azoft.collage.data.CollageRegionData;
17 | import com.azoft.azoft.collage.utils.CollageRegion;
18 | import com.squareup.picasso.Callback;
19 | import com.squareup.picasso.Picasso;
20 |
21 | /**
22 | * Will show empty view (plus view) or image data for this region it correct place. If this view is square image is scaled and no gesture can be
23 | * made, if not, image can be moved.
24 | *
25 | * Date: 4/8/2014
26 | * Time: 5:24 PM
27 | *
28 | * @author MiG35
29 | */
30 | @SuppressWarnings("UnusedDeclaration")
31 | public class CollageItemView extends ImageView {
32 |
33 | private static final float MIN_SCALE_FACTOR = 1f;
34 | private static final float MAX_SCALE_FACTOR = 5f;
35 |
36 | private CollageRegion mCollageRegion;
37 | private CollageRegionData mRegionData;
38 |
39 | private OnClickListener mOnClickListener;
40 | private GestureDetectorCompat mGestureDetector;
41 | private ScaleGestureDetector mScaleGestureDetector;
42 |
43 | private boolean mNeedInit = true;
44 |
45 | private float mMinScale;
46 | private float mMaxScale;
47 | private ScrollHolder mScrollHolder;
48 |
49 | public CollageItemView(final Context context) {
50 | super(context);
51 | init(context);
52 | }
53 |
54 | public CollageItemView(final Context context, final AttributeSet attrs) {
55 | super(context, attrs);
56 | init(context);
57 | }
58 |
59 | public CollageItemView(final Context context, final AttributeSet attrs, final int defStyle) {
60 | super(context, attrs, defStyle);
61 | init(context);
62 | }
63 |
64 | private void init(final Context context) {
65 | mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
66 | private static final float HALF = 0.5f;
67 |
68 | @Override
69 | public boolean onScale(final ScaleGestureDetector detector) {
70 | final float oldScaleFactor = mRegionData.getImageScale();
71 | // we use "+" but "*" because here it is more suitable I think
72 | float newScaleFactor = mRegionData.getImageScale() + (detector.getScaleFactor() - 1) * 0.7f;
73 | // Don't let the object get too small or too large.
74 | newScaleFactor = Math.max(MIN_SCALE_FACTOR, Math.min(newScaleFactor, MAX_SCALE_FACTOR));
75 |
76 | if (0 != Float.compare(oldScaleFactor, newScaleFactor)) {
77 | updateImagePosition(mMinScale * oldScaleFactor, mMinScale * newScaleFactor);
78 | mRegionData.setImageScale(newScaleFactor);
79 | updateScale();
80 | }
81 |
82 | return super.onScale(detector);
83 | }
84 |
85 | private void updateImagePosition(final float oldImageScaleFactor, final float newImageScaleFactor) {
86 | final float imageCenterX;
87 | final float imageCenterY;
88 | if (null == mRegionData.getImageLeft() || null == mRegionData.getImageTop()) {
89 | imageCenterX = (mScrollHolder.mScrollXMax + getWidth()) * HALF;
90 | imageCenterY = (mScrollHolder.mScrollYMax + getHeight()) * HALF;
91 | } else {
92 | imageCenterX = mScrollHolder.mScrollXMax * mRegionData.getImageLeft() + getWidth() * HALF;
93 | imageCenterY = mScrollHolder.mScrollYMax * mRegionData.getImageTop() + getHeight() * HALF;
94 | }
95 | final float newImageCenterX = imageCenterX * newImageScaleFactor / oldImageScaleFactor;
96 | final float newImageCenterY = imageCenterY * newImageScaleFactor / oldImageScaleFactor;
97 |
98 | final ScrollHolder scrollHolder = generateScrollHolder(newImageScaleFactor);
99 |
100 | mRegionData.setImageLeft(scrollHolder.mScrollXMax == 0 ? 0 :
101 | Math.max(0, Math.min(scrollHolder.mScrollXMax, (newImageCenterX - getWidth() * HALF) / scrollHolder.mScrollXMax)));
102 | mRegionData.setImageTop(scrollHolder.mScrollYMax == 0 ? 0 :
103 | Math.max(0, Math.min(scrollHolder.mScrollYMax, (newImageCenterY - getHeight() * HALF) / scrollHolder.mScrollYMax)));
104 | }
105 |
106 | @Override
107 | public boolean onScaleBegin(final ScaleGestureDetector detector) {
108 | return null != mScrollHolder;
109 | }
110 | });
111 | mGestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
112 |
113 | @Override
114 | public boolean onDown(final MotionEvent e) {
115 | return null != mOnClickListener || null != mScrollHolder;
116 | }
117 |
118 | @Override
119 | public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) {
120 | if (null != mScrollHolder) {
121 | final float curScrollX = getScrollX();
122 | final float curScrollY = getScrollY();
123 |
124 | scrollTo((int) (curScrollX + distanceX), (int) (curScrollY + distanceY));
125 | }
126 | return true;
127 | }
128 |
129 | @Override
130 | public boolean onSingleTapUp(final MotionEvent e) {
131 | if (null != mOnClickListener) {
132 | mOnClickListener.onClick(CollageItemView.this);
133 | }
134 | return true;
135 | }
136 | });
137 | }
138 |
139 | @Override
140 | public boolean onTouchEvent(final MotionEvent event) {
141 | boolean handle = false;
142 | if (null != mScrollHolder) {
143 | handle = mScaleGestureDetector.onTouchEvent(event);
144 | }
145 | handle |= mGestureDetector.onTouchEvent(event);
146 | return handle;
147 | }
148 |
149 | @Override
150 | protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
151 | super.onSizeChanged(w, h, oldw, oldh);
152 |
153 | if (oldw != 0 && oldh != 0) {
154 | mNeedInit = true;
155 | }
156 |
157 | new Handler().post(new Runnable() {
158 | @Override
159 | public void run() {
160 | if (mNeedInit) {
161 | setRegionData(mRegionData);
162 | }
163 | }
164 | });
165 | }
166 |
167 | @Override
168 | public void setOnClickListener(final OnClickListener onClickListener) {
169 | mOnClickListener = onClickListener;
170 | }
171 |
172 | public void setCollageRegion(final CollageRegion collageRegion) {
173 | mCollageRegion = collageRegion;
174 | }
175 |
176 | public CollageRegion getCollageRegion() {
177 | return mCollageRegion;
178 | }
179 |
180 | public void setRegionData(final CollageRegionData regionData) {
181 | if (mRegionData != regionData) {
182 | mNeedInit = true;
183 | mRegionData = regionData;
184 | updateRegionData();
185 | } else if (mNeedInit) {
186 | updateRegionData();
187 | }
188 | }
189 |
190 | private void updateRegionData() {
191 | mScrollHolder = null;
192 | setImageMatrix(null);
193 | setScaleType(ScaleType.FIT_XY);
194 |
195 | if (null == mRegionData) {
196 | mNeedInit = false;
197 | setImageResource(R.drawable.ic_action_new);
198 | } else {
199 | final int width = getWidth();
200 | final int height = getHeight();
201 |
202 | final BitmapFactory.Options options = new BitmapFactory.Options();
203 | options.inJustDecodeBounds = true;
204 |
205 | BitmapFactory.decodeFile(mRegionData.getImageFile().getPath(), options);
206 |
207 | if (0 == width || 0 == height || 0 == options.outWidth || 0 == options.outHeight) {
208 | return;
209 | }
210 | mNeedInit = false;
211 |
212 | final float scale = Math.max(1f * width / options.outWidth, 1f * height / options.outHeight);
213 | final int resultWidth;
214 | final int resultHeight;
215 | if (scale < 1) {
216 | resultWidth = (int) (options.outWidth * scale);
217 | resultHeight = (int) (options.outHeight * scale);
218 | } else {
219 | resultWidth = (int) (options.outWidth * Math.ceil(scale));
220 | resultHeight = (int) (options.outHeight * Math.ceil(scale));
221 | }
222 |
223 | Picasso.with(getContext()).load(mRegionData.getImageFile())
224 | .resize(resultWidth, resultHeight)
225 | .skipMemoryCache().noFade()
226 | .error(R.drawable.ic_action_new).into(this, new Callback() {
227 | @Override
228 | public void onSuccess() {
229 | final int width = getWidth();
230 | final int height = getHeight();
231 | if (0 == width || 0 == height) {
232 | return;
233 | }
234 | final Drawable drawable = getDrawable();
235 | if (null == drawable) {
236 | return;
237 | }
238 | final int bitmapWidth = drawable.getIntrinsicWidth();
239 | final int bitmapHeight = drawable.getIntrinsicHeight();
240 | if (bitmapWidth < 0 || bitmapHeight < 0) {
241 | return;
242 | }
243 |
244 | mMinScale = 1f * Math.max(1f * width / bitmapWidth, 1f * height / bitmapHeight);
245 | mMaxScale = mMinScale * MAX_SCALE_FACTOR;
246 |
247 | updateScale();
248 | }
249 |
250 | @Override
251 | public void onError() {
252 | // pass
253 | }
254 | }
255 | );
256 | }
257 | }
258 |
259 | private void updateScale() {
260 | final float scaleFactor = mMinScale * mRegionData.getImageScale();
261 | mScrollHolder = generateScrollHolder(scaleFactor);
262 | final Matrix matrix = new Matrix();
263 | matrix.setScale(scaleFactor, scaleFactor);
264 | setScaleType(ScaleType.MATRIX);
265 | setImageMatrix(matrix);
266 |
267 | if (mRegionData.getImageLeft() == null || mRegionData.getImageTop() == null) {
268 | scrollTo(mScrollHolder.mScrollXMax / 2, mScrollHolder.mScrollYMax / 2);
269 | } else {
270 | CollageItemView.super.scrollTo((int) (mRegionData.getImageLeft() * mScrollHolder.mScrollXMax),
271 | (int) (mRegionData.getImageTop() * mScrollHolder.mScrollYMax));
272 | }
273 | }
274 |
275 | private ScrollHolder generateScrollHolder(final float scaleFactor) {
276 | final int width = getWidth();
277 | final int height = getHeight();
278 | if (0 == width || 0 == height) {
279 | return ScrollHolder.EMPTY;
280 | }
281 | final Drawable drawable = getDrawable();
282 | if (null == drawable) {
283 | return ScrollHolder.EMPTY;
284 | }
285 | final int bitmapWidth = drawable.getIntrinsicWidth();
286 | final int bitmapHeight = drawable.getIntrinsicHeight();
287 | if (bitmapWidth < 0 || bitmapHeight < 0) {
288 | return ScrollHolder.EMPTY;
289 | }
290 |
291 | final int scrollXMax = Math.abs(Math.round(width - bitmapWidth * scaleFactor));
292 | final int scrollYMax = Math.abs(Math.round(height - bitmapHeight * scaleFactor));
293 | return new ScrollHolder(scrollXMax, scrollYMax);
294 | }
295 |
296 | @Override
297 | public void scrollTo(final int x, final int y) {
298 | int newScrollX = x;
299 | int newScrollY = y;
300 | if (null != mScrollHolder) {
301 | if (newScrollX > mScrollHolder.mScrollXMax) {
302 | newScrollX = mScrollHolder.mScrollXMax;
303 | }
304 | if (newScrollX < 0) {
305 | newScrollX = 0;
306 | }
307 | if (newScrollY > mScrollHolder.mScrollYMax) {
308 | newScrollY = mScrollHolder.mScrollYMax;
309 | }
310 | if (newScrollY < 0) {
311 | newScrollY = 0;
312 | }
313 |
314 | mRegionData.setImageLeft(mScrollHolder.mScrollXMax == 0 ? 0 : 1f * newScrollX / mScrollHolder.mScrollXMax);
315 | mRegionData.setImageTop(mScrollHolder.mScrollYMax == 0 ? 0 : 1f * newScrollY / mScrollHolder.mScrollYMax);
316 | }
317 |
318 | super.scrollTo(newScrollX, newScrollY);
319 | }
320 |
321 | private static class ScrollHolder {
322 |
323 | static final ScrollHolder EMPTY = new ScrollHolder();
324 |
325 | int mScrollXMax;
326 | int mScrollYMax;
327 |
328 | ScrollHolder(final int scrollXMax, final int scrollYMax) {
329 | mScrollXMax = scrollXMax;
330 | mScrollYMax = scrollYMax;
331 | }
332 |
333 | ScrollHolder() {
334 | }
335 | }
336 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/widgets/CollageViewGroup.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.widgets;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 |
8 | import com.azoft.azoft.collage.R;
9 | import com.azoft.azoft.collage.data.Collage;
10 | import com.azoft.azoft.collage.data.CollageFillData;
11 | import com.azoft.azoft.collage.data.CollageRegionData;
12 | import com.azoft.azoft.collage.utils.CollageRegion;
13 |
14 | /**
15 | * General view that construct all regions as CollageItemView children. This view calculate there sizes and location.
16 | * Can handle region clicks.
17 | *
18 | * Date: 4/8/2014
19 | * Time: 5:23 PM
20 | *
21 | * @author MiG35
22 | */
23 | @SuppressWarnings("UnusedDeclaration")
24 | public class CollageViewGroup extends SquareRelativeLayout {
25 |
26 | private CollageFillData mCollageFillData;
27 | private final OnClickListener mCollageItemClickListener = new OnClickListener() {
28 | @Override
29 | public void onClick(final View v) {
30 | if (null != mRegionClickListener && v instanceof CollageItemView) {
31 | mRegionClickListener.onRegionClicked(((CollageItemView) v).getCollageRegion());
32 | }
33 | }
34 | };
35 | private RegionClickListener mRegionClickListener;
36 |
37 | public CollageViewGroup(final Context context) {
38 | super(context);
39 | }
40 |
41 | public CollageViewGroup(final Context context, final AttributeSet attrs) {
42 | super(context, attrs);
43 | }
44 |
45 | public CollageViewGroup(final Context context, final AttributeSet attrs, final int defStyle) {
46 | super(context, attrs, defStyle);
47 | }
48 |
49 | @Override
50 | protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
51 | super.onSizeChanged(w, h, oldw, oldh);
52 |
53 | new Handler().post(new Runnable() {
54 | @Override
55 | public void run() {
56 | setCollage(mCollageFillData);
57 | }
58 | });
59 | }
60 |
61 | public void setCollage(final Collage collage) {
62 | setCollage(null == collage ? null : new CollageFillData(collage));
63 | }
64 |
65 | public void setCollage(final CollageFillData collageFillData) {
66 | if (mCollageFillData != collageFillData || getChildCount() != collageFillData.getRegionsCount()) {
67 | removeAllViews();
68 | mCollageFillData = collageFillData;
69 | initCollageViews();
70 | }
71 | }
72 |
73 | public void invalidateRegionData() {
74 | for (int i = 0; i < getChildCount(); ++i) {
75 | final View child = getChildAt(i);
76 | if (child instanceof CollageItemView) {
77 | final CollageItemView collageItemView = (CollageItemView) child;
78 | final CollageRegionData regionData = mCollageFillData.getRegionData(collageItemView.getCollageRegion());
79 | collageItemView.setRegionData(regionData);
80 | }
81 | }
82 | }
83 |
84 | @SuppressWarnings("ConstantConditions")
85 | private void updateClickEnable() {
86 | final boolean clicksEnabled = mRegionClickListener != null;
87 | for (int i = 0; i < getChildCount(); ++i) {
88 | final View child = getChildAt(i);
89 | if (clicksEnabled) {
90 | child.setOnClickListener(mCollageItemClickListener);
91 | } else {
92 | child.setOnClickListener(null);
93 | }
94 | }
95 | }
96 |
97 | @SuppressWarnings("ObjectAllocationInLoop")
98 | private void initCollageViews() {
99 | setBackgroundColor(getContext().getResources().getColor(R.color.collage_bg_color));
100 |
101 | final int width = getWidth();
102 | final int height = getHeight();
103 | if (null == mCollageFillData || width == 0 || height == 0) {
104 | return;
105 | }
106 | for (final CollageRegion collageRegion : mCollageFillData.getCollageRegions()) {
107 | final int collageWidth = (int) Math.round(collageRegion.getWidth() * width);
108 | final int collageHeight = (int) Math.round(collageRegion.getHeight() * height);
109 |
110 | final LayoutParams layoutParams = new LayoutParams(collageWidth, collageHeight);
111 | layoutParams.setMargins((int) Math.round(width * collageRegion.getLeft()), (int) Math.round(height * collageRegion.getTop()), 0, 0);
112 | final CollageItemView collageItemView = new CollageItemView(getContext());
113 | collageItemView.setCollageRegion(collageRegion);
114 | addView(collageItemView, layoutParams);
115 | }
116 | updateClickEnable();
117 | invalidateRegionData();
118 | }
119 |
120 | public void setRegionClickListener(final RegionClickListener regionClickListener) {
121 | mRegionClickListener = regionClickListener;
122 | updateClickEnable();
123 | }
124 |
125 | public interface RegionClickListener {
126 |
127 | void onRegionClicked(CollageRegion collageRegion);
128 | }
129 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/ui/widgets/SquareRelativeLayout.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.ui.widgets;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.RelativeLayout;
6 |
7 | /**
8 | * Help view that will be squared view with size as smallest size in measure.
9 | * Can't be used as WRAP_CONTENT on both sizes.
10 | *
11 | * Date: 4/9/2014
12 | * Time: 10:34 AM
13 | *
14 | * @author MiG35
15 | */
16 | @SuppressWarnings("UnusedDeclaration")
17 | public class SquareRelativeLayout extends RelativeLayout {
18 |
19 | public SquareRelativeLayout(final Context context) {
20 | super(context);
21 | }
22 |
23 | public SquareRelativeLayout(final Context context, final AttributeSet attrs) {
24 | super(context, attrs);
25 | }
26 |
27 | public SquareRelativeLayout(final Context context, final AttributeSet attrs, final int defStyle) {
28 | super(context, attrs, defStyle);
29 | }
30 |
31 | @Override
32 | protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
33 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
34 | final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
35 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
36 | final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
37 | if (widthMode == MeasureSpec.UNSPECIFIED && heightMode == MeasureSpec.UNSPECIFIED) {
38 | throw new IllegalStateException("this view should have at least one specific or max size");
39 | }
40 | final int neededSize;
41 | if (widthMode == MeasureSpec.UNSPECIFIED) {
42 | neededSize = heightSize;
43 | } else if (heightMode == MeasureSpec.UNSPECIFIED) {
44 | neededSize = widthSize;
45 | } else {
46 | neededSize = Math.min(widthSize, heightSize);
47 | }
48 |
49 | super.onMeasure(MeasureSpec.makeMeasureSpec(neededSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(neededSize, MeasureSpec.EXACTLY));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/utils/CollageRegion.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.utils;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Contains CollageRegion position in Collage object. All coordinates are from 0 to 1.
7 | *
8 | * Date: 4/8/2014
9 | * Time: 4:14 PM
10 | *
11 | * @author MiG35
12 | */
13 | public class CollageRegion implements Serializable {
14 |
15 | private static final long serialVersionUID = -599596516243533187L;
16 |
17 | private final int mId;
18 |
19 | private final double mLeft;
20 | private final double mTop;
21 | private final double mRight;
22 | private final double mBottom;
23 |
24 | /**
25 | * @param id - unique region id in collage
26 | * @param left - should be in [0, 1] region.
27 | * @param top - should be in [0, 1] region.
28 | * @param right - should be in [0, 1] region. Should be greater then left.
29 | * @param bottom - should be in [0, 1] region. Should be greater then top.
30 | */
31 | public CollageRegion(final int id, final double left, final double top, final double right, final double bottom) {
32 | //noinspection OverlyComplexBooleanExpression
33 | if (0 > left || 0 > top || left > 1 || top > 1) {
34 | throw new IllegalArgumentException("left and top positions should be from 0 to 1");
35 | }
36 | if (left >= right || top >= bottom) {
37 | throw new IllegalArgumentException("left should be less then right, and top should be less then bottom");
38 | }
39 | mId = id;
40 | mLeft = left;
41 | mTop = top;
42 | mRight = right;
43 | mBottom = bottom;
44 | }
45 |
46 | public int getId() {
47 | return mId;
48 | }
49 |
50 | public double getLeft() {
51 | return mLeft;
52 | }
53 |
54 | public double getTop() {
55 | return mTop;
56 | }
57 |
58 | public double getRight() {
59 | return mRight;
60 | }
61 |
62 | public double getBottom() {
63 | return mBottom;
64 | }
65 |
66 | public double getWidth() {
67 | return mRight - mLeft;
68 | }
69 |
70 | public double getHeight() {
71 | return mBottom - mTop;
72 | }
73 |
74 | @Override
75 | public boolean equals(final Object o) {
76 | if (this == o) {
77 | return true;
78 | }
79 | if (!(o instanceof CollageRegion)) {
80 | return false;
81 | }
82 |
83 | final CollageRegion otherCollageRegion = (CollageRegion) o;
84 |
85 | return mId == otherCollageRegion.mId;
86 | }
87 |
88 | @Override
89 | public int hashCode() {
90 | return mId;
91 | }
92 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/utils/CommonUtils.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.utils;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.pm.ResolveInfo;
6 | import android.net.ConnectivityManager;
7 | import android.net.NetworkInfo;
8 | import android.net.Uri;
9 | import android.os.Environment;
10 |
11 | import com.mig35.loaderlib.exceptions.NoNetworkException;
12 | import com.azoft.azoft.collage.R;
13 | import com.azoft.azoft.collage.app.CollageApplication;
14 | import com.azoft.azoft.collage.exceptions.DiskWriteException;
15 | import com.azoft.azoft.collage.exceptions.InternalServerException;
16 |
17 | import java.io.BufferedInputStream;
18 | import java.io.BufferedOutputStream;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.io.OutputStream;
23 | import java.util.List;
24 |
25 | public final class CommonUtils {
26 |
27 | public static File getCacheFileDir() {
28 | File rootCacheDir = null;
29 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
30 | rootCacheDir = CollageApplication.getInstance().getExternalCacheDir();
31 | }
32 | if (checkAndCreateDirIfNotExists(rootCacheDir)) {
33 | return rootCacheDir;
34 | }
35 | rootCacheDir = getInternalCacheDir();
36 | if (checkAndCreateDirIfNotExists(rootCacheDir)) {
37 | return rootCacheDir;
38 | }
39 |
40 | return null;
41 | }
42 |
43 | public static File getInternalCacheDir() {
44 | final File rootCacheDir = CollageApplication.getInstance().getCacheDir();
45 |
46 | if (checkAndCreateDirIfNotExists(rootCacheDir)) {
47 | return rootCacheDir;
48 | }
49 |
50 | return null;
51 | }
52 |
53 | public static File getInternalFilesDir() {
54 | final File rootFilesDir = CollageApplication.getInstance().getFilesDir();
55 |
56 | if (checkAndCreateDirIfNotExists(rootFilesDir)) {
57 | return rootFilesDir;
58 | }
59 |
60 | return null;
61 | }
62 |
63 | public static boolean checkAndCreateDirIfNotExists(final File rootCacheDir) {
64 | if (null != rootCacheDir) {
65 | if (!rootCacheDir.exists() && rootCacheDir.mkdirs()) {
66 | return true;
67 | }
68 |
69 | if (rootCacheDir.exists()) {
70 | return true;
71 | }
72 | }
73 | return false;
74 | }
75 |
76 | /**
77 | * Will search connected or connecting network. If found do nothing, if not,
78 | * throws exception
79 | *
80 | * @throws java.io.IOException if no network found
81 | */
82 | public static void checkInternet() throws IOException {
83 | final ConnectivityManager cm = (ConnectivityManager) CollageApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
84 | final NetworkInfo netInfo = cm.getActiveNetworkInfo();
85 | if (netInfo == null || !netInfo.isConnectedOrConnecting()) {
86 | throw new NoNetworkException();
87 | }
88 | }
89 |
90 | public static void writeNetworkStreamToAnOtherStream(final InputStream inputStream, final OutputStream outputStream)
91 | throws DiskWriteException, InternalServerException, IOException {
92 | if (null == inputStream || null == outputStream) {
93 | throw new IllegalArgumentException("input and output streams can't be null");
94 | }
95 |
96 | boolean read = true;
97 | try {
98 | try {
99 | final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
100 | final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
101 | final byte[] buffer = new byte[2048];
102 | int readCount;
103 | while ((readCount = bufferedInputStream.read(buffer)) != -1) {
104 | read = false;
105 | bufferedOutputStream.write(buffer, 0, readCount);
106 | read = true;
107 | }
108 | bufferedOutputStream.flush();
109 | } finally {
110 | inputStream.close();
111 | }
112 | } catch (final IOException e) {
113 | if (read) {
114 | checkInternet();
115 | throw new InternalServerException(e);
116 | } else {
117 | throw new DiskWriteException(e);
118 | }
119 | } finally {
120 | outputStream.close();
121 | }
122 | }
123 |
124 | private CommonUtils() {
125 | }
126 |
127 | @SuppressWarnings("ConstantConditions")
128 | public static void sendEmailWithAttachment(final Context context, final String path, final String emailSubject) {
129 | final Uri uriAsPath = Uri.parse(path);
130 | final Intent emailIntent = new Intent(Intent.ACTION_SEND);
131 | emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
132 | emailIntent.putExtra(Intent.EXTRA_STREAM, uriAsPath);
133 | emailIntent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
134 | emailIntent.putExtra(Intent.EXTRA_TEXT, emailSubject);
135 | emailIntent.setType("image/*");
136 | final List emailActivities = context.getPackageManager().queryIntentActivities(emailIntent, 0);
137 | // we should grand all interested apps read permission
138 | for (final ResolveInfo resolveInfo : emailActivities) {
139 | if (null != resolveInfo.activityInfo) {
140 | context.grantUriPermission(resolveInfo.activityInfo.packageName, uriAsPath, Intent.FLAG_GRANT_READ_URI_PERMISSION);
141 | }
142 | }
143 |
144 | emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
145 | context.startActivity(Intent.createChooser(emailIntent, context.getString(R.string.text_email_chooser)));
146 | }
147 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/utils/MediaUtils.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.utils;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | import com.azoft.azoft.collage.exceptions.DiskWriteException;
6 |
7 | import java.io.File;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 |
12 | /**
13 | * Helper class to store bitmap as file with provider access.
14 | *
15 | * Date: 4/10/2014
16 | * Time: 3:24 PM
17 | *
18 | * @author MiG35
19 | */
20 | public final class MediaUtils {
21 |
22 | private static final String STORAGE_FILE_PATH = "mediadata";
23 |
24 | private static final String STORAGE_AUTHORITY = "com.azoft.azoft.collage.contentproviders.media";
25 | private static final String STORAGE_AUTHORITY_PATH = "images";
26 |
27 | private MediaUtils() {
28 | }
29 |
30 | public static String insertImage(final Bitmap source, final String title) throws DiskWriteException {
31 | final File storageFile = getStoreFile(title);
32 | if (null == storageFile) {
33 | return null;
34 | }
35 | try {
36 | final OutputStream imageOut = new FileOutputStream(storageFile);
37 | try {
38 | source.compress(Bitmap.CompressFormat.PNG, 100, imageOut);
39 | } finally {
40 | imageOut.close();
41 | }
42 | return "content://" + STORAGE_AUTHORITY + '/' + STORAGE_AUTHORITY_PATH + '/' + title;
43 | } catch (final IOException e) {
44 | throw new DiskWriteException(e);
45 | }
46 | }
47 |
48 | static File getStoreFile(final String title) {
49 | final File internalFilesDir = CommonUtils.getInternalFilesDir();
50 | if (null == internalFilesDir) {
51 | return null;
52 | }
53 | final File mediaDataDir = new File(internalFilesDir, STORAGE_FILE_PATH);
54 | if (!mediaDataDir.exists() && !mediaDataDir.mkdir()) {
55 | return null;
56 | }
57 | return new File(mediaDataDir, title);
58 | }
59 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/utils/collagegenerators/CollageFactory.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.utils.collagegenerators;
2 |
3 | import com.azoft.azoft.collage.data.Collage;
4 |
5 | /**
6 | * This class helps to create collages from it's number.
7 | *
8 | * Date: 4/8/2014
9 | * Time: 4:46 PM
10 | *
11 | * @author MiG35
12 | */
13 | public interface CollageFactory {
14 |
15 | Collage getCollage(final int number);
16 |
17 | int getCollageCount();
18 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/java/com/azoft/azoft/collage/utils/collagegenerators/SimpleCollageGenerator.java:
--------------------------------------------------------------------------------
1 | package com.azoft.azoft.collage.utils.collagegenerators;
2 |
3 | import android.util.SparseArray;
4 |
5 | import com.azoft.azoft.collage.data.Collage;
6 | import com.azoft.azoft.collage.utils.CollageRegion;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * Generator with hardcoded numbers of collagees.
13 | *
14 | * Date: 4/8/2014
15 | * Time: 4:20 PM
16 | *
17 | * @author MiG35
18 | */
19 | public final class SimpleCollageGenerator implements CollageFactory {
20 |
21 | private static final int KOLAJ_ITEMS_COUNT = 4;
22 | private final SparseArray mCollages = new SparseArray<>();
23 |
24 | @Override
25 | public Collage getCollage(final int number) {
26 | if (number < 0 || number >= 4) {
27 | throw new IllegalArgumentException("SimpleCollageGenerator can create collagees from 0 to 3 items only");
28 | }
29 | Collage collage = mCollages.get(number);
30 | if (null == collage) {
31 | collage = generateCollage(number);
32 | mCollages.put(number, collage);
33 | }
34 | return collage;
35 | }
36 |
37 | @Override
38 | public int getCollageCount() {
39 | return KOLAJ_ITEMS_COUNT;
40 | }
41 |
42 | @SuppressWarnings({"ValueOfIncrementOrDecrementUsed", "MagicNumber"})
43 | private Collage generateCollage(final int number) {
44 | final List collageRegions = new ArrayList<>();
45 | int regionId = 0;
46 | if (0 == number) {
47 | collageRegions.add(new CollageRegion(regionId, 0.01, 0.01, 0.99, 0.99));
48 | } else if (1 == number) {
49 | collageRegions.add(new CollageRegion(regionId++, 0.01, 0.01, 0.49d, 0.99));
50 | collageRegions.add(new CollageRegion(regionId, 0.51d, 0.01, 0.99, 0.99));
51 | } else if (2 == number) {
52 | collageRegions.add(new CollageRegion(regionId++, 0.01, 0.01, 0.49d, 0.99));
53 | collageRegions.add(new CollageRegion(regionId++, 0.51d, 0.01, 0.99, 0.49d));
54 | collageRegions.add(new CollageRegion(regionId, 0.51d, 0.51d, 0.99, 0.99));
55 | } else if (3 == number) {
56 | collageRegions.add(new CollageRegion(regionId++, 0.01, 0.01, 0.49d, 0.49d));
57 | collageRegions.add(new CollageRegion(regionId++, 0.01, 0.51d, 0.49d, 0.99));
58 | collageRegions.add(new CollageRegion(regionId++, 0.51d, 0.01, 0.99, 0.49d));
59 | collageRegions.add(new CollageRegion(regionId, 0.51d, 0.51d, 0.99, 0.99));
60 | }
61 | return new Collage(collageRegions);
62 | }
63 | }
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_picture.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_share.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/ic_action_user.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-hdpi/selected_collage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-hdpi/selected_collage.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_picture.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_share.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/ic_action_user.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-mdpi/selected_collage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-mdpi/selected_collage.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_picture.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_share.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/ic_action_user.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xhdpi/selected_collage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xhdpi/selected_collage.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_picture.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_action_share.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/drawable/ic_action_new.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/Azoft-Collage/src/main/res/drawable/ic_action_new.9.png
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/activity_instagram_auth.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/activity_single_fragment.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/activity_start.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
13 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/fragment_collage_builder.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/fragment_collage_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
11 |
12 |
16 |
17 |
18 |
19 |
24 |
25 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/fragment_collage_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/fragment_image_selection_from_user_feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
18 |
19 |
26 |
27 |
33 |
34 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/fragment_user_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
17 |
18 |
25 |
26 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/item_collage.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/item_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
14 |
20 |
21 |
27 |
28 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/layout/item_user_feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
17 |
18 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/menu/collage_builder.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/menu/collage_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/menu/image_selection_user_feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/menu/start_collage.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/menu/user_account_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Коллаж Azoft
5 |
6 |
7 | Ошибка подключения к серверу.
8 | Отсутствует подключение к Интернету.
9 | Недостаточно прав совершить это действие.
10 | Изображения у пользователя не найдены.
11 | Произошла неизвестная ошибка. Попробуйте повторить позднее.
12 | Ошибка обработки ответа сервера.
13 | Ошибка работы с дисокм. Возможно он заполнен.
14 | Ввод
15 | Ок
16 |
17 |
18 | Ошибка при авторизации в Instagram. Попробуйти повторить снова.
19 |
20 |
21 | Выберите пользователя
22 | %s
23 | Выберите пользователя
24 | Выберите коллаж
25 |
26 |
27 | Поиск по нику пользователя
28 | Результаты для \"%s\"
29 | Ник пользователя
30 | Ни одного пользователя не найдено для %s
31 | Давай коллаж!
32 |
33 |
34 | Создание коллажа
35 | Заполните все элементы коллажа
36 | Превью
37 |
38 |
39 | Выберите картинку
40 | Картинки для %s не найдены
41 | Обновить данные
42 |
43 |
44 | Превью
45 | Поделиться
46 | Поделиться используя…
47 | Ошибка
48 | Извините, но коллаж не был создан. Возможно из-за ошибки сохранения или из-за нехватки памяти…
49 | collageimage.png
50 | Коллаж
51 |
52 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #fff
5 |
6 | #000
7 |
8 | #80000000
9 |
10 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 80dp
4 | 10dp
5 |
6 | 120dp
7 | 5dp
8 |
9 | 90dp
10 | 2dp
11 |
12 | 1dp
13 |
14 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Azoft-Collage
5 |
6 |
7 | Failed to connect to server.
8 | No connection to the network.
9 | You are not allowed to do this.
10 | User has no images.
11 | An unknown error has occurred. Please try again later.
12 | Error processing server response.
13 | Problems in disk writing. Maybe it is full.
14 | Enter
15 | Ok
16 |
17 |
18 | Error during Instagram login process. Please, try again.
19 |
20 |
21 | Select user please
22 | %s
23 | Please select user first
24 | Please select collage first
25 |
26 |
27 | Search for user\'s nickname
28 | Search results for \"%s\"
29 | User Nickname
30 | No users found for %s
31 | Create collage
32 |
33 |
34 | Collage editor
35 | Please fill all image items first
36 | Preview
37 |
38 |
39 | Select an image
40 | No %s\'s images found
41 | Update feed
42 |
43 |
44 | Preview
45 | Share
46 | Share using…
47 | Error
48 | Sorry but your collage can\'t be created. May be it is because problem with disk space or memory issue…
49 | collageimage.png
50 | Collage
51 |
52 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/Azoft-Collage/src/main/res/xml/filepaths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.5.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | mavenCentral()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/device-2016-01-15-125125.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/device-2016-01-15-125125.mp4
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Feb 09 16:06:58 NOVT 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/privacy_policy.html:
--------------------------------------------------------------------------------
1 | Your privacy is important to us. We use the information you provide about yourself when using this application only to create a collage photo. We do not share this information with outside parties.
2 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azoft/CollageMaker-Android/353328896b64f31b3438ea6459f98fc5e9524efa/readme.md
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':Azoft-Collage'
--------------------------------------------------------------------------------