getPictureSizes() {
41 | return pictureSizes;
42 | }
43 |
44 | /*private int getScore(CameraSelectionCriteria criteria) {
45 | int score = 10;
46 | if (criteria != null) {
47 | if ((criteria.getFacing().isFront() && frontCamera != Camera.CameraInfo.CAMERA_FACING_FRONT) || (!criteria.getFacing().isFront() && frontCamera != Camera.CameraInfo.CAMERA_FACING_BACK)) {
48 | score = 0;
49 | }
50 | }
51 | return (score);
52 | }*/
53 | }
54 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/GeoPoint.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class GeoPoint extends TLObject {
5 | public double _long;
6 | public double lat;
7 |
8 | public static GeoPoint TLdeserialize(AbstractSerializedData stream, int constructor,
9 | boolean exception) {
10 | GeoPoint result = null;
11 | switch (constructor) {
12 | case 0x1117dd5f:
13 | result = new TL_geoPointEmpty();
14 | break;
15 | case 0x2049d70c:
16 | result = new TL_geoPoint();
17 | break;
18 | }
19 | if (result == null && exception) {
20 | throw new RuntimeException(
21 | String.format("can't parse magic %x in GeoPoint", constructor));
22 | }
23 | if (result != null) {
24 | result.readParams(stream, exception);
25 | }
26 | return result;
27 | }
28 |
29 | public static class TL_geoPointEmpty extends GeoPoint {
30 | public static int constructor = 0x1117dd5f;
31 |
32 | public void serializeToStream(AbstractSerializedData stream) {
33 | stream.writeInt32(constructor);
34 | }
35 | }
36 |
37 | public static class TL_geoPoint extends GeoPoint {
38 | public static int constructor = 0x2049d70c;
39 |
40 | public void readParams(AbstractSerializedData stream, boolean exception) {
41 | _long = stream.readDouble(exception);
42 | lat = stream.readDouble(exception);
43 | }
44 |
45 | public void serializeToStream(AbstractSerializedData stream) {
46 | stream.writeInt32(constructor);
47 | stream.writeDouble(_long);
48 | stream.writeDouble(lat);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hc/gallery/util/StorageType.java:
--------------------------------------------------------------------------------
1 | package com.hc.gallery.util;
2 |
3 | /**
4 | * 创建者:邓浩宸
5 | * 时间 :2017/4/20 13:01
6 | * 描述 :TODO 请描述该类职责
7 | */
8 | public enum StorageType {
9 | TYPE_LOG(DirectoryName.LOG_DIRECTORY_NAME),
10 | TYPE_TEMP(DirectoryName.TEMP_DIRECTORY_NAME),
11 | TYPE_FILE(DirectoryName.FILE_DIRECTORY_NAME),
12 | TYPE_AUDIO(DirectoryName.AUDIO_DIRECTORY_NAME),
13 | TYPE_IMAGE(DirectoryName.IMAGE_DIRECTORY_NAME),
14 | TYPE_VIDEO(DirectoryName.VIDEO_DIRECTORY_NAME),
15 | TYPE_THUMB_IMAGE(DirectoryName.THUMB_DIRECTORY_NAME),
16 | TYPE_THUMB_VIDEO(DirectoryName.THUMB_DIRECTORY_NAME),
17 | ;
18 | private DirectoryName storageDirectoryName;
19 | private long storageMinSize;
20 |
21 | public String getStoragePath() {
22 | return storageDirectoryName.getPath();
23 | }
24 |
25 | public long getStorageMinSize() {
26 | return storageMinSize;
27 | }
28 |
29 | StorageType(DirectoryName dirName) {
30 | this(dirName, StorageUtil.THRESHOLD_MIN_SPCAE);
31 | }
32 |
33 | StorageType(DirectoryName dirName, long storageMinSize) {
34 | this.storageDirectoryName = dirName;
35 | this.storageMinSize = storageMinSize;
36 | }
37 |
38 | enum DirectoryName {
39 | AUDIO_DIRECTORY_NAME("audio/"),
40 | DATA_DIRECTORY_NAME("data/"),
41 | FILE_DIRECTORY_NAME("file/"),
42 | LOG_DIRECTORY_NAME("log/"),
43 | TEMP_DIRECTORY_NAME("temp/"),
44 | IMAGE_DIRECTORY_NAME("image/"),
45 | THUMB_DIRECTORY_NAME("thumb/"),
46 | VIDEO_DIRECTORY_NAME("video/"),
47 | ;
48 |
49 | private String path;
50 |
51 | public String getPath() {
52 | return path;
53 | }
54 |
55 | private DirectoryName(String path) {
56 | this.path = path;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/gallery/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | KrGallery
4 |
5 | Photos
6 | Video
7 | All Photos
8 | All Videos
9 | No photos yet
10 | No videos yet
11 | FIND IMAGES
12 | FIND GIFS
13 | No recent photos
14 | No recent GIFs
15 | No results
16 | CROP
17 | Photo
18 | %1$d of %2$d
19 | Set
20 | Album
21 |
22 | Clear search history?
23 | Clear
24 |
25 | Search web
26 | Search GIFs
27 |
28 | WEB SEARCH
29 | You can select up to %d pictures
30 |
31 | Done
32 | Cancel
33 | Preview
34 | Failed to read an album, please check permissions
35 |
36 |
37 | 视频文件大小为: %1$dKB,
38 | 视频文件大小为: %1$.2fMB,
39 | 视频已超限,大小为: %1$dKB,
40 | 视频已超限,大小为: %1$.2fMB,
41 | 是否发送该视频?
42 |
--------------------------------------------------------------------------------
/gallery/src/main/res/layout/dialog_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
25 |
26 |
30 |
31 |
39 |
40 |
44 |
45 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/utils/DispatchQueue.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.utils;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 |
7 | import java.util.concurrent.CountDownLatch;
8 |
9 | public class DispatchQueue extends Thread {
10 |
11 | private volatile Handler handler = null;
12 | private CountDownLatch syncLatch = new CountDownLatch(1);
13 |
14 | public DispatchQueue(final String threadName) {
15 | setName(threadName);
16 | start();
17 | }
18 |
19 | private void sendMessage(Message msg, int delay) {
20 | try {
21 | syncLatch.await();
22 | if (delay <= 0) {
23 | handler.sendMessage(msg);
24 | } else {
25 | handler.sendMessageDelayed(msg, delay);
26 | }
27 | } catch (Exception e) {
28 | e.printStackTrace();
29 | }
30 | }
31 |
32 | public void cancelRunnable(Runnable runnable) {
33 | try {
34 | syncLatch.await();
35 | handler.removeCallbacks(runnable);
36 | } catch (Exception e) {
37 | e.printStackTrace();
38 | }
39 | }
40 |
41 | public void postRunnable(Runnable runnable) {
42 | postRunnable(runnable, 0);
43 | }
44 |
45 | public void postRunnable(Runnable runnable, long delay) {
46 | try {
47 | syncLatch.await();
48 | if (delay <= 0) {
49 | handler.post(runnable);
50 | } else {
51 | handler.postDelayed(runnable, delay);
52 | }
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | }
56 | }
57 |
58 | public void cleanupQueue() {
59 | try {
60 | syncLatch.await();
61 | handler.removeCallbacksAndMessages(null);
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | }
66 |
67 | @Override
68 | public void run() {
69 | Looper.prepare();
70 | handler = new Handler();
71 | syncLatch.countDown();
72 | Looper.loop();
73 | }
74 | }
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/camera/Size.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This is the source code of Telegram for Android v. 3.x.x.
3 | * It is licensed under GNU GPL v. 2 or later.
4 | * You should have received a copy of the license in this archive (see LICENSE).
5 | *
6 | * Copyright Nikolai Kudashov, 2013-2017.
7 | */
8 |
9 | package com.dhc.gallery.camera;
10 |
11 | public final class Size {
12 |
13 | public Size(int width, int height) {
14 | mWidth = width;
15 | mHeight = height;
16 | }
17 |
18 | public int getWidth() {
19 | return mWidth;
20 | }
21 |
22 | public int getHeight() {
23 | return mHeight;
24 | }
25 |
26 | @Override
27 | public boolean equals(final Object obj) {
28 | if (obj == null) {
29 | return false;
30 | }
31 | if (this == obj) {
32 | return true;
33 | }
34 | if (obj instanceof Size) {
35 | Size other = (Size) obj;
36 | return mWidth == other.mWidth && mHeight == other.mHeight;
37 | }
38 | return false;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return mWidth + "x" + mHeight;
44 | }
45 |
46 | private static NumberFormatException invalidSize(String s) {
47 | throw new NumberFormatException("Invalid Size: \"" + s + "\"");
48 | }
49 |
50 | public static Size parseSize(String string) throws NumberFormatException {
51 | int sep_ix = string.indexOf('*');
52 | if (sep_ix < 0) {
53 | sep_ix = string.indexOf('x');
54 | }
55 | if (sep_ix < 0) {
56 | throw invalidSize(string);
57 | }
58 | try {
59 | return new Size(Integer.parseInt(string.substring(0, sep_ix)), Integer.parseInt(string.substring(sep_ix + 1)));
60 | } catch (NumberFormatException e) {
61 | throw invalidSize(string);
62 | }
63 | }
64 |
65 | @Override
66 | public int hashCode() {
67 | return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
68 | }
69 |
70 | private final int mWidth;
71 | private final int mHeight;
72 | }
73 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/SizeNotifierFrameLayoutPhoto.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.components;
2 |
3 | import android.content.Context;
4 | import android.graphics.Rect;
5 | import android.view.View;
6 | import android.view.WindowManager;
7 | import android.widget.FrameLayout;
8 |
9 | import com.dhc.gallery.utils.AndroidUtilities;
10 |
11 | public class SizeNotifierFrameLayoutPhoto extends FrameLayout {
12 |
13 | private Rect rect = new Rect();
14 | private int keyboardHeight;
15 | private SizeNotifierFrameLayoutPhotoDelegate delegate;
16 | private WindowManager windowManager;
17 |
18 | public interface SizeNotifierFrameLayoutPhotoDelegate {
19 | void onSizeChanged(int keyboardHeight, boolean isWidthGreater);
20 | }
21 |
22 | public SizeNotifierFrameLayoutPhoto(Context context) {
23 | super(context);
24 | }
25 |
26 | public void setDelegate(SizeNotifierFrameLayoutPhotoDelegate delegate) {
27 | this.delegate = delegate;
28 | }
29 |
30 | @Override
31 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
32 | super.onLayout(changed, l, t, r, b);
33 | notifyHeightChanged();
34 | }
35 |
36 | public int getKeyboardHeight() {
37 | View rootView = getRootView();
38 | int usableViewHeight = rootView.getHeight() - AndroidUtilities.getViewInset(rootView);
39 | getWindowVisibleDisplayFrame(rect);
40 | int top = rect.top;
41 | int size = AndroidUtilities.displaySize.y - top - usableViewHeight;
42 | if (size <= AndroidUtilities.dp(10)) {
43 | size = 0;
44 | }
45 | return size;
46 | }
47 |
48 | public void notifyHeightChanged() {
49 | if (delegate != null) {
50 | keyboardHeight = getKeyboardHeight();
51 | final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y;
52 | post(new Runnable() {
53 | @Override
54 | public void run() {
55 | if (delegate != null) {
56 | delegate.onSizeChanged(keyboardHeight, isWidthGreater);
57 | }
58 | }
59 | });
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/InputFile.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class InputFile extends TLObject {
5 | public long id;
6 | public int parts;
7 | public String name;
8 | public String md5_checksum;
9 |
10 | public static InputFile TLdeserialize(AbstractSerializedData stream, int constructor,
11 | boolean exception) {
12 | InputFile result = null;
13 | switch (constructor) {
14 | case 0xfa4f0bb5:
15 | result = new TL_inputFileBig();
16 | break;
17 | case 0xf52ff27f:
18 | result = new TL_inputFile();
19 | break;
20 | }
21 | if (result == null && exception) {
22 | throw new RuntimeException(
23 | String.format("can't parse magic %x in InputFile", constructor));
24 | }
25 | if (result != null) {
26 | result.readParams(stream, exception);
27 | }
28 | return result;
29 | }
30 |
31 | public static class TL_inputFileBig extends InputFile {
32 | public static int constructor = 0xfa4f0bb5;
33 |
34 | public void readParams(AbstractSerializedData stream, boolean exception) {
35 | id = stream.readInt64(exception);
36 | parts = stream.readInt32(exception);
37 | name = stream.readString(exception);
38 | }
39 |
40 | public void serializeToStream(AbstractSerializedData stream) {
41 | stream.writeInt32(constructor);
42 | stream.writeInt64(id);
43 | stream.writeInt32(parts);
44 | stream.writeString(name);
45 | }
46 | }
47 |
48 | public static class TL_inputFile extends InputFile {
49 | public static int constructor = 0xf52ff27f;
50 |
51 | public void readParams(AbstractSerializedData stream, boolean exception) {
52 | id = stream.readInt64(exception);
53 | parts = stream.readInt32(exception);
54 | name = stream.readString(exception);
55 | md5_checksum = stream.readString(exception);
56 | }
57 |
58 | public void serializeToStream(AbstractSerializedData stream) {
59 | stream.writeInt32(constructor);
60 | stream.writeInt64(id);
61 | stream.writeInt32(parts);
62 | stream.writeString(name);
63 | stream.writeString(md5_checksum);
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/InputStickerSet.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class InputStickerSet extends TLObject {
5 | public long id;
6 | public long access_hash;
7 | public String short_name;
8 |
9 | public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int constructor,
10 | boolean exception) {
11 | InputStickerSet result = null;
12 | switch (constructor) {
13 | case 0xffb62b95:
14 | result = new TL_inputStickerSetEmpty();
15 | break;
16 | case 0x9de7a269:
17 | result = new TL_inputStickerSetID();
18 | break;
19 | case 0x861cc8a0:
20 | result = new TL_inputStickerSetShortName();
21 | break;
22 | }
23 | if (result == null && exception) {
24 | throw new RuntimeException(
25 | String.format("can't parse magic %x in InputStickerSet", constructor));
26 | }
27 | if (result != null) {
28 | result.readParams(stream, exception);
29 | }
30 | return result;
31 | }
32 |
33 | public static class TL_inputStickerSetEmpty extends InputStickerSet {
34 | public static int constructor = 0xffb62b95;
35 |
36 | public void serializeToStream(AbstractSerializedData stream) {
37 | stream.writeInt32(constructor);
38 | }
39 | }
40 |
41 | public static class TL_inputStickerSetID extends InputStickerSet {
42 | public static int constructor = 0x9de7a269;
43 |
44 | public void readParams(AbstractSerializedData stream, boolean exception) {
45 | id = stream.readInt64(exception);
46 | access_hash = stream.readInt64(exception);
47 | }
48 |
49 | public void serializeToStream(AbstractSerializedData stream) {
50 | stream.writeInt32(constructor);
51 | stream.writeInt64(id);
52 | stream.writeInt64(access_hash);
53 | }
54 | }
55 |
56 | public static class TL_inputStickerSetShortName extends InputStickerSet {
57 | public static int constructor = 0x861cc8a0;
58 |
59 | public void readParams(AbstractSerializedData stream, boolean exception) {
60 | short_name = stream.readString(exception);
61 | }
62 |
63 | public void serializeToStream(AbstractSerializedData stream) {
64 | stream.writeInt32(constructor);
65 | stream.writeString(short_name);
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/InputFileLocation.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class InputFileLocation extends TLObject {
5 | public long id;
6 | public long access_hash;
7 | public long volume_id;
8 | public int local_id;
9 | public long secret;
10 |
11 | public static InputFileLocation TLdeserialize(AbstractSerializedData stream, int constructor,
12 | boolean exception) {
13 | InputFileLocation result = null;
14 | switch (constructor) {
15 | case 0xf5235d55:
16 | result = new TL_inputEncryptedFileLocation();
17 | break;
18 | case 0x4e45abe9:
19 | result = new TL_inputDocumentFileLocation();
20 | break;
21 | case 0x14637196:
22 | result = new TL_inputFileLocation();
23 | break;
24 | }
25 | if (result == null && exception) {
26 | throw new RuntimeException(
27 | String.format("can't parse magic %x in InputFileLocation", constructor));
28 | }
29 | if (result != null) {
30 | result.readParams(stream, exception);
31 | }
32 | return result;
33 | }
34 |
35 | public static class TL_inputEncryptedFileLocation extends InputFileLocation {
36 | public static int constructor = 0xf5235d55;
37 |
38 | public void readParams(AbstractSerializedData stream, boolean exception) {
39 | id = stream.readInt64(exception);
40 | access_hash = stream.readInt64(exception);
41 | }
42 |
43 | public void serializeToStream(AbstractSerializedData stream) {
44 | stream.writeInt32(constructor);
45 | stream.writeInt64(id);
46 | stream.writeInt64(access_hash);
47 | }
48 | }
49 |
50 | public static class TL_inputDocumentFileLocation extends InputFileLocation {
51 | public static int constructor = 0x4e45abe9;
52 |
53 | public void readParams(AbstractSerializedData stream, boolean exception) {
54 | id = stream.readInt64(exception);
55 | access_hash = stream.readInt64(exception);
56 | }
57 |
58 | public void serializeToStream(AbstractSerializedData stream) {
59 | stream.writeInt32(constructor);
60 | stream.writeInt64(id);
61 | stream.writeInt64(access_hash);
62 | }
63 | }
64 |
65 | public static class TL_inputFileLocation extends InputFileLocation {
66 | public static int constructor = 0x14637196;
67 |
68 | public void readParams(AbstractSerializedData stream, boolean exception) {
69 | volume_id = stream.readInt64(exception);
70 | local_id = stream.readInt32(exception);
71 | secret = stream.readInt64(exception);
72 | }
73 |
74 | public void serializeToStream(AbstractSerializedData stream) {
75 | stream.writeInt32(constructor);
76 | stream.writeInt64(volume_id);
77 | stream.writeInt32(local_id);
78 | stream.writeInt64(secret);
79 | }
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/AspectRatioFrameLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dhc.gallery.components;
17 |
18 | import android.content.Context;
19 | import android.util.AttributeSet;
20 | import android.widget.FrameLayout;
21 |
22 | /**
23 | * A {@link FrameLayout} that resizes itself to match a specified aspect ratio.
24 | */
25 | public final class AspectRatioFrameLayout extends FrameLayout {
26 |
27 | /**
28 | * The {@link FrameLayout} will not resize itself if the fractional difference between its natural
29 | * aspect ratio and the requested aspect ratio falls below this threshold.
30 | *
31 | * This tolerance allows the view to occupy the whole of the screen when the requested aspect
32 | * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce
33 | * the number of view layers that need to be composited by the underlying system, which can help
34 | * to reduce power consumption.
35 | */
36 | private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f;
37 |
38 | private float videoAspectRatio;
39 |
40 | public AspectRatioFrameLayout(Context context) {
41 | super(context);
42 | }
43 |
44 | public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
45 | super(context, attrs);
46 | }
47 |
48 | /**
49 | * Set the aspect ratio that this view should satisfy.
50 | *
51 | * @param widthHeightRatio The width to height ratio.
52 | */
53 | public void setAspectRatio(float widthHeightRatio) {
54 | if (this.videoAspectRatio != widthHeightRatio) {
55 | this.videoAspectRatio = widthHeightRatio;
56 | requestLayout();
57 | }
58 | }
59 |
60 | @Override
61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
63 | if (videoAspectRatio == 0) {
64 | // Aspect ratio not set.
65 | return;
66 | }
67 |
68 | int width = getMeasuredWidth();
69 | int height = getMeasuredHeight();
70 | float viewAspectRatio = (float) width / height;
71 | float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
72 | if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
73 | // We're within the allowed tolerance.
74 | return;
75 | }
76 |
77 | if (aspectDeformation > 0) {
78 | height = (int) (width / videoAspectRatio);
79 | } else {
80 | width = (int) (height * videoAspectRatio);
81 | }
82 | super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
83 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/FileLocation.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class FileLocation extends TLObject {
5 | public int dc_id;
6 | public long volume_id;
7 | public int local_id;
8 | public long secret;
9 | public byte[] key;
10 | public byte[] iv;
11 |
12 | public static FileLocation TLdeserialize(AbstractSerializedData stream, int constructor,
13 | boolean exception) {
14 | FileLocation result = null;
15 | switch (constructor) {
16 | case 0x53d69076:
17 | result = new TL_fileLocation();
18 | break;
19 | case 0x55555554:
20 | result = new TL_fileEncryptedLocation();
21 | break;
22 | case 0x7c596b46:
23 | result = new TL_fileLocationUnavailable();
24 | break;
25 | }
26 | if (result == null && exception) {
27 | throw new RuntimeException(
28 | String.format("can't parse magic %x in FileLocation", constructor));
29 | }
30 | if (result != null) {
31 | result.readParams(stream, exception);
32 | }
33 | return result;
34 | }
35 |
36 | public static class TL_fileLocation extends FileLocation {
37 | public static int constructor = 0x53d69076;
38 |
39 | public void readParams(AbstractSerializedData stream, boolean exception) {
40 | dc_id = stream.readInt32(exception);
41 | volume_id = stream.readInt64(exception);
42 | local_id = stream.readInt32(exception);
43 | secret = stream.readInt64(exception);
44 | }
45 |
46 | public void serializeToStream(AbstractSerializedData stream) {
47 | stream.writeInt32(constructor);
48 | stream.writeInt32(dc_id);
49 | stream.writeInt64(volume_id);
50 | stream.writeInt32(local_id);
51 | stream.writeInt64(secret);
52 | }
53 | }
54 |
55 | public static class TL_fileEncryptedLocation extends FileLocation {
56 | public static int constructor = 0x55555554;
57 |
58 | public void readParams(AbstractSerializedData stream, boolean exception) {
59 | dc_id = stream.readInt32(exception);
60 | volume_id = stream.readInt64(exception);
61 | local_id = stream.readInt32(exception);
62 | secret = stream.readInt64(exception);
63 | key = stream.readByteArray(exception);
64 | iv = stream.readByteArray(exception);
65 | }
66 |
67 | public void serializeToStream(AbstractSerializedData stream) {
68 | stream.writeInt32(constructor);
69 | stream.writeInt32(dc_id);
70 | stream.writeInt64(volume_id);
71 | stream.writeInt32(local_id);
72 | stream.writeInt64(secret);
73 | stream.writeByteArray(key);
74 | stream.writeByteArray(iv);
75 | }
76 | }
77 |
78 | public static class TL_fileLocationUnavailable extends FileLocation {
79 | public static int constructor = 0x7c596b46;
80 |
81 | public void readParams(AbstractSerializedData stream, boolean exception) {
82 | volume_id = stream.readInt64(exception);
83 | local_id = stream.readInt32(exception);
84 | secret = stream.readInt64(exception);
85 | }
86 |
87 | public void serializeToStream(AbstractSerializedData stream) {
88 | stream.writeInt32(constructor);
89 | stream.writeInt64(volume_id);
90 | stream.writeInt32(local_id);
91 | stream.writeInt64(secret);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/InputEncryptedFile.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class InputEncryptedFile extends TLObject {
5 | public long id;
6 | public long access_hash;
7 | public int parts;
8 | public int key_fingerprint;
9 | public String md5_checksum;
10 |
11 | public static InputEncryptedFile TLdeserialize(AbstractSerializedData stream, int constructor,
12 | boolean exception) {
13 | InputEncryptedFile result = null;
14 | switch (constructor) {
15 | case 0x5a17b5e5:
16 | result = new TL_inputEncryptedFile();
17 | break;
18 | case 0x2dc173c8:
19 | result = new TL_inputEncryptedFileBigUploaded();
20 | break;
21 | case 0x1837c364:
22 | result = new TL_inputEncryptedFileEmpty();
23 | break;
24 | case 0x64bd0306:
25 | result = new TL_inputEncryptedFileUploaded();
26 | break;
27 | }
28 | if (result == null && exception) {
29 | throw new RuntimeException(
30 | String.format("can't parse magic %x in InputEncryptedFile", constructor));
31 | }
32 | if (result != null) {
33 | result.readParams(stream, exception);
34 | }
35 | return result;
36 | }
37 |
38 | public static class TL_inputEncryptedFileBigUploaded extends InputEncryptedFile {
39 | public static int constructor = 0x2dc173c8;
40 |
41 | public void readParams(AbstractSerializedData stream, boolean exception) {
42 | id = stream.readInt64(exception);
43 | parts = stream.readInt32(exception);
44 | key_fingerprint = stream.readInt32(exception);
45 | }
46 |
47 | public void serializeToStream(AbstractSerializedData stream) {
48 | stream.writeInt32(constructor);
49 | stream.writeInt64(id);
50 | stream.writeInt32(parts);
51 | stream.writeInt32(key_fingerprint);
52 | }
53 | }
54 |
55 | public static class TL_inputEncryptedFile extends InputEncryptedFile {
56 | public static int constructor = 0x5a17b5e5;
57 |
58 | public void readParams(AbstractSerializedData stream, boolean exception) {
59 | id = stream.readInt64(exception);
60 | access_hash = stream.readInt64(exception);
61 | }
62 |
63 | public void serializeToStream(AbstractSerializedData stream) {
64 | stream.writeInt32(constructor);
65 | stream.writeInt64(id);
66 | stream.writeInt64(access_hash);
67 | }
68 | }
69 |
70 | public static class TL_inputEncryptedFileEmpty extends InputEncryptedFile {
71 | public static int constructor = 0x1837c364;
72 |
73 | public void serializeToStream(AbstractSerializedData stream) {
74 | stream.writeInt32(constructor);
75 | }
76 | }
77 |
78 | public static class TL_inputEncryptedFileUploaded extends InputEncryptedFile {
79 | public static int constructor = 0x64bd0306;
80 |
81 | public void readParams(AbstractSerializedData stream, boolean exception) {
82 | id = stream.readInt64(exception);
83 | parts = stream.readInt32(exception);
84 | md5_checksum = stream.readString(exception);
85 | key_fingerprint = stream.readInt32(exception);
86 | }
87 |
88 | public void serializeToStream(AbstractSerializedData stream) {
89 | stream.writeInt32(constructor);
90 | stream.writeInt64(id);
91 | stream.writeInt32(parts);
92 | stream.writeString(md5_checksum);
93 | stream.writeInt32(key_fingerprint);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/Theme.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery;
3 |
4 | import android.content.res.ColorStateList;
5 | import android.graphics.Canvas;
6 | import android.graphics.ColorFilter;
7 | import android.graphics.Paint;
8 | import android.graphics.drawable.ColorDrawable;
9 | import android.graphics.drawable.Drawable;
10 | import android.graphics.drawable.RippleDrawable;
11 | import android.graphics.drawable.StateListDrawable;
12 | import android.os.Build;
13 |
14 | import com.dhc.gallery.utils.AndroidUtilities;
15 |
16 | import java.util.HashMap;
17 |
18 | public class Theme {
19 |
20 | public static final int ACTION_BAR_COLOR = 0xff527da3;
21 | public static final int ACTION_BAR_PHOTO_VIEWER_COLOR = 0x7f000000;
22 | public static final int ACTION_BAR_MEDIA_PICKER_COLOR = 0xff333333;
23 | public static final int ACTION_BAR_SUBTITLE_COLOR = 0xffd5e8f7;
24 | public static final int ACTION_BAR_SELECTOR_COLOR = 0xff406d94;
25 |
26 | public static final int ACTION_BAR_PICKER_SELECTOR_COLOR = 0xff3d3d3d;
27 | public static final int ACTION_BAR_WHITE_SELECTOR_COLOR = 0x40ffffff;
28 | public static final int ACTION_BAR_AUDIO_SELECTOR_COLOR = 0x2f000000;
29 | public static final int ACTION_BAR_MODE_SELECTOR_COLOR = 0xfff0f0f0;
30 |
31 | private static Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
32 | private static HashMap defaultColors = new HashMap<>();
33 | private static HashMap currentColors;
34 |
35 |
36 | public static final String key_chat_serviceBackground = "chat_serviceBackground";
37 | private static int serviceMessageColor;
38 |
39 | public static Drawable createBarSelectorDrawable(int color) {
40 | return createBarSelectorDrawable(color, true);
41 | }
42 |
43 | public static Drawable createBarSelectorDrawable(int color, boolean masked) {
44 | if (Build.VERSION.SDK_INT >= 21) {
45 | Drawable maskDrawable = null;
46 | if (masked) {
47 | maskPaint.setColor(0xffffffff);
48 | maskDrawable = new Drawable() {
49 | @Override
50 | public void draw(Canvas canvas) {
51 | android.graphics.Rect bounds = getBounds();
52 | canvas.drawCircle(bounds.centerX(), bounds.centerY(),
53 | AndroidUtilities.dp(18), maskPaint);
54 | }
55 |
56 | @Override
57 | public void setAlpha(int alpha) {
58 |
59 | }
60 |
61 | @Override
62 | public void setColorFilter(ColorFilter colorFilter) {
63 |
64 | }
65 |
66 | @Override
67 | public int getOpacity() {
68 | return 0;
69 | }
70 | };
71 | }
72 | ColorStateList colorStateList = new ColorStateList(
73 | new int[][] {
74 | new int[] {}
75 | },
76 | new int[] {
77 | color
78 | });
79 | return new RippleDrawable(colorStateList, null, maskDrawable);
80 | } else {
81 | StateListDrawable stateListDrawable = new StateListDrawable();
82 | stateListDrawable.addState(new int[] {
83 | android.R.attr.state_pressed
84 | }, new ColorDrawable(color));
85 | stateListDrawable.addState(new int[] {
86 | android.R.attr.state_focused
87 | }, new ColorDrawable(color));
88 | stateListDrawable.addState(new int[] {
89 | android.R.attr.state_selected
90 | }, new ColorDrawable(color));
91 | stateListDrawable.addState(new int[] {
92 | android.R.attr.state_activated
93 | }, new ColorDrawable(color));
94 | stateListDrawable.addState(new int[] {}, new ColorDrawable(0x00000000));
95 | return stateListDrawable;
96 | }
97 | }
98 |
99 |
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hc/gallery/util/StorageUtil.java:
--------------------------------------------------------------------------------
1 | package com.hc.gallery.util;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.os.Environment;
6 | import android.text.TextUtils;
7 |
8 | import java.io.File;
9 | import java.util.UUID;
10 | /**
11 | * 创建者:邓浩宸
12 | * 时间 :2017/4/20 13:01
13 | * 描述 :TODO 请描述该类职责
14 | */
15 | public class StorageUtil {
16 | public final static long K = 1024;
17 | public final static long M = 1024 * 1024;
18 | // 外置存储卡默认预警临界值
19 | private static final long THRESHOLD_WARNING_SPACE = 100 * M;
20 | // 保存文件时所需的最小空间的默认值
21 | public static final long THRESHOLD_MIN_SPCAE = 20 * M;
22 |
23 | public static void init(Context context, String rootPath) {
24 | ExternalStorage.getInstance().init(context, rootPath);
25 | }
26 |
27 | /**
28 | * 获取文件保存路径,没有toast提示
29 | *
30 | * @param fileName
31 | * @param fileType
32 | * @return 可用的保存路径或者null
33 | */
34 | public static String getWritePath(String fileName, StorageType fileType) {
35 | return getWritePath(null, fileName, fileType, false);
36 | }
37 |
38 | /**
39 | * 获取32位uuid
40 | *
41 | * @return
42 | */
43 | public static String get32UUID() {
44 | return UUID.randomUUID().toString().replaceAll("-", "");
45 | }
46 |
47 | /**
48 | * 获取文件保存路径
49 | *
50 | * @param fileName
51 | * 文件全名
52 | * @param tip
53 | * 空间不足时是否给出默认的toast提示
54 | * @return 可用的保存路径或者null
55 | */
56 | private static String getWritePath(Context context, String fileName, StorageType fileType, boolean tip) {
57 | String path = ExternalStorage.getInstance().getWritePath(fileName, fileType);
58 | if (TextUtils.isEmpty(path)) {
59 | return null;
60 | }
61 | File dir = new File(path).getParentFile();
62 | if (dir != null && !dir.exists()) {
63 | dir.mkdirs();
64 | }
65 | return path;
66 | }
67 |
68 | /**
69 | * 判断能否使用外置存储
70 | */
71 | public static boolean isExternalStorageExist() {
72 | return ExternalStorage.getInstance().isSdkStorageReady();
73 | }
74 |
75 |
76 | /**
77 | * 判断外部存储是否存在,以及是否有足够空间保存指定类型的文件
78 | *
79 | * @param context
80 | * @param fileType
81 | * @param tip 是否需要toast提示
82 | * @return false: 无存储卡或无空间可写, true: 表示ok
83 | */
84 | public static boolean hasEnoughSpaceForWrite(Context context, StorageType fileType, boolean tip) {
85 | if (!ExternalStorage.getInstance().isSdkStorageReady()) {
86 | return false;
87 | }
88 |
89 | long residual = ExternalStorage.getInstance().getAvailableExternalSize();
90 | if (residual < fileType.getStorageMinSize()) {
91 | return false;
92 | } else if (residual < THRESHOLD_WARNING_SPACE) {
93 | }
94 |
95 | return true;
96 | }
97 | /**
98 | * 根据输入的文件名和类型,找到该文件的全路径。
99 | *
100 | * @param fileName
101 | * @param fileType
102 | * @return 如果存在该文件,返回路径,否则返回空
103 | */
104 | public static String getReadPath(String fileName, StorageType fileType) {
105 | return ExternalStorage.getInstance().getReadPath(fileName, fileType);
106 | }
107 |
108 | /**
109 | * 获取文件保存路径,空间不足时有toast提示
110 | *
111 | * @param context
112 | * @param fileName
113 | * @param fileType
114 | * @return 可用的保存路径或者null
115 | */
116 | public static String getWritePath(Context context, String fileName, StorageType fileType) {
117 | return getWritePath(context, fileName, fileType, true);
118 | }
119 |
120 | public static String getDirectoryByDirType(StorageType fileType) {
121 | return ExternalStorage.getInstance().getDirectoryByDirType(fileType);
122 | }
123 |
124 | public static String getSystemImagePath() {
125 | if (Build.VERSION.SDK_INT > 7) {
126 | String picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();
127 | return picturePath + "/nim/";
128 | } else {
129 | String picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
130 | return picturePath + "/nim/";
131 | }
132 | }
133 |
134 | public static boolean isInvalidVideoFile(String filePath) {
135 | return filePath.toLowerCase().endsWith(".3gp")
136 | || filePath.toLowerCase().endsWith(".mp4");
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/PhotoSize.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class PhotoSize extends TLObject {
5 | public String type;
6 | public FileLocation location;
7 | public int w;
8 | public int h;
9 | public int size;
10 | public byte[] bytes;
11 |
12 | public static PhotoSize TLdeserialize(AbstractSerializedData stream, int constructor,
13 | boolean exception) {
14 | PhotoSize result = null;
15 | switch (constructor) {
16 | case 0x77bfb61b:
17 | result = new TL_photoSize();
18 | break;
19 | case 0xe17e23c:
20 | result = new TL_photoSizeEmpty();
21 | break;
22 | case 0xe9a734fa:
23 | result = new TL_photoCachedSize();
24 | break;
25 | }
26 | if (result == null && exception) {
27 | throw new RuntimeException(
28 | String.format("can't parse magic %x in PhotoSize", constructor));
29 | }
30 | if (result != null) {
31 | result.readParams(stream, exception);
32 | }
33 | return result;
34 | }
35 |
36 | public static class TL_photoSize extends PhotoSize {
37 | public static int constructor = 0x77bfb61b;
38 |
39 | public void readParams(AbstractSerializedData stream, boolean exception) {
40 | type = stream.readString(exception);
41 | location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception);
42 | w = stream.readInt32(exception);
43 | h = stream.readInt32(exception);
44 | size = stream.readInt32(exception);
45 | }
46 |
47 | public void serializeToStream(AbstractSerializedData stream) {
48 | stream.writeInt32(constructor);
49 | stream.writeString(type);
50 | location.serializeToStream(stream);
51 | stream.writeInt32(w);
52 | stream.writeInt32(h);
53 | stream.writeInt32(size);
54 | }
55 | }
56 |
57 | public static class TL_photoSizeEmpty extends PhotoSize {
58 | public static int constructor = 0xe17e23c;
59 |
60 | public void readParams(AbstractSerializedData stream, boolean exception) {
61 | int startReadPosiition = stream.getPosition(); // TODO remove this hack after some time
62 | try {
63 | type = stream.readString(true);
64 | if (type.length() > 1 || !type.equals("") && !type.equals("s") && !type.equals("x")
65 | && !type.equals("m") && !type.equals("y") && !type.equals("w")) {
66 | type = "s";
67 | if (stream instanceof NativeByteBuffer) {
68 | ((NativeByteBuffer) stream).position(startReadPosiition);
69 | }
70 | }
71 | } catch (Exception e) {
72 | type = "s";
73 | if (stream instanceof NativeByteBuffer) {
74 | ((NativeByteBuffer) stream).position(startReadPosiition);
75 | }
76 | }
77 | }
78 |
79 | public void serializeToStream(AbstractSerializedData stream) {
80 | stream.writeInt32(constructor);
81 | stream.writeString(type);
82 | }
83 | }
84 |
85 | public static class TL_photoCachedSize extends PhotoSize {
86 | public static int constructor = 0xe9a734fa;
87 |
88 | public void readParams(AbstractSerializedData stream, boolean exception) {
89 | type = stream.readString(exception);
90 | location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception);
91 | w = stream.readInt32(exception);
92 | h = stream.readInt32(exception);
93 | bytes = stream.readByteArray(exception);
94 | }
95 |
96 | public void serializeToStream(AbstractSerializedData stream) {
97 | stream.writeInt32(constructor);
98 | stream.writeString(type);
99 | location.serializeToStream(stream);
100 | stream.writeInt32(w);
101 | stream.writeInt32(h);
102 | stream.writeByteArray(bytes);
103 | }
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/actionbar/MenuDrawable.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.actionbar;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.ColorFilter;
5 | import android.graphics.Paint;
6 | import android.graphics.PixelFormat;
7 | import android.graphics.drawable.Drawable;
8 | import android.view.animation.DecelerateInterpolator;
9 |
10 | import com.dhc.gallery.utils.AndroidUtilities;
11 |
12 | public class MenuDrawable extends Drawable {
13 |
14 | private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
15 | private boolean reverseAngle = false;
16 | private long lastFrameTime;
17 | private boolean animationInProgress;
18 | private float finalRotation;
19 | private float currentRotation;
20 | private int currentAnimationTime;
21 | private DecelerateInterpolator interpolator = new DecelerateInterpolator();
22 |
23 | public MenuDrawable() {
24 | super();
25 | paint.setColor(0xffffffff);
26 | paint.setStrokeWidth(AndroidUtilities.dp(2));
27 | }
28 |
29 | public void setRotation(float rotation, boolean animated) {
30 | lastFrameTime = 0;
31 | if (currentRotation == 1) {
32 | reverseAngle = true;
33 | } else if (currentRotation == 0) {
34 | reverseAngle = false;
35 | }
36 | lastFrameTime = 0;
37 | if (animated) {
38 | if (currentRotation < rotation) {
39 | currentAnimationTime = (int) (currentRotation * 300);
40 | } else {
41 | currentAnimationTime = (int) ((1.0f - currentRotation) * 300);
42 | }
43 | lastFrameTime = System.currentTimeMillis();
44 | finalRotation = rotation;
45 | } else {
46 | finalRotation = currentRotation = rotation;
47 | }
48 | invalidateSelf();
49 | }
50 |
51 | @Override
52 | public void draw(Canvas canvas) {
53 | if (currentRotation != finalRotation) {
54 | if (lastFrameTime != 0) {
55 | long dt = System.currentTimeMillis() - lastFrameTime;
56 |
57 | currentAnimationTime += dt;
58 | if (currentAnimationTime >= 300) {
59 | currentRotation = finalRotation;
60 | } else {
61 | if (currentRotation < finalRotation) {
62 | currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation;
63 | } else {
64 | currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f);
65 | }
66 | }
67 | }
68 | lastFrameTime = System.currentTimeMillis();
69 | invalidateSelf();
70 | }
71 |
72 | canvas.save();
73 | canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2);
74 | canvas.rotate(currentRotation * (reverseAngle ? -180 : 180));
75 | canvas.drawLine(-AndroidUtilities.dp(9), 0, AndroidUtilities.dp(9) - AndroidUtilities.dp(3.0f) * currentRotation, 0, paint);
76 | float endYDiff = AndroidUtilities.dp(5) * (1 - Math.abs(currentRotation)) - AndroidUtilities.dp(0.5f) * Math.abs(currentRotation);
77 | float endXDiff = AndroidUtilities.dp(9) - AndroidUtilities.dp(2.5f) * Math.abs(currentRotation);
78 | float startYDiff = AndroidUtilities.dp(5) + AndroidUtilities.dp(2.0f) * Math.abs(currentRotation);
79 | float startXDiff = -AndroidUtilities.dp(9) + AndroidUtilities.dp(7.5f) * Math.abs(currentRotation);
80 | canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint);
81 | canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint);
82 | canvas.restore();
83 | }
84 |
85 | @Override
86 | public void setAlpha(int alpha) {
87 |
88 | }
89 |
90 | @Override
91 | public void setColorFilter(ColorFilter cf) {
92 |
93 | }
94 |
95 | @Override
96 | public int getOpacity() {
97 | return PixelFormat.TRANSPARENT;
98 | }
99 |
100 | @Override
101 | public int getIntrinsicWidth() {
102 | return AndroidUtilities.dp(24);
103 | }
104 |
105 | @Override
106 | public int getIntrinsicHeight() {
107 | return AndroidUtilities.dp(24);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/gallery/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
38 |
39 |
40 |
47 |
48 |
49 |
53 |
54 |
55 |
59 |
60 |
64 |
65 |
71 |
72 |
78 |
79 |
83 |
84 |
88 |
89 |
95 |
96 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/StorageFileType.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | public class StorageFileType extends TLObject {
5 |
6 | public static StorageFileType TLdeserialize(AbstractSerializedData stream, int constructor,
7 | boolean exception) {
8 | StorageFileType result = null;
9 | switch (constructor) {
10 | case 0xaa963b05:
11 | result = new TL_storage_fileUnknown();
12 | break;
13 | case 0xb3cea0e4:
14 | result = new TL_storage_fileMp4();
15 | break;
16 | case 0x1081464c:
17 | result = new TL_storage_fileWebp();
18 | break;
19 | case 0xa4f63c0:
20 | result = new TL_storage_filePng();
21 | break;
22 | case 0xcae1aadf:
23 | result = new TL_storage_fileGif();
24 | break;
25 | case 0xae1e508d:
26 | result = new TL_storage_filePdf();
27 | break;
28 | case 0x528a0677:
29 | result = new TL_storage_fileMp3();
30 | break;
31 | case 0x7efe0e:
32 | result = new TL_storage_fileJpeg();
33 | break;
34 | case 0x4b09ebbc:
35 | result = new TL_storage_fileMov();
36 | break;
37 | case 0x40bc6f52:
38 | result = new TL_storage_filePartial();
39 | break;
40 | }
41 | if (result == null && exception) {
42 | throw new RuntimeException(
43 | String.format("can't parse magic %x in StorageFileType", constructor));
44 | }
45 | if (result != null) {
46 | result.readParams(stream, exception);
47 | }
48 | return result;
49 | }
50 |
51 | public static class TL_storage_fileUnknown extends StorageFileType {
52 | public static int constructor = 0xaa963b05;
53 |
54 |
55 | public void serializeToStream(AbstractSerializedData stream) {
56 | stream.writeInt32(constructor);
57 | }
58 | }
59 |
60 | public static class TL_storage_fileMp4 extends StorageFileType {
61 | public static int constructor = 0xb3cea0e4;
62 |
63 |
64 | public void serializeToStream(AbstractSerializedData stream) {
65 | stream.writeInt32(constructor);
66 | }
67 | }
68 |
69 | public static class TL_storage_fileWebp extends StorageFileType {
70 | public static int constructor = 0x1081464c;
71 |
72 |
73 | public void serializeToStream(AbstractSerializedData stream) {
74 | stream.writeInt32(constructor);
75 | }
76 | }
77 |
78 | public static class TL_storage_filePng extends StorageFileType {
79 | public static int constructor = 0xa4f63c0;
80 |
81 |
82 | public void serializeToStream(AbstractSerializedData stream) {
83 | stream.writeInt32(constructor);
84 | }
85 | }
86 |
87 | public static class TL_storage_fileGif extends StorageFileType {
88 | public static int constructor = 0xcae1aadf;
89 |
90 |
91 | public void serializeToStream(AbstractSerializedData stream) {
92 | stream.writeInt32(constructor);
93 | }
94 | }
95 |
96 | public static class TL_storage_filePdf extends StorageFileType {
97 | public static int constructor = 0xae1e508d;
98 |
99 |
100 | public void serializeToStream(AbstractSerializedData stream) {
101 | stream.writeInt32(constructor);
102 | }
103 | }
104 |
105 | public static class TL_storage_fileMp3 extends StorageFileType {
106 | public static int constructor = 0x528a0677;
107 |
108 |
109 | public void serializeToStream(AbstractSerializedData stream) {
110 | stream.writeInt32(constructor);
111 | }
112 | }
113 |
114 | public static class TL_storage_fileJpeg extends StorageFileType {
115 | public static int constructor = 0x7efe0e;
116 |
117 |
118 | public void serializeToStream(AbstractSerializedData stream) {
119 | stream.writeInt32(constructor);
120 | }
121 | }
122 |
123 | public static class TL_storage_fileMov extends StorageFileType {
124 | public static int constructor = 0x4b09ebbc;
125 |
126 |
127 | public void serializeToStream(AbstractSerializedData stream) {
128 | stream.writeInt32(constructor);
129 | }
130 | }
131 |
132 | public static class TL_storage_filePartial extends StorageFileType {
133 | public static int constructor = 0x40bc6f52;
134 |
135 |
136 | public void serializeToStream(AbstractSerializedData stream) {
137 | stream.writeInt32(constructor);
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/BackupImageView.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.components;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.graphics.drawable.Drawable;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 |
11 | import com.dhc.gallery.proxy.ImageReceiver;
12 | import com.dhc.gallery.tl.FileLocation;
13 | import com.dhc.gallery.tl.TLObject;
14 |
15 | public class BackupImageView extends View {
16 |
17 | private ImageReceiver imageReceiver;
18 | private int width = -1;
19 | private int height = -1;
20 |
21 | public BackupImageView(Context context) {
22 | super(context);
23 | init();
24 | }
25 |
26 | public BackupImageView(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | init();
29 | }
30 |
31 | public BackupImageView(Context context, AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | init();
34 | }
35 |
36 | private void init() {
37 | imageReceiver = new ImageReceiver(this);
38 | }
39 |
40 | public void setImage(TLObject path, String filter, String ext, Drawable thumb) {
41 | setImage(path, null, filter, thumb, null, null, null, ext, 0);
42 | }
43 |
44 | public void setImage(TLObject path, String filter, Drawable thumb) {
45 | setImage(path, null, filter, thumb, null, null, null, null, 0);
46 | }
47 |
48 | public void setImage(TLObject path, String filter, Bitmap thumb) {
49 | setImage(path, null, filter, null, thumb, null, null, null, 0);
50 | }
51 |
52 | public void setImage(TLObject path, String filter, Drawable thumb, int size) {
53 | setImage(path, null, filter, thumb, null, null, null, null, size);
54 | }
55 |
56 | public void setImage(TLObject path, String filter, Bitmap thumb, int size) {
57 | setImage(path, null, filter, null, thumb, null, null, null, size);
58 | }
59 |
60 | public void setImage(TLObject path, String filter, FileLocation thumb, int size) {
61 | setImage(path, null, filter, null, null, thumb, null, null, size);
62 | }
63 |
64 | public void setImage(String path, String filter, Drawable thumb) {
65 | setImage(null, path, filter, thumb, null, null, null, null, 0);
66 | }
67 |
68 | public void setOrientation(int angle, boolean center) {
69 | imageReceiver.setOrientation(angle, center);
70 | }
71 |
72 | public void setImage(TLObject path, String httpUrl, String filter, Drawable thumb,
73 | Bitmap thumbBitmap, FileLocation thumbLocation, String thumbFilter, String ext,
74 | int size) {
75 | if (thumbBitmap != null) {
76 | thumb = new BitmapDrawable(null, thumbBitmap);
77 | }
78 | imageReceiver.setImage(path, httpUrl, filter, thumb, thumbLocation, thumbFilter, size, ext,
79 | false);
80 | }
81 |
82 | public void setImageBitmap(Bitmap bitmap) {
83 | imageReceiver.setImageBitmap(bitmap);
84 | }
85 |
86 | public void setImageResource(int resId) {
87 | imageReceiver.setImageBitmap(getResources().getDrawable(resId));
88 | }
89 |
90 | public void setImageDrawable(Drawable drawable) {
91 | imageReceiver.setImageBitmap(drawable);
92 | }
93 |
94 | public void setRoundRadius(int value) {
95 | imageReceiver.setRoundRadius(value);
96 | }
97 |
98 | public void setAspectFit(boolean value) {
99 | imageReceiver.setAspectFit(value);
100 | }
101 |
102 | public ImageReceiver getImageReceiver() {
103 | return imageReceiver;
104 | }
105 |
106 | public void setSize(int w, int h) {
107 | width = w;
108 | height = h;
109 | }
110 |
111 | @Override
112 | protected void onDetachedFromWindow() {
113 | super.onDetachedFromWindow();
114 | imageReceiver.onDetachedFromWindow();
115 | }
116 |
117 | @Override
118 | protected void onAttachedToWindow() {
119 | super.onAttachedToWindow();
120 | imageReceiver.onAttachedToWindow();
121 | }
122 |
123 | @Override
124 | protected void onDraw(Canvas canvas) {
125 | if (width != -1 && height != -1) {
126 | imageReceiver.setImageCoords((getWidth() - width) / 2, (getHeight() - height) / 2,
127 | width, height);
128 | } else {
129 | imageReceiver.setImageCoords(0, 0, getWidth(), getHeight());
130 | }
131 | imageReceiver.draw(canvas);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/actionbar/BackDrawable.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.actionbar;
2 |
3 |
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.ColorFilter;
7 | import android.graphics.Paint;
8 | import android.graphics.PixelFormat;
9 | import android.graphics.drawable.Drawable;
10 | import android.view.animation.DecelerateInterpolator;
11 |
12 | import com.dhc.gallery.utils.AndroidUtilities;
13 |
14 | public class BackDrawable extends Drawable {
15 |
16 | private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
17 | private boolean reverseAngle = false;
18 | private long lastFrameTime;
19 | private boolean animationInProgress;
20 | private float finalRotation;
21 | private float currentRotation;
22 | private int currentAnimationTime;
23 | private boolean alwaysClose;
24 | private DecelerateInterpolator interpolator = new DecelerateInterpolator();
25 |
26 | public BackDrawable(boolean close) {
27 | super();
28 | paint.setColor(0xffffffff);
29 | paint.setStrokeWidth(AndroidUtilities.dp(2));
30 | alwaysClose = close;
31 | }
32 |
33 | public void setRotation(float rotation, boolean animated) {
34 | lastFrameTime = 0;
35 | if (currentRotation == 1) {
36 | reverseAngle = true;
37 | } else if (currentRotation == 0) {
38 | reverseAngle = false;
39 | }
40 | lastFrameTime = 0;
41 | if (animated) {
42 | if (currentRotation < rotation) {
43 | currentAnimationTime = (int) (currentRotation * 300);
44 | } else {
45 | currentAnimationTime = (int) ((1.0f - currentRotation) * 300);
46 | }
47 | lastFrameTime = System.currentTimeMillis();
48 | finalRotation = rotation;
49 | } else {
50 | finalRotation = currentRotation = rotation;
51 | }
52 | invalidateSelf();
53 | }
54 |
55 | @Override
56 | public void draw(Canvas canvas) {
57 | if (currentRotation != finalRotation) {
58 | if (lastFrameTime != 0) {
59 | long dt = System.currentTimeMillis() - lastFrameTime;
60 |
61 | currentAnimationTime += dt;
62 | if (currentAnimationTime >= 300) {
63 | currentRotation = finalRotation;
64 | } else {
65 | if (currentRotation < finalRotation) {
66 | currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation;
67 | } else {
68 | currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f);
69 | }
70 | }
71 | }
72 | lastFrameTime = System.currentTimeMillis();
73 | invalidateSelf();
74 | }
75 |
76 | int rD = (int) ((117 - 255) * currentRotation);
77 | int c = Color.rgb(255 + rD, 255 + rD, 255 + rD);
78 | paint.setColor(c);
79 |
80 | canvas.save();
81 | canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2);
82 | float rotation = currentRotation;
83 | if (!alwaysClose) {
84 | canvas.rotate(currentRotation * (reverseAngle ? -225 : 135));
85 | } else {
86 | canvas.rotate(135 + currentRotation * (reverseAngle ? -180 : 180));
87 | rotation = 1.0f;
88 | }
89 | canvas.drawLine(-AndroidUtilities.dp(7) - AndroidUtilities.dp(1) * rotation, 0, AndroidUtilities.dp(8), 0, paint);
90 | float startYDiff = -AndroidUtilities.dp(0.5f);
91 | float endYDiff = AndroidUtilities.dp(7) + AndroidUtilities.dp(1) * rotation;
92 | float startXDiff = -AndroidUtilities.dp(7.0f) + AndroidUtilities.dp(7.0f) * rotation;
93 | float endXDiff = AndroidUtilities.dp(0.5f) - AndroidUtilities.dp(0.5f) * rotation;
94 | canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint);
95 | canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint);
96 | canvas.restore();
97 | }
98 |
99 | @Override
100 | public void setAlpha(int alpha) {
101 |
102 | }
103 |
104 | @Override
105 | public void setColorFilter(ColorFilter cf) {
106 |
107 | }
108 |
109 | @Override
110 | public int getOpacity() {
111 | return PixelFormat.TRANSPARENT;
112 | }
113 |
114 | @Override
115 | public int getIntrinsicWidth() {
116 | return AndroidUtilities.dp(24);
117 | }
118 |
119 | @Override
120 | public int getIntrinsicHeight() {
121 | return AndroidUtilities.dp(24);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/GalleryConfig.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery;
3 |
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 |
7 | import com.dhc.gallery.ui.GalleryActivity;
8 |
9 | /**
10 | * the {@link GalleryActivity} of buidler.
11 | */
12 | public class GalleryConfig implements Parcelable {
13 |
14 |
15 | public static final int SELECT_PHOTO = 0;
16 | public static final int TAKE_PHOTO = 1;
17 | public static final int RECORD_VEDIO = 2;
18 | public static final int SELECT_VEDIO = 3;
19 | public static final int TAKEPHOTO_RECORDVEDIO = 4;
20 | private String[] filterMimeTypes = new String[]{};
21 | private String hintOfPick;
22 | private boolean singlePhoto = false;
23 | private int limitPickPhoto = 9;
24 | private boolean isSingleVedio = false;
25 | private boolean isNeedCrop = false;
26 | private String filePath;
27 | private int type = SELECT_PHOTO;
28 | private int requestCode = -1;
29 | private int limitRecordTime;
30 | private int limitRecordSize;
31 |
32 |
33 | public GalleryConfig() {
34 | }
35 |
36 | public String[] getFilterMimeTypes() {
37 | return filterMimeTypes;
38 | }
39 |
40 | public void setFilterMimeTypes(String[] filterMimeTypes) {
41 | this.filterMimeTypes = filterMimeTypes;
42 | }
43 |
44 | public int getLimitRecordSize() {
45 | return limitRecordSize;
46 | }
47 |
48 | public void setLimitRecordSize(int limitRecordSize) {
49 | this.limitRecordSize = limitRecordSize;
50 | }
51 |
52 | public int getLimitRecordTime() {
53 | return limitRecordTime;
54 | }
55 |
56 | public void setLimitRecordTime(int limitRecordTime) {
57 | this.limitRecordTime = limitRecordTime;
58 | }
59 |
60 | public String getHintOfPick() {
61 | return hintOfPick;
62 | }
63 |
64 | public void setHintOfPick(String hintOfPick) {
65 | this.hintOfPick = hintOfPick;
66 | }
67 |
68 | public boolean isSinglePhoto() {
69 | return singlePhoto;
70 | }
71 |
72 | public void setSinglePhoto(boolean singlePhoto) {
73 | this.singlePhoto = singlePhoto;
74 | }
75 |
76 | public int getLimitPickPhoto() {
77 | return limitPickPhoto;
78 | }
79 |
80 | public void setLimitPickPhoto(int limitPickPhoto) {
81 | this.limitPickPhoto = limitPickPhoto;
82 | }
83 |
84 | public boolean isSingleVedio() {
85 | return isSingleVedio;
86 | }
87 |
88 | public void setSingleVedio(boolean singleVedio) {
89 | isSingleVedio = singleVedio;
90 | }
91 |
92 | public boolean isNeedCrop() {
93 | return isNeedCrop;
94 | }
95 |
96 | public void setNeedCrop(boolean needCrop) {
97 | isNeedCrop = needCrop;
98 | }
99 |
100 | public String getFilePath() {
101 | return filePath;
102 | }
103 |
104 | public void setFilePath(String filePath) {
105 | this.filePath = filePath;
106 | }
107 |
108 | public int getType() {
109 | return type;
110 | }
111 |
112 | public void setType(int type) {
113 | this.type = type;
114 | }
115 |
116 | public int getRequestCode() {
117 | return requestCode;
118 | }
119 |
120 | public void setRequestCode(int requestCode) {
121 | this.requestCode = requestCode;
122 | }
123 |
124 |
125 | @Override
126 | public int describeContents() {
127 | return 0;
128 | }
129 |
130 | @Override
131 | public void writeToParcel(Parcel dest, int flags) {
132 | dest.writeStringArray(this.filterMimeTypes);
133 | dest.writeString(this.hintOfPick);
134 | dest.writeByte(this.singlePhoto ? (byte) 1 : (byte) 0);
135 | dest.writeInt(this.limitPickPhoto);
136 | dest.writeByte(this.isSingleVedio ? (byte) 1 : (byte) 0);
137 | dest.writeByte(this.isNeedCrop ? (byte) 1 : (byte) 0);
138 | dest.writeString(this.filePath);
139 | dest.writeInt(this.type);
140 | dest.writeInt(this.requestCode);
141 | dest.writeInt(this.limitRecordTime);
142 | dest.writeInt(this.limitRecordSize);
143 | }
144 |
145 | protected GalleryConfig(Parcel in) {
146 | this.filterMimeTypes = in.createStringArray();
147 | this.hintOfPick = in.readString();
148 | this.singlePhoto = in.readByte() != 0;
149 | this.limitPickPhoto = in.readInt();
150 | this.isSingleVedio = in.readByte() != 0;
151 | this.isNeedCrop = in.readByte() != 0;
152 | this.filePath = in.readString();
153 | this.type = in.readInt();
154 | this.requestCode = in.readInt();
155 | this.limitRecordTime = in.readInt();
156 | this.limitRecordSize = in.readInt();
157 | }
158 |
159 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
160 | @Override
161 | public GalleryConfig createFromParcel(Parcel source) {
162 | return new GalleryConfig(source);
163 | }
164 |
165 | @Override
166 | public GalleryConfig[] newArray(int size) {
167 | return new GalleryConfig[size];
168 | }
169 | };
170 | }
171 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/PickerBottomLayout.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.components;
3 |
4 | import android.content.Context;
5 | import android.util.TypedValue;
6 | import android.view.Gravity;
7 | import android.view.View;
8 | import android.widget.FrameLayout;
9 | import android.widget.LinearLayout;
10 | import android.widget.TextView;
11 |
12 | import com.dhc.gallery.ui.PhotoAlbumPickerActivity;
13 | import com.dhc.gallery.R;
14 | import com.dhc.gallery.Theme;
15 | import com.dhc.gallery.utils.AndroidUtilities;
16 | import com.dhc.gallery.utils.LayoutHelper;
17 |
18 | public class PickerBottomLayout extends FrameLayout {
19 |
20 | public LinearLayout doneButton;
21 | public TextView cancelButton;
22 | public TextView doneButtonTextView;
23 | public TextView doneButtonBadgeTextView;
24 |
25 | private boolean isDarkTheme;
26 |
27 | public PickerBottomLayout(Context context) {
28 | this(context, true);
29 | }
30 |
31 | public PickerBottomLayout(Context context, boolean darkTheme) {
32 | super(context);
33 | isDarkTheme = darkTheme;
34 |
35 | setBackgroundColor(isDarkTheme ? 0xff1a1a1a : 0xffffffff);
36 |
37 | cancelButton = new TextView(context);
38 | cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
39 | cancelButton.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff);
40 | cancelButton.setGravity(Gravity.CENTER);
41 | cancelButton.setBackgroundDrawable(
42 | Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR
43 | : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false));
44 | cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0);
45 | cancelButton.setText(R.string.Preview);
46 | // cancelButton.getPaint().setFakeBoldText(true);
47 | addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT,
48 | LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT));
49 |
50 | doneButton = new LinearLayout(context);
51 | doneButton.setOrientation(LinearLayout.HORIZONTAL);
52 | doneButton.setBackgroundDrawable(
53 | Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR
54 | : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false));
55 | doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0);
56 | addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT,
57 | LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT));
58 |
59 | doneButtonBadgeTextView = new TextView(context);
60 | // doneButtonBadgeTextView.getPaint().setFakeBoldText(true);
61 | doneButtonBadgeTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
62 | doneButtonBadgeTextView.setTextColor(0xffffffff);
63 | doneButtonBadgeTextView.setGravity(Gravity.CENTER);
64 | doneButtonBadgeTextView.setBackgroundResource(
65 | isDarkTheme ? R.drawable.photobadge_new : R.drawable.photobadge_new);
66 | doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8),
67 | AndroidUtilities.dp(1));
68 | doneButton.addView(doneButtonBadgeTextView,
69 | LayoutHelper.createLinear(26, 26, Gravity.CENTER_VERTICAL, 0, 0, 10, 0));
70 |
71 | doneButtonTextView = new TextView(context);
72 | doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
73 | doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff);
74 | doneButtonTextView.setGravity(Gravity.CENTER);
75 | doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8));
76 | doneButtonTextView.setText(R.string.Send);
77 | // doneButtonTextView.getPaint().setFakeBoldText(true);
78 | doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT,
79 | LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL));
80 | }
81 |
82 | public void updateSelectedCount(int count, boolean disable) {
83 | if (count == 0) {
84 | doneButtonBadgeTextView.setVisibility(View.GONE);
85 |
86 | if (disable) {
87 | doneButtonTextView.setTextColor(0xff999999);
88 | cancelButton.setTextColor(0xff999999);
89 | doneButton.setEnabled(false);
90 | cancelButton.setEnabled(false);
91 | } else {
92 | // doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8);
93 | doneButtonTextView.setTextColor(
94 | PhotoAlbumPickerActivity.limitPickPhoto == 1 ? 0xffffffff : 0xff999999);
95 | }
96 | } else {
97 | doneButtonTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
98 | doneButtonBadgeTextView.setVisibility(View.VISIBLE);
99 | doneButtonBadgeTextView.setText(String.format("%d", count));
100 |
101 | doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff);
102 | cancelButton.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff);
103 | if (disable) {
104 | doneButton.setEnabled(true);
105 | cancelButton.setEnabled(true);
106 | }
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hc/gallery/util/ExternalStorage.java:
--------------------------------------------------------------------------------
1 | package com.hc.gallery.util;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 | import android.os.StatFs;
6 | import android.text.TextUtils;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 |
11 | /**
12 | * 创建者:邓浩宸
13 | * 时间 :2017/4/20 13:01
14 | * 描述 :TODO 请描述该类职责
15 | */
16 | class ExternalStorage {
17 | /**
18 | * 外部存储根目录
19 | */
20 | private String sdkStorageRoot = null;
21 |
22 | private static ExternalStorage instance;
23 |
24 | private ExternalStorage() {
25 |
26 | }
27 |
28 | synchronized public static ExternalStorage getInstance() {
29 | if (instance == null) {
30 | instance = new ExternalStorage();
31 | }
32 | return instance;
33 | }
34 |
35 | public void init(Context context, String sdkStorageRoot) {
36 | if (!TextUtils.isEmpty(sdkStorageRoot)) {
37 | File dir = new File(sdkStorageRoot);
38 | if (!dir.exists()) {
39 | dir.mkdirs();
40 | }
41 | if (dir.exists() && !dir.isFile()) {
42 | this.sdkStorageRoot = sdkStorageRoot;
43 | if (!sdkStorageRoot.endsWith("/")) {
44 | this.sdkStorageRoot = sdkStorageRoot + "/";
45 | }
46 | }
47 | }
48 |
49 | if (TextUtils.isEmpty(this.sdkStorageRoot)) {
50 | loadStorageState(context);
51 | }
52 |
53 | createSubFolders();
54 | }
55 |
56 | private void loadStorageState(Context context) {
57 | String externalPath = Environment.getExternalStorageDirectory().getPath();
58 | this.sdkStorageRoot = externalPath + "/" + context.getPackageName() + "/";
59 | }
60 |
61 | private void createSubFolders() {
62 | boolean result = true;
63 | File root = new File(sdkStorageRoot);
64 | if (root.exists() && !root.isDirectory()) {
65 | root.delete();
66 | }
67 | for (StorageType storageType : StorageType.values()) {
68 | result &= makeDirectory(sdkStorageRoot + storageType.getStoragePath());
69 | }
70 | if (result) {
71 | createNoMediaFile(sdkStorageRoot);
72 | }
73 | }
74 |
75 | /**
76 | * 创建目录
77 | *
78 | * @param path
79 | * @return
80 | */
81 | private boolean makeDirectory(String path) {
82 | File file = new File(path);
83 | boolean exist = file.exists();
84 | if (!exist) {
85 | exist = file.mkdirs();
86 | }
87 | return exist;
88 | }
89 |
90 | protected static String NO_MEDIA_FILE_NAME = ".nomedia";
91 |
92 | private void createNoMediaFile(String path) {
93 | File noMediaFile = new File(path + "/" + NO_MEDIA_FILE_NAME);
94 | try {
95 | if (!noMediaFile.exists()) {
96 | noMediaFile.createNewFile();
97 | }
98 | } catch (IOException e) {
99 | e.printStackTrace();
100 | }
101 | }
102 |
103 | /**
104 | * 文件全名转绝对路径(写)
105 | *
106 | * @param fileName
107 | * 文件全名(文件名.扩展名)
108 | * @return 返回绝对路径信息
109 | */
110 | public String getWritePath(String fileName, StorageType fileType) {
111 | return pathForName(fileName, fileType, false, false);
112 | }
113 |
114 | private String pathForName(String fileName, StorageType type, boolean dir,
115 | boolean check) {
116 | String directory = getDirectoryByDirType(type);
117 | StringBuilder path = new StringBuilder(directory);
118 |
119 | if (!dir) {
120 | path.append(fileName);
121 | }
122 |
123 | String pathString = path.toString();
124 | File file = new File(pathString);
125 |
126 | if (check) {
127 | if (file.exists()) {
128 | if ((dir && file.isDirectory())
129 | || (!dir && !file.isDirectory())) {
130 | return pathString;
131 | }
132 | }
133 |
134 | return "";
135 | } else {
136 | return pathString;
137 | }
138 | }
139 |
140 | /**
141 | * 返回指定类型的文件夹路径
142 | *
143 | * @param fileType
144 | * @return
145 | */
146 | public String getDirectoryByDirType(StorageType fileType) {
147 | return sdkStorageRoot + fileType.getStoragePath();
148 | }
149 |
150 | /**
151 | * 根据输入的文件名和类型,找到该文件的全路径。
152 | * @param fileName
153 | * @param fileType
154 | * @return 如果存在该文件,返回路径,否则返回空
155 | */
156 | public String getReadPath(String fileName, StorageType fileType) {
157 | if (TextUtils.isEmpty(fileName)) {
158 | return "";
159 | }
160 |
161 | return pathForName(fileName, fileType, false, true);
162 | }
163 |
164 | public boolean isSdkStorageReady() {
165 | String externalRoot = Environment.getExternalStorageDirectory().getAbsolutePath();
166 | if (this.sdkStorageRoot.startsWith(externalRoot)) {
167 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
168 | } else {
169 | return true;
170 | }
171 | }
172 |
173 | /**
174 | * 获取外置存储卡剩余空间
175 | * @return
176 | */
177 | public long getAvailableExternalSize() {
178 | return getResidualSpace(sdkStorageRoot);
179 | }
180 |
181 | /**
182 | * 获取目录剩余空间
183 | * @param directoryPath
184 | * @return
185 | */
186 | private long getResidualSpace(String directoryPath) {
187 | try {
188 | StatFs sf = new StatFs(directoryPath);
189 | long blockSize = sf.getBlockSize();
190 | long availCount = sf.getAvailableBlocks();
191 | long availCountByte = availCount * blockSize;
192 | return availCountByte;
193 | } catch (Exception e) {
194 | e.printStackTrace();
195 | }
196 | return 0;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/PhotoPickerPhotoCell.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.components;
3 |
4 | import android.animation.Animator;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ObjectAnimator;
7 | import android.content.Context;
8 | import android.view.Gravity;
9 | import android.widget.FrameLayout;
10 |
11 | import com.dhc.gallery.R;
12 | import com.dhc.gallery.proxy.AnimatorListenerAdapterProxy;
13 | import com.dhc.gallery.utils.AndroidUtilities;
14 | import com.dhc.gallery.utils.LayoutHelper;
15 |
16 | import static com.dhc.gallery.ui.PhotoAlbumPickerActivity.DarkTheme;
17 |
18 | public class PhotoPickerPhotoCell extends FrameLayout {
19 |
20 | public BackupImageView photoImage;
21 | public FrameLayout checkFrame;
22 | public CheckBox checkBox;
23 | private AnimatorSet animator;
24 | public int itemWidth;
25 |
26 | public PhotoPickerPhotoCell(Context context) {
27 | super(context);
28 |
29 | photoImage = new BackupImageView(context);
30 | addView(photoImage,
31 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
32 |
33 | checkFrame = new FrameLayout(context);
34 | addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.RIGHT | Gravity.TOP));
35 |
36 | checkBox = new CheckBox(context, R.drawable.checkbig);
37 | checkBox.setSize(24);
38 | checkBox.setCheckOffset(AndroidUtilities.dp(1));
39 | checkBox.setDrawBackground(true);
40 | checkBox.setColor(0xff007aff);
41 | addView(checkBox,
42 | LayoutHelper.createFrame(24, 24, Gravity.RIGHT | Gravity.TOP, 0, 4, 4, 0));
43 | }
44 |
45 | @Override
46 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
47 | super.onMeasure(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY),
48 | MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY));
49 | }
50 |
51 | public void setChecked(final boolean checked, final boolean animated) {
52 | checkBox.setChecked(checked, animated);
53 | if (animator != null) {
54 | animator.cancel();
55 | animator = null;
56 | }
57 | if (animated) {
58 | if (checked) {
59 | setBackgroundColor(DarkTheme ? 0xff0A0A0A : 0xffffffff);
60 | }
61 | animator = new AnimatorSet();
62 | animator.playTogether(
63 | ObjectAnimator.ofFloat(photoImage, "scaleX", checked ? 0.85f : 1.0f),
64 | ObjectAnimator.ofFloat(photoImage, "scaleY", checked ? 0.85f : 1.0f));
65 | animator.setDuration(200);
66 | animator.addListener(new AnimatorListenerAdapterProxy() {
67 | @Override
68 | public void onAnimationEnd(Animator animation) {
69 | if (animator != null && animator.equals(animation)) {
70 | animator = null;
71 | if (!checked) {
72 | setBackgroundColor(0);
73 | }
74 | }
75 | }
76 |
77 | @Override
78 | public void onAnimationCancel(Animator animation) {
79 | if (animator != null && animator.equals(animation)) {
80 | animator = null;
81 | }
82 | }
83 | });
84 | animator.start();
85 | } else {
86 | setBackgroundColor(checked ? DarkTheme ? 0xff0A0A0A : 0xffffffff : 0);
87 | photoImage.setScaleX(checked ? 0.85f : 1.0f);
88 | photoImage.setScaleY(checked ? 0.85f : 1.0f);
89 | }
90 | }
91 |
92 | public void setChecked(int num, final boolean checked, final boolean animated) {
93 | checkBox.setChecked(num, checked, animated);
94 | if (animator != null) {
95 | animator.cancel();
96 | animator = null;
97 | }
98 | if (animated) {
99 | if (checked) {
100 | setBackgroundColor(DarkTheme ? 0xff0A0A0A : 0xffffffff);
101 | }
102 | animator = new AnimatorSet();
103 | animator.playTogether(
104 | ObjectAnimator.ofFloat(photoImage, "scaleX", checked ? 0.85f : 1.0f),
105 | ObjectAnimator.ofFloat(photoImage, "scaleY", checked ? 0.85f : 1.0f));
106 | animator.setDuration(200);
107 | animator.addListener(new AnimatorListenerAdapterProxy() {
108 | @Override
109 | public void onAnimationEnd(Animator animation) {
110 | if (animator != null && animator.equals(animation)) {
111 | animator = null;
112 | if (!checked) {
113 | setBackgroundColor(0);
114 | }
115 | }
116 | }
117 |
118 | @Override
119 | public void onAnimationCancel(Animator animation) {
120 | if (animator != null && animator.equals(animation)) {
121 | animator = null;
122 | }
123 | }
124 | });
125 | animator.start();
126 | } else {
127 | setBackgroundColor(checked ? DarkTheme ? 0xff0A0A0A : 0xffffffff : 0);
128 | photoImage.setScaleX(checked ? 0.85f : 1.0f);
129 | photoImage.setScaleY(checked ? 0.85f : 1.0f);
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/PhotoPickerSearchCell.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.components;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.text.TextUtils;
6 | import android.util.TypedValue;
7 | import android.view.Gravity;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.widget.FrameLayout;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 |
15 | import com.dhc.gallery.utils.AndroidUtilities;
16 | import com.dhc.gallery.utils.LayoutHelper;
17 | import com.dhc.gallery.R;
18 |
19 | public class PhotoPickerSearchCell extends LinearLayout {
20 |
21 | public interface PhotoPickerSearchCellDelegate {
22 | void didPressedSearchButton(int index);
23 | }
24 |
25 | private class SearchButton extends FrameLayout {
26 |
27 | private TextView textView1;
28 | private TextView textView2;
29 | private ImageView imageView;
30 | private View selector;
31 |
32 | public SearchButton(Context context) {
33 | super(context);
34 |
35 | setBackgroundColor(0xff1a1a1a);
36 |
37 | selector = new View(context);
38 | selector.setBackgroundResource(R.drawable.list_selector);
39 | addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
40 |
41 | imageView = new ImageView(context);
42 | imageView.setScaleType(ImageView.ScaleType.CENTER);
43 | addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP));
44 |
45 | textView1 = new TextView(context);
46 | textView1.setGravity(Gravity.CENTER_VERTICAL);
47 | textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
48 | // textView1.getPaint().setFakeBoldText(true);
49 | textView1.setTextColor(0xffffffff);
50 | textView1.setSingleLine(true);
51 | textView1.setEllipsize(TextUtils.TruncateAt.END);
52 | addView(textView1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 8, 4, 0));
53 |
54 | textView2 = new TextView(context);
55 | textView2.setGravity(Gravity.CENTER_VERTICAL);
56 | textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
57 | // textView2.getPaint().setFakeBoldText(true);
58 | textView2.setTextColor(0xff666666);
59 | textView2.setSingleLine(true);
60 | textView2.setEllipsize(TextUtils.TruncateAt.END);
61 | addView(textView2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 26, 4, 0));
62 | }
63 |
64 | @Override
65 | public boolean onTouchEvent(MotionEvent event) {
66 | if (Build.VERSION.SDK_INT >= 21) {
67 | selector.drawableHotspotChanged(event.getX(), event.getY());
68 | }
69 | return super.onTouchEvent(event);
70 | }
71 | }
72 |
73 | private PhotoPickerSearchCellDelegate delegate;
74 |
75 | public PhotoPickerSearchCell(Context context, boolean allowGifs) {
76 | super(context);
77 | setOrientation(HORIZONTAL);
78 |
79 | SearchButton searchButton = new SearchButton(context);
80 | searchButton.textView1.setText(R.string.SearchImages);
81 | searchButton.textView2.setText(R.string.SearchImagesInfo);
82 | searchButton.imageView.setImageResource(R.drawable.search_web);
83 | addView(searchButton);
84 | LayoutParams layoutParams = (LayoutParams) searchButton.getLayoutParams();
85 | layoutParams.weight = 0.5f;
86 | layoutParams.topMargin = AndroidUtilities.dp(4);
87 | layoutParams.height = AndroidUtilities.dp(48);
88 | layoutParams.width = 0;
89 | searchButton.setLayoutParams(layoutParams);
90 | searchButton.setOnClickListener(new OnClickListener() {
91 | @Override
92 | public void onClick(View v) {
93 | if (delegate != null) {
94 | delegate.didPressedSearchButton(0);
95 | }
96 | }
97 | });
98 |
99 | FrameLayout frameLayout = new FrameLayout(context);
100 | frameLayout.setBackgroundColor(0);
101 | addView(frameLayout);
102 | layoutParams = (LayoutParams) frameLayout.getLayoutParams();
103 | layoutParams.topMargin = AndroidUtilities.dp(4);
104 | layoutParams.height = AndroidUtilities.dp(48);
105 | layoutParams.width = AndroidUtilities.dp(4);
106 | frameLayout.setLayoutParams(layoutParams);
107 |
108 | searchButton = new SearchButton(context);
109 | searchButton.textView1.setText(R.string.SearchGifs);
110 | searchButton.textView2.setText("GIPHY");
111 | searchButton.imageView.setImageResource(R.drawable.search_gif);
112 | addView(searchButton);
113 | layoutParams = (LayoutParams) searchButton.getLayoutParams();
114 | layoutParams.weight = 0.5f;
115 | layoutParams.topMargin = AndroidUtilities.dp(4);
116 | layoutParams.height = AndroidUtilities.dp(48);
117 | layoutParams.width = 0;
118 | searchButton.setLayoutParams(layoutParams);
119 | if (allowGifs) {
120 | searchButton.setOnClickListener(new OnClickListener() {
121 | @Override
122 | public void onClick(View v) {
123 | if (delegate != null) {
124 | delegate.didPressedSearchButton(1);
125 | }
126 | }
127 | });
128 | } else {
129 | searchButton.setAlpha(0.5f);
130 | }
131 | }
132 |
133 | public void setDelegate(PhotoPickerSearchCellDelegate delegate) {
134 | this.delegate = delegate;
135 | }
136 |
137 | @Override
138 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
139 | super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(52), MeasureSpec.EXACTLY));
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/GalleryHelper.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.os.Environment;
6 | import android.provider.MediaStore;
7 | import android.widget.Toast;
8 |
9 | import com.dhc.gallery.ui.GalleryActivity;
10 |
11 | import static android.os.Environment.MEDIA_MOUNTED;
12 |
13 |
14 | /**
15 | * 创建者 邓浩宸
16 | * 创建时间 2017/4/17 15:52
17 | * 描述
18 | *
1, 选择单张图片 返回 String path
19 | *
2, 选择多张图片 返回 List
20 | * 3, 选择单张图片并裁剪 如果有输入path路径 返回 String path 否则返回 byte [] data 数据
21 | *
4, 拍照 返回 String path
22 | *
5, 拍照并裁剪 如果有输入path路径 返回 String path 否则返回 byte [] data 数据
23 | *
6, 摄影 返回 String path
24 | *
7, 选着视频 返回 String path
25 | */
26 | public class GalleryHelper {
27 |
28 |
29 | public GalleryHelper() {
30 | }
31 | private Activity mActivity;
32 | private Fragment mFragment;
33 | private android.support.v4.app.Fragment mV4Fragment;
34 |
35 |
36 | GalleryConfig configuration = new GalleryConfig();
37 | static GalleryHelper instance;
38 |
39 | /**
40 | * 开启页面
41 | * @param mActivity
42 | * @return
43 | */
44 | public static GalleryHelper with(Activity mActivity) {
45 | instance = new GalleryHelper();
46 | instance.mActivity=mActivity;
47 | return instance;
48 | }
49 |
50 | /**
51 | * 开启页面
52 | * @param mFragment
53 | * @return
54 | */
55 | public static GalleryHelper with(Fragment mFragment ){
56 | instance = new GalleryHelper();
57 | instance.mFragment=mFragment;
58 | return instance;
59 | }
60 | /**
61 | * 开启页面
62 | * @param mV4Fragment
63 | * @return GalleryHelper
64 | */
65 | public static GalleryHelper with(android.support.v4.app.Fragment mV4Fragment ){
66 | instance = new GalleryHelper();
67 | instance.mV4Fragment=mV4Fragment;
68 | return instance;
69 | }
70 | /**
71 | *
72 | * 选择的类型
73 | * @param type
74 | * {@link GalleryConfig.SELECT_PHOTO }
75 | * {@link GalleryConfig.TAKE_PHOTO }
76 | * {@link GalleryConfig.RECORD_VEDIO }
77 | * {@link GalleryConfig.SELECT_VEDIO }
78 | * {@link GalleryConfig.TAKEPHOTO_RECORDVEDIO }
79 | * @return GalleryHelper
80 | */
81 | public GalleryHelper type(int type) {
82 | configuration.setType(type);
83 | return this;
84 | }
85 |
86 | /**
87 | * 响应码
88 | * @param type
89 | * @return GalleryHelper
90 | */
91 | public GalleryHelper requestCode(int type) {
92 | configuration.setRequestCode(type);
93 | return this;
94 | }
95 |
96 | /**
97 | * 限定视频录制时间
98 | * @param limitRecordTime
99 | * @return GalleryHelper
100 | */
101 | public GalleryHelper limitRecordTime(int limitRecordTime) {
102 | configuration.setLimitRecordTime(limitRecordTime);
103 | return this;
104 | }
105 | /**
106 | * 限定视频录制大小
107 | * @param limitRecordSize
108 | * @return GalleryHelper
109 | */
110 | public GalleryHelper limitRecordSize(int limitRecordSize) {
111 | configuration.setLimitRecordSize(limitRecordSize);
112 | return this;
113 | }
114 |
115 | /**
116 | * 单选视频
117 | * @return
118 | */
119 | public GalleryHelper isSingleVedio() {
120 | configuration.setSingleVedio(true);
121 | configuration.setFilterMimeTypes( new String[]{
122 | MediaStore.Video.Media.DATA,
123 | MediaStore.Video.Media._ID,
124 | MediaStore.Video.Media.TITLE,
125 | MediaStore.Video.Media.MIME_TYPE
126 | });
127 | return this;
128 | }
129 |
130 | /**
131 | * 需要裁剪图片 这将返回一个 byte[] data数据类型
132 | * @return
133 | */
134 | public GalleryHelper isNeedCrop() {
135 | configuration.setNeedCrop(true);
136 | return this;
137 | }
138 |
139 | /**
140 | * 进行裁剪图片 返回一个传入路径值
141 | * @param filePath
142 | * @return
143 | */
144 | public GalleryHelper isNeedCropWithPath(String filePath) {
145 | configuration.setNeedCrop(true);
146 | configuration.setFilePath(filePath);
147 | return this;
148 | }
149 |
150 | /**
151 | * @param filterMimeTypes filter of media type, based on MimeType standards:
152 | * {http://www.w3school.com.cn/media/media_mimeref.asp}
153 | *
eg:new string[]{"image/gif","image/jpeg"}
154 | */
155 | public GalleryHelper selectVedioWithMimeTypes(String[] filterMimeTypes) {
156 | configuration.setSingleVedio(true);
157 | configuration.setFilterMimeTypes(filterMimeTypes);
158 | return this;
159 | }
160 |
161 | /**
162 | * @param hintOfPick hint of Toast when limit is reached
163 | */
164 | public GalleryHelper hintOfPick(String hintOfPick) {
165 | configuration.setHintOfPick(hintOfPick);
166 | return this;
167 | }
168 |
169 | /**
170 | * 选择单张照片
171 | * @return
172 | */
173 | public GalleryHelper singlePhoto() {
174 | configuration.setSinglePhoto(true);
175 | configuration.setLimitPickPhoto(1);
176 | return this;
177 | }
178 |
179 | /**
180 | * @param limitPickPhoto the limit of photos those can be selected
181 | */
182 | public GalleryHelper limitPickPhoto(int limitPickPhoto) {
183 | configuration.setLimitPickPhoto(limitPickPhoto);
184 | return this;
185 | }
186 |
187 |
188 | public void execute() {
189 | if(mActivity == null&&mFragment==null&&mV4Fragment==null) {
190 | return;
191 | }
192 | if(!existSDcard()){
193 | Toast.makeText(mActivity, "没有找到SD卡", Toast.LENGTH_SHORT).show();
194 | return;
195 | }
196 | if (mActivity!=null){
197 | GalleryActivity.openActivity(mActivity,configuration.getRequestCode(),configuration);
198 | }else if(mFragment!=null){
199 | GalleryActivity.openActivity(mFragment,configuration.getRequestCode(),configuration);
200 | }else if(mV4Fragment!=null){
201 | GalleryActivity.openActivity(mV4Fragment,configuration.getRequestCode(),configuration);
202 | }
203 | }
204 | private boolean existSDcard() {
205 | String externalStorageState;
206 | try {
207 | externalStorageState = Environment.getExternalStorageState();
208 | } catch (NullPointerException e) { // (sh)it happens (Issue #660)
209 | externalStorageState = "";
210 | } catch (IncompatibleClassChangeError e) { // (sh)it happens too (Issue #989)
211 | externalStorageState = "";
212 | }
213 | return MEDIA_MOUNTED.equals(externalStorageState);
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KrGallery
2 |
3 | Crop , Video, Photos, from Telegram
4 |
5 | 一个集**拍照和选择图片,裁剪**,**录制视频和选择视频**的强大且流畅简洁的库。
6 |
7 |
8 | KrGallery摘取于[Telegram](https://github.com/DrKLO/Telegram "https://github.com/DrKLO/Telegram"),基于[@TelegramGallery](https://github.com/TangXiaoLv/TelegramGallery)开发,快速,高效,低耗,轻量级,使用简单。
9 |
10 | - [功能](#功能)
11 | - [效果](#效果)
12 | - [安装](#安装)
13 | - [用途](#用途)
14 | - [选择图片](#选择图片)
15 | - [拍照](#拍照)
16 | - [获取图片](#获取图片)
17 | - [录制视频](#录制视频)
18 | - [选择视频](#选择视频)
19 | - [获取视频](#获取视频)
20 | - [注意](#注意)
21 | - [API](#API说明)
22 | - [TODO](#TODO)
23 | - [作者](#作者)
24 | - [感谢](#感谢)
25 | - [更变日志]()
26 |
27 | ## 功能
28 |
29 | * 快速,高效,低耗
30 | * 简易的整合,轻量级
31 | * 基本没有依赖于任何的三方库
32 | * 集拍照,选择图片,裁剪,录制视频和选择视频为一体
33 |
34 | ----------
35 |
36 | ## 安装
37 |
38 | [](https://jitpack.io/#chengzichen/KrGallery) [  ](https://bintray.com/chengzichen/maven/gallerylib/_latestVersion)
39 |
40 | - 方式一:
41 |
42 | **Step 1. 在根目录的gradle文件中配置**
43 |
44 |
45 | **Add it in your root build.gradle at the end of repositories:**
46 |
47 |
48 | allprojects {
49 | repositories {
50 | ...
51 | maven { url 'https://jitpack.io' }
52 | }
53 | }
54 |
55 |
56 | **step2 添加依赖:**
57 |
58 | dependencies {
59 | compile 'com.github.chengzichen:KrGallery:v1.03'
60 | }
61 |
62 |
63 |
64 | - 方式二:
65 |
66 |
67 | **Step 1. 在根目录的gradle文件中配置**
68 |
69 | allprojects {
70 | repositories {
71 | ...
72 | jcenter()
73 | }
74 | }
75 |
76 |
77 | **step2 添加依赖:**
78 |
79 |
80 | dependencies {
81 | compile 'com.dhc.krgallery:gallerylib:1.0.3'
82 | }
83 |
84 |
85 |
86 | ----------
87 |
88 |
89 | ## 效果
90 | 
91 | 
92 | 
93 | 
94 |
95 | ## 用途
96 |
97 | ### 选择图片
98 |
99 | - **单选**(type:GalleryConfig.SELECT_PHOTO)
100 |
101 | GalleryHelper
102 | .with(MainActivity.this) //Activity or Fragment
103 | .type(GalleryConfig.SELECT_PHOTO) //选择类型
104 | .requestCode(12) //startResultActivity requestcode 自己定义
105 | .singlePhoto() //选择单张图片
106 | .execute();
107 |
108 |
109 | - **多选**(type:GalleryConfig.SELECT_PHOTO)
110 |
111 | GalleryHelper
112 | .with(MainActivity.this) //Activity or Fragment
113 | .type(GalleryConfig.SELECT_PHOTO) //选择类型
114 | .requestCode(12) //startResultActivity requestcode 自己定义
115 | .limitPickPhoto(9) //图片选择张数
116 | .execute();
117 |
118 |
119 | - **需要裁剪图片**
120 |
121 | String outputPath = StorageUtil.getWritePath(StorageUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP);//定义裁剪图片输出在sdcard的位置
122 |
123 | GalleryHelper
124 | .with(MainActivity.this) //Activity or Fragment
125 | .type(GalleryConfig.SELECT_PHOTO) //选择类型
126 | .requestCode(12) //startResultActivity requestcode 自己定义
127 | .singlePhoto() //选择单张图片
128 | .isNeedCropWithPath(outputPath) //需要裁剪并输出图片的路径,没有传入时返回数据为byte[]
129 | .execute();
130 |
131 |
132 |
133 | ### 拍照
134 |
135 | - 拍照
136 |
137 | GalleryHelper
138 | .with(MainActivity.this) //Activity or Fragment
139 | .type(GalleryConfig.TAKE_PHOTO) //选择类型,拍照
140 | .requestCode(12) //startResultActivity requestcode 自己定义
141 | .execute();
142 |
143 |
144 | - 需要裁剪图片
145 |
146 | outputPath = StorageUtil.getWritePath(StorageUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP);
147 | GalleryHelper
148 | .with(MainActivity.this) //Activity or Fragment
149 | .type(GalleryConfig.TAKE_PHOTO) //选择类型
150 | .isNeedCropWithPath(outputPath) //需要裁剪并输出图片的路径,没有传入时返回数据为byte[]
151 | .requestCode(12) //startResultActivity requestcode 自己定义
152 | .execute();
153 |
154 | **onActivityResult**
155 |
156 |
157 | ### 获取图片
158 |
159 |
160 |
161 |
162 | > **在Acitivity 或者Fragment 中onActivityResult 方法**
163 |
164 |
165 | String path = dataIntent.getStringExtra(GalleryActivity.PHOTOS);
166 |
167 |
168 | > **注意 : 需要裁剪并输出图片的路径,没有传入时返回数据为byte[]**
169 |
170 |
171 |
172 | byte[] datas =dataIntent.getByteArrayExtra(GalleryActivity.DATA);
173 |
174 | ### 录制视频(可限制录制时间)
175 |
176 |
177 | GalleryHelper
178 | .with(MainActivity.this) //Activity or Fragment
179 | .type(GalleryConfig.RECORD_VEDIO)//选择类型
180 | .requestCode(12) //startResultActivity requestcode 自己定义
181 | .limitRecordTime(10) //定义录制视频时间
182 | .limitRecordSize(10) //定义录制视频时间
183 | .execute();
184 |
185 | ### 选择视频
186 |
187 | GalleryHelper
188 | .with(MainActivity.this) //Activity or Fragment
189 | .type(GalleryConfig.SELECT_VEDIO)//Activity or Fragment
190 | .requestCode(12) //startResultActivity requestcode 自己定义
191 | .isSingleVedio() //是否是单选视频
192 | .execute();
193 |
194 |
195 | ### 获取视频
196 |
197 | > **在Acitivity 或者Fragment 中onActivityResult 方法**
198 |
199 |
200 | String path = data.getStringExtra(GalleryActivity.VIDEO);
201 |
202 | ### 注意
203 |
204 | - **需要裁剪并输出图片的路径,没有传入时返回数据为byte[]**
205 | - **选取多张图片时裁剪只对第一张照片有效**
206 | - **选着视频目前支持单个视频**
207 |
208 |
209 | ### API说明
210 |
211 | - 类[GalleryHelper](KrGallery/gallery/src/main/java/com/dhc/gallery/GalleryHelper.java)
212 |
213 | 1. with() //Activity or Fragment
214 | 2. type(int type)
215 | 1. GalleryConfig.SELECT_PHOTO //选择图片
216 | 2. GalleryConfig.TAKE_PHOTO //拍照
217 | 3. GalleryConfig.RECORD_VEDIO //录制视频
218 | 4. GalleryConfig.SELECT_VEDIO //选择单个视频
219 | 5. GalleryConfig.TAKEPHOTO_RECORDVEDIO //拍照和录制视频
220 | 3. requestCode(int code) //startResultActivity requestcode 自己定义
221 | 4. isSingleVedio() //选择单个视频,必须调用方法
222 | 5. isNeedCropWithPath() //进行裁剪图片 返回一个传入路径值
223 | 6. isNeedCrop() //需要裁剪图片 这将返回一个 byte[] data数据类型
224 | 7. selectVedioWithMimeTypes() //filter of media type, based on MimeType standards:{http://www.w3school.com.cn/media/media_mimeref.asp}eg:new string[]{"image/gif","image/jpeg"}
225 | 8. hintOfPick() //hint of Toast when limit is reached
226 | 9. singlePhoto() //选择单张照片
227 | 10. limitPickPhoto(int) //hint of Toast when limit is reached
228 | 11. limitRecordTime(int) //限制视频录制的时间
229 | 11. execute()
230 |
231 |
232 | ## TODO
233 |
234 | - 修改部分样式
235 | - 自定义主题
236 | - 视频的编辑
237 | - 图片的编辑
238 | - 提供压缩
239 | - 优化代码
240 |
241 |
242 | ## 作者
243 |
244 |
245 |
246 | - github: [@chengzichen](https://github.com/chengzichen)
247 |
248 |
249 | - 博客 : [邓浩宸的博客](https://chengzichen.github.io/)
250 |
251 |
252 | ## 感谢
253 |
254 |
255 |
256 | > [@Telegram](https://github.com/DrKLO/Telegram "https://github.com/DrKLO/Telegram")
257 |
258 |
259 |
260 | > [@TelegramGallery](https://github.com/TangXiaoLv/TelegramGallery)
261 |
262 | ## 友情链接
263 |
264 |
265 |
266 | > [@XDroid](https://github.com/limedroid) 老司机
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/actionbar/ActionBarMenu.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.actionbar;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.widget.LinearLayout;
8 |
9 | import com.dhc.gallery.Theme;
10 | import com.dhc.gallery.utils.AndroidUtilities;
11 | import com.dhc.gallery.utils.LayoutHelper;
12 |
13 | public class ActionBarMenu extends LinearLayout {
14 |
15 | protected ActionBar parentActionBar;
16 |
17 | public ActionBarMenu(Context context, ActionBar layer) {
18 | super(context);
19 | setOrientation(LinearLayout.HORIZONTAL);
20 | parentActionBar = layer;
21 | }
22 |
23 | public ActionBarMenu(Context context) {
24 | super(context);
25 | }
26 |
27 | public View addItemResource(int id, int resourceId) {
28 | LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
29 | View view = li.inflate(resourceId, null);
30 | view.setTag(id);
31 | addView(view);
32 | LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
33 | layoutParams.height = LayoutHelper.MATCH_PARENT;
34 | view.setBackgroundDrawable(Theme.createBarSelectorDrawable(parentActionBar.itemsBackgroundColor));
35 | view.setLayoutParams(layoutParams);
36 | view.setOnClickListener(new OnClickListener() {
37 | @Override
38 | public void onClick(View view) {
39 | onItemClick((Integer) view.getTag());
40 | }
41 | });
42 | return view;
43 | }
44 |
45 | public ActionBarMenuItem addItem(int id, Drawable drawable) {
46 | return addItem(id, 0, parentActionBar.itemsBackgroundColor, drawable, AndroidUtilities.dp(48));
47 | }
48 |
49 | public ActionBarMenuItem addItem(int id, int icon) {
50 | return addItem(id, icon, parentActionBar.itemsBackgroundColor);
51 | }
52 |
53 | public ActionBarMenuItem addItem(int id, int icon, int backgroundColor) {
54 | return addItem(id, icon, backgroundColor, null, AndroidUtilities.dp(48));
55 | }
56 |
57 | public ActionBarMenuItem addItemWithWidth(int id, int icon, int width) {
58 | return addItem(id, icon, parentActionBar.itemsBackgroundColor, null, width);
59 | }
60 |
61 | public ActionBarMenuItem addItem(int id, int icon, int backgroundColor, Drawable drawable, int width) {
62 | ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor);
63 | menuItem.setTag(id);
64 | if (drawable != null) {
65 | menuItem.iconView.setImageDrawable(drawable);
66 | } else {
67 | menuItem.iconView.setImageResource(icon);
68 | }
69 | addView(menuItem);
70 | LayoutParams layoutParams = (LayoutParams) menuItem.getLayoutParams();
71 | layoutParams.height = LayoutHelper.MATCH_PARENT;
72 | layoutParams.width = width;
73 | menuItem.setLayoutParams(layoutParams);
74 | menuItem.setOnClickListener(new OnClickListener() {
75 | @Override
76 | public void onClick(View view) {
77 | ActionBarMenuItem item = (ActionBarMenuItem) view;
78 | if (item.hasSubMenu()) {
79 | if (parentActionBar.actionBarMenuOnItemClick.canOpenMenu()) {
80 | item.toggleSubMenu();
81 | }
82 | } else if (item.isSearchField()) {
83 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true));
84 | } else {
85 | onItemClick((Integer) view.getTag());
86 | }
87 | }
88 | });
89 | return menuItem;
90 | }
91 |
92 | public View addItem(int id,View view) {
93 | view.setTag(id);
94 | addView(view);
95 | view.setOnClickListener(new OnClickListener() {
96 | @Override
97 | public void onClick(View view) {
98 | onItemClick((Integer) view.getTag());
99 | }
100 | });
101 | return view;
102 | }
103 |
104 | public void hideAllPopupMenus() {
105 | int count = getChildCount();
106 | for (int a = 0; a < count; a++) {
107 | View view = getChildAt(a);
108 | if (view instanceof ActionBarMenuItem) {
109 | ((ActionBarMenuItem) view).closeSubMenu();
110 | }
111 | }
112 | }
113 |
114 | public void onItemClick(int id) {
115 | if (parentActionBar.actionBarMenuOnItemClick != null) {
116 | parentActionBar.actionBarMenuOnItemClick.onItemClick(id);
117 | }
118 | }
119 |
120 | public void clearItems() {
121 | removeAllViews();
122 | }
123 |
124 | public void onMenuButtonPressed() {
125 | int count = getChildCount();
126 | for (int a = 0; a < count; a++) {
127 | View view = getChildAt(a);
128 | if (view instanceof ActionBarMenuItem) {
129 | ActionBarMenuItem item = (ActionBarMenuItem) view;
130 | if (item.getVisibility() != VISIBLE) {
131 | continue;
132 | }
133 | if (item.hasSubMenu()) {
134 | item.toggleSubMenu();
135 | break;
136 | } else if (item.overrideMenuClick) {
137 | onItemClick((Integer) item.getTag());
138 | break;
139 | }
140 | }
141 | }
142 | }
143 |
144 | public void closeSearchField() {
145 | int count = getChildCount();
146 | for (int a = 0; a < count; a++) {
147 | View view = getChildAt(a);
148 | if (view instanceof ActionBarMenuItem) {
149 | ActionBarMenuItem item = (ActionBarMenuItem) view;
150 | if (item.isSearchField()) {
151 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(false));
152 | break;
153 | }
154 | }
155 | }
156 | }
157 |
158 | public void openSearchField(boolean toggle, String text) {
159 | int count = getChildCount();
160 | for (int a = 0; a < count; a++) {
161 | View view = getChildAt(a);
162 | if (view instanceof ActionBarMenuItem) {
163 | ActionBarMenuItem item = (ActionBarMenuItem) view;
164 | if (item.isSearchField()) {
165 | if (toggle) {
166 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true));
167 | }
168 | item.getSearchField().setText(text);
169 | item.getSearchField().setSelection(text.length());
170 | break;
171 | }
172 | }
173 | }
174 | }
175 |
176 | public ActionBarMenuItem getItem(int id) {
177 | View v = findViewWithTag(id);
178 | if (v instanceof ActionBarMenuItem) {
179 | return (ActionBarMenuItem) v;
180 | }
181 | return null;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/tl/Photo.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.tl;
3 |
4 | import java.util.ArrayList;
5 |
6 | public class Photo extends TLObject {
7 | public long id;
8 | public long access_hash;
9 | public int user_id;
10 | public int date;
11 | public String caption;
12 | public GeoPoint geo;
13 | public ArrayList sizes = new ArrayList<>();
14 |
15 | public static Photo TLdeserialize(AbstractSerializedData stream, int constructor,
16 | boolean exception) {
17 | Photo result = null;
18 | switch (constructor) {
19 | case 0x22b56751:
20 | result = new TL_photo_old();
21 | break;
22 | case 0xcded42fe:
23 | result = new TL_photo();
24 | break;
25 | case 0xc3838076:
26 | result = new TL_photo_old2();
27 | break;
28 | case 0x2331b22d:
29 | result = new TL_photoEmpty();
30 | break;
31 | }
32 | if (result == null && exception) {
33 | throw new RuntimeException(String.format("can't parse magic %x in Photo", constructor));
34 | }
35 | if (result != null) {
36 | result.readParams(stream, exception);
37 | }
38 | return result;
39 | }
40 |
41 | public static class TL_photo_old extends TL_photo {
42 | public static int constructor = 0x22b56751;
43 |
44 | public void readParams(AbstractSerializedData stream, boolean exception) {
45 | id = stream.readInt64(exception);
46 | access_hash = stream.readInt64(exception);
47 | user_id = stream.readInt32(exception);
48 | date = stream.readInt32(exception);
49 | caption = stream.readString(exception);
50 | geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception);
51 | int magic = stream.readInt32(exception);
52 | if (magic != 0x1cb5c415) {
53 | if (exception) {
54 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic));
55 | }
56 | return;
57 | }
58 | int count = stream.readInt32(exception);
59 | for (int a = 0; a < count; a++) {
60 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception),
61 | exception);
62 | if (object == null) {
63 | return;
64 | }
65 | sizes.add(object);
66 | }
67 | }
68 |
69 | public void serializeToStream(AbstractSerializedData stream) {
70 | stream.writeInt32(constructor);
71 | stream.writeInt64(id);
72 | stream.writeInt64(access_hash);
73 | stream.writeInt32(user_id);
74 | stream.writeInt32(date);
75 | stream.writeString(caption);
76 | geo.serializeToStream(stream);
77 | stream.writeInt32(0x1cb5c415);
78 | int count = sizes.size();
79 | stream.writeInt32(count);
80 | for (int a = 0; a < count; a++) {
81 | sizes.get(a).serializeToStream(stream);
82 | }
83 | }
84 | }
85 |
86 | public static class TL_photo extends Photo {
87 | public static int constructor = 0xcded42fe;
88 |
89 | public void readParams(AbstractSerializedData stream, boolean exception) {
90 | id = stream.readInt64(exception);
91 | access_hash = stream.readInt64(exception);
92 | date = stream.readInt32(exception);
93 | int magic = stream.readInt32(exception);
94 | if (magic != 0x1cb5c415) {
95 | if (exception) {
96 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic));
97 | }
98 | return;
99 | }
100 | int count = stream.readInt32(exception);
101 | for (int a = 0; a < count; a++) {
102 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception),
103 | exception);
104 | if (object == null) {
105 | return;
106 | }
107 | sizes.add(object);
108 | }
109 | }
110 |
111 | public void serializeToStream(AbstractSerializedData stream) {
112 | stream.writeInt32(constructor);
113 | stream.writeInt64(id);
114 | stream.writeInt64(access_hash);
115 | stream.writeInt32(date);
116 | stream.writeInt32(0x1cb5c415);
117 | int count = sizes.size();
118 | stream.writeInt32(count);
119 | for (int a = 0; a < count; a++) {
120 | sizes.get(a).serializeToStream(stream);
121 | }
122 | }
123 | }
124 |
125 | public static class TL_photo_old2 extends TL_photo {
126 | public static int constructor = 0xc3838076;
127 |
128 | public void readParams(AbstractSerializedData stream, boolean exception) {
129 | id = stream.readInt64(exception);
130 | access_hash = stream.readInt64(exception);
131 | user_id = stream.readInt32(exception);
132 | date = stream.readInt32(exception);
133 | geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception);
134 | int magic = stream.readInt32(exception);
135 | if (magic != 0x1cb5c415) {
136 | if (exception) {
137 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic));
138 | }
139 | return;
140 | }
141 | int count = stream.readInt32(exception);
142 | for (int a = 0; a < count; a++) {
143 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception),
144 | exception);
145 | if (object == null) {
146 | return;
147 | }
148 | sizes.add(object);
149 | }
150 | }
151 |
152 | public void serializeToStream(AbstractSerializedData stream) {
153 | stream.writeInt32(constructor);
154 | stream.writeInt64(id);
155 | stream.writeInt64(access_hash);
156 | stream.writeInt32(user_id);
157 | stream.writeInt32(date);
158 | geo.serializeToStream(stream);
159 | stream.writeInt32(0x1cb5c415);
160 | int count = sizes.size();
161 | stream.writeInt32(count);
162 | for (int a = 0; a < count; a++) {
163 | sizes.get(a).serializeToStream(stream);
164 | }
165 | }
166 | }
167 |
168 | public static class TL_photoEmpty extends Photo {
169 | public static int constructor = 0x2331b22d;
170 |
171 | public void readParams(AbstractSerializedData stream, boolean exception) {
172 | id = stream.readInt64(exception);
173 | }
174 |
175 | public void serializeToStream(AbstractSerializedData stream) {
176 | stream.writeInt32(constructor);
177 | stream.writeInt64(id);
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/PhotoPickerAlbumsCell.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.components;
3 |
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.text.TextUtils;
7 | import android.util.TypedValue;
8 | import android.view.Gravity;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 | import android.widget.FrameLayout;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 |
15 | import com.dhc.gallery.utils.AndroidUtilities;
16 | import com.dhc.gallery.utils.LayoutHelper;
17 | import com.dhc.gallery.utils.MediaController;
18 | import com.dhc.gallery.R;
19 |
20 | public class PhotoPickerAlbumsCell extends FrameLayout {
21 |
22 | public interface PhotoPickerAlbumsCellDelegate {
23 | void didSelectAlbum(MediaController.AlbumEntry albumEntry);
24 | }
25 |
26 | private AlbumView[] albumViews;
27 | private MediaController.AlbumEntry[] albumEntries;
28 | private int albumsCount;
29 | private PhotoPickerAlbumsCellDelegate delegate;
30 |
31 | private class AlbumView extends FrameLayout {
32 |
33 | private BackupImageView imageView;
34 | private TextView nameTextView;
35 | private TextView countTextView;
36 | private View selector;
37 |
38 | public AlbumView(Context context) {
39 | super(context);
40 |
41 | imageView = new BackupImageView(context);
42 | addView(imageView,
43 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
44 |
45 | LinearLayout linearLayout = new LinearLayout(context);
46 | linearLayout.setOrientation(LinearLayout.HORIZONTAL);
47 | linearLayout.setBackgroundColor(0x7f000000);
48 | addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28,
49 | Gravity.LEFT | Gravity.BOTTOM));
50 |
51 | nameTextView = new TextView(context);
52 | nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
53 | nameTextView.setTextColor(0xffffffff);
54 | nameTextView.setSingleLine(true);
55 | nameTextView.setEllipsize(TextUtils.TruncateAt.END);
56 | nameTextView.setMaxLines(1);
57 | nameTextView.setGravity(Gravity.CENTER_VERTICAL);
58 | linearLayout.addView(nameTextView,
59 | LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 8, 0, 0, 0));
60 |
61 | countTextView = new TextView(context);
62 | countTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
63 | countTextView.setTextColor(0xffaaaaaa);
64 | countTextView.setSingleLine(true);
65 | countTextView.setEllipsize(TextUtils.TruncateAt.END);
66 | countTextView.setMaxLines(1);
67 | countTextView.setGravity(Gravity.CENTER_VERTICAL);
68 | linearLayout.addView(countTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT,
69 | LayoutHelper.MATCH_PARENT, 4, 0, 4, 0));
70 |
71 | selector = new View(context);
72 | selector.setBackgroundResource(R.drawable.list_selector);
73 | addView(selector,
74 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
75 | }
76 |
77 | @Override
78 | public boolean onTouchEvent(MotionEvent event) {
79 | if (Build.VERSION.SDK_INT >= 21) {
80 | selector.drawableHotspotChanged(event.getX(), event.getY());
81 | }
82 | return super.onTouchEvent(event);
83 | }
84 | }
85 |
86 | public PhotoPickerAlbumsCell(Context context) {
87 | super(context);
88 | albumEntries = new MediaController.AlbumEntry[4];
89 | albumViews = new AlbumView[4];
90 | for (int a = 0; a < 4; a++) {
91 | albumViews[a] = new AlbumView(context);
92 | addView(albumViews[a]);
93 | albumViews[a].setVisibility(INVISIBLE);
94 | albumViews[a].setTag(a);
95 | albumViews[a].setOnClickListener(new OnClickListener() {
96 | @Override
97 | public void onClick(View v) {
98 | if (delegate != null) {
99 | delegate.didSelectAlbum(albumEntries[(Integer) v.getTag()]);
100 | }
101 | }
102 | });
103 | }
104 | }
105 |
106 | public void setAlbumsCount(int count) {
107 | for (int a = 0; a < albumViews.length; a++) {
108 | albumViews[a].setVisibility(a < count ? VISIBLE : INVISIBLE);
109 | }
110 | albumsCount = count;
111 | }
112 |
113 | public void setDelegate(PhotoPickerAlbumsCellDelegate delegate) {
114 | this.delegate = delegate;
115 | }
116 |
117 | public void setAlbum(int a, MediaController.AlbumEntry albumEntry) {
118 | albumEntries[a] = albumEntry;
119 |
120 | if (albumEntry != null) {
121 | AlbumView albumView = albumViews[a];
122 | albumView.imageView.setOrientation(0, true);
123 | if (albumEntry.coverPhoto != null && albumEntry.coverPhoto.path != null) {
124 | albumView.imageView.setOrientation(albumEntry.coverPhoto.orientation, true);
125 | if (albumEntry.coverPhoto.isVideo) {
126 | albumView.imageView.setImage(
127 | "vthumb://" + albumEntry.coverPhoto.imageId + ":"
128 | + albumEntry.coverPhoto.path,
129 | null, getContext().getResources().getDrawable(R.drawable.nophotos));
130 | } else {
131 | albumView.imageView.setImage(
132 | "thumb://" + albumEntry.coverPhoto.imageId + ":"
133 | + albumEntry.coverPhoto.path,
134 | null, getContext().getResources().getDrawable(R.drawable.nophotos));
135 | }
136 | } else {
137 | albumView.imageView.setImageResource(R.drawable.nophotos);
138 | }
139 | albumView.nameTextView.setText(albumEntry.bucketName);
140 | albumView.countTextView.setText(String.format("%d", albumEntry.photos.size()));
141 | } else {
142 | albumViews[a].setVisibility(INVISIBLE);
143 | }
144 | }
145 |
146 | @Override
147 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
148 | int itemWidth;
149 | if (AndroidUtilities.isTablet()) {
150 | itemWidth = (AndroidUtilities.dp(490) - ((albumsCount + 1) * AndroidUtilities.dp(4)))
151 | / albumsCount;
152 | } else {
153 | itemWidth = (AndroidUtilities.displaySize.x
154 | - ((albumsCount + 1) * AndroidUtilities.dp(4))) / albumsCount;
155 | }
156 |
157 | for (int a = 0; a < albumsCount; a++) {
158 | LayoutParams layoutParams = (LayoutParams) albumViews[a].getLayoutParams();
159 | layoutParams.topMargin = AndroidUtilities.dp(4);
160 | layoutParams.leftMargin = (itemWidth + AndroidUtilities.dp(4)) * a;
161 | layoutParams.width = itemWidth;
162 | layoutParams.height = itemWidth;
163 | layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
164 | albumViews[a].setLayoutParams(layoutParams);
165 | }
166 |
167 | super.onMeasure(widthMeasureSpec, MeasureSpec
168 | .makeMeasureSpec(AndroidUtilities.dp(4) + itemWidth, MeasureSpec.EXACTLY));
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/BaseDialog.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.components;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.os.Handler;
7 | import android.util.DisplayMetrics;
8 | import android.view.Gravity;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.view.Window;
12 | import android.view.WindowManager;
13 | import android.widget.Button;
14 | import android.widget.FrameLayout;
15 | import android.widget.ImageView;
16 | import android.widget.TextView;
17 |
18 | import com.dhc.gallery.R;
19 | import com.dhc.gallery.utils.AndroidUtilities;
20 |
21 |
22 | /**
23 | * Created by shiming on 16/11/28.
24 | */
25 |
26 | public class BaseDialog extends Dialog implements View.OnClickListener,DialogInterface.OnDismissListener {
27 |
28 | private Context mContext;
29 |
30 | private FrameLayout mContainer;
31 |
32 | private FrameLayout mBtnPanel;
33 |
34 | private int lifeTime;
35 |
36 | private Handler handler;
37 |
38 | private OnClickListener mListener;
39 | private ImageView closeIV;
40 |
41 | public BaseDialog(Context context) {
42 | super(context, R.style.dialog_custom);
43 | mContext = context;
44 | handler = new Handler(context.getMainLooper());
45 | initView();
46 | }
47 |
48 | private void initView() {
49 | Window window = getWindow();
50 | window.setGravity(Gravity.CENTER); // 此处可以设置dialog显示的位置为居中
51 | window.setWindowAnimations(R.style.bottom_menu_animation); // 添加动画效果
52 | View child = getLayoutInflater().inflate(R.layout.layout_dialog_base, null, false);
53 | setContentView(child);
54 | mContainer = (FrameLayout) findViewById(R.id.fl_container);
55 | mBtnPanel = (FrameLayout) findViewById(R.id.fl_btn_panel);
56 | closeIV = (ImageView) findViewById(R.id.iv_close);
57 | closeIV.setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View view) {
60 | dismiss();
61 | }
62 | });
63 | Window dialogWindow = getWindow();
64 | WindowManager.LayoutParams lp = dialogWindow.getAttributes();
65 | DisplayMetrics d = mContext.getResources().getDisplayMetrics(); // 获取屏幕宽、高用
66 | lp.width = (int) (d.widthPixels * 0.8); // 宽度设置为屏幕的0.9
67 | dialogWindow.setAttributes(lp);
68 | setIsCancelable(true);
69 |
70 | setOnDismissListener(this);
71 | }
72 |
73 | public BaseDialog setLifeTime(int seconds){
74 | lifeTime = seconds;
75 | return this;
76 | }
77 |
78 | public BaseDialog setWindowAnimation(int style){
79 | getWindow().setWindowAnimations(style);
80 | return this;
81 | }
82 |
83 | public BaseDialog showCloseBtn(boolean isShow){
84 | if (isShow){
85 | closeIV.setVisibility(View.VISIBLE);
86 | }else{
87 | closeIV.setVisibility(View.GONE);
88 | }
89 | return this;
90 | }
91 |
92 | public BaseDialog setCloseBtnClickListener(View.OnClickListener listener){
93 | closeIV.setOnClickListener(listener);
94 | return this;
95 | }
96 |
97 | public BaseDialog setMatchParent() {
98 | Window dialogWindow = getWindow();
99 | WindowManager.LayoutParams lp = dialogWindow.getAttributes();
100 | lp.width = WindowManager.LayoutParams.MATCH_PARENT;
101 | dialogWindow.setAttributes(lp);
102 | return this;
103 | }
104 |
105 | public BaseDialog setWindowBackground(int color){
106 | mContainer.setBackgroundColor(mContext.getResources().getColor(color));
107 | mBtnPanel.setBackgroundColor(mContext.getResources().getColor(color));
108 | return this;
109 | }
110 |
111 | public BaseDialog setDialogSize(float widthDP,float heightDP){
112 | Window dialogWindow = getWindow();
113 | WindowManager.LayoutParams lp = dialogWindow.getAttributes();
114 | lp.width = AndroidUtilities.dp2px(getContext(),widthDP);
115 | lp.height = AndroidUtilities.dp2px(getContext(),heightDP);
116 | dialogWindow.setAttributes(lp);
117 | return this;
118 | }
119 |
120 | public BaseDialog setGravity(int gravity) {
121 | getWindow().setGravity(gravity);
122 | return this;
123 | }
124 |
125 | public BaseDialog setIsCancelable(boolean isCancelable) {
126 | setCancelable(isCancelable);
127 | return this;
128 | }
129 |
130 | public BaseDialog setCanCancelOutside(boolean isCan){
131 | setCanceledOnTouchOutside(isCan);
132 | return this;
133 | }
134 |
135 | public BaseDialog setCustomerContent(int layoutId) {
136 | View child = getLayoutInflater().inflate(layoutId, null, false);
137 | mContainer.addView(child);
138 | return this;
139 | }
140 |
141 |
142 |
143 | public BaseDialog setBackgroundResource(int viewId, int resId) {
144 | findViewById(viewId).setBackgroundResource(resId);
145 | return this;
146 | }
147 |
148 | public BaseDialog setText(int viewId, int textId) {
149 | ((TextView) findViewById(viewId)).setText(textId);
150 | return this;
151 | }
152 | public BaseDialog setText(int viewId, String text) {
153 | ((TextView) findViewById(viewId)).setText(text);
154 | return this;
155 | }
156 |
157 |
158 | public BaseDialog setTextColor(int viewId, int colorId) {
159 | ((TextView) findViewById(viewId)).setTextColor(colorId);
160 | return this;
161 | }
162 |
163 | public BaseDialog setImageResource(int viewId, int resId) {
164 | ((ImageView) findViewById(viewId)).setImageResource(resId);
165 | return this;
166 | }
167 |
168 | public BaseDialog setViewOnClickListener(int viewId, View.OnClickListener listener) {
169 | findViewById(viewId).setOnClickListener(listener);
170 | return this;
171 | }
172 |
173 | @Override
174 | public void show() {
175 | super.show();
176 | if (lifeTime > 0){
177 | handler.postDelayed(new Runnable() {
178 | @Override
179 | public void run() {
180 | dismiss();
181 | }
182 | },lifeTime * 1000);
183 | }
184 | }
185 |
186 | public BaseDialog setListener(OnClickListener listener){
187 | mListener = listener;
188 | return this;
189 | }
190 |
191 |
192 | public BaseDialog setBtnPanelView(int layoutId){
193 | setBtnPanelView(layoutId,null);
194 | return this;
195 | }
196 |
197 | public BaseDialog setBtnPanelView(int layoutId, OnClickListener listener) {
198 | ViewGroup viewGroup = (ViewGroup) getLayoutInflater().inflate(layoutId, null, false);
199 | int count = viewGroup.getChildCount();
200 | for (int i = 0; i < count; i++) {
201 | View child = viewGroup.getChildAt(i);
202 | if (child instanceof Button) {
203 | child.setOnClickListener(this);
204 | }
205 | }
206 | mListener = listener;
207 | mBtnPanel.addView(viewGroup);
208 | // 设置容器的背景 可以根据实际情况动态添加
209 | // mContainer.setBackgroundResource(R.drawable.zhenai_library_dialog_base_top_shape);
210 | return this;
211 | }
212 |
213 | @Override
214 | public void onClick(View view) {
215 | if (mListener != null) {
216 | mListener.onClick(this, view.getId());
217 | }
218 |
219 | }
220 |
221 | @Override
222 | public void onDismiss(DialogInterface dialogInterface) {
223 | handler.removeCallbacksAndMessages(null);
224 | handler = null;
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/utils/LayoutHelper.java:
--------------------------------------------------------------------------------
1 |
2 | package com.dhc.gallery.utils;
3 |
4 | import android.widget.FrameLayout;
5 | import android.widget.LinearLayout;
6 | import android.widget.RelativeLayout;
7 | import android.widget.ScrollView;
8 |
9 | public class LayoutHelper {
10 |
11 | public static final int MATCH_PARENT = -1;
12 | public static final int WRAP_CONTENT = -2;
13 |
14 | private static int getSize(float size) {
15 | return (int) (size < 0 ? size : AndroidUtilities.dp(size));
16 | }
17 |
18 | public static FrameLayout.LayoutParams createScroll(int width, int height, int gravity) {
19 | return new ScrollView.LayoutParams(getSize(width), getSize(height), gravity);
20 | }
21 |
22 | public static FrameLayout.LayoutParams createFrame(int width, float height, int gravity,
23 | float leftMargin, float topMargin, float rightMargin, float bottomMargin) {
24 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getSize(width),
25 | getSize(height), gravity);
26 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin),
27 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
28 | return layoutParams;
29 | }
30 |
31 | public static FrameLayout.LayoutParams createFrame(int width, int height, int gravity) {
32 | return new FrameLayout.LayoutParams(getSize(width), getSize(height), gravity);
33 | }
34 |
35 | public static FrameLayout.LayoutParams createFrame(int width, float height) {
36 | return new FrameLayout.LayoutParams(getSize(width), getSize(height));
37 | }
38 |
39 | public static RelativeLayout.LayoutParams createRelative(float width, float height,
40 | int leftMargin, int topMargin, int rightMargin, int bottomMargin, int alignParent,
41 | int alignRelative, int anchorRelative) {
42 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(getSize(width),
43 | getSize(height));
44 | if (alignParent >= 0) {
45 | layoutParams.addRule(alignParent);
46 | }
47 | if (alignRelative >= 0 && anchorRelative >= 0) {
48 | layoutParams.addRule(alignRelative, anchorRelative);
49 | }
50 | layoutParams.leftMargin = AndroidUtilities.dp(leftMargin);
51 | layoutParams.topMargin = AndroidUtilities.dp(topMargin);
52 | layoutParams.rightMargin = AndroidUtilities.dp(rightMargin);
53 | layoutParams.bottomMargin = AndroidUtilities.dp(bottomMargin);
54 | return layoutParams;
55 | }
56 |
57 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int leftMargin,
58 | int topMargin, int rightMargin, int bottomMargin) {
59 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin, -1,
60 | -1, -1);
61 | }
62 |
63 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int leftMargin,
64 | int topMargin, int rightMargin, int bottomMargin, int alignParent) {
65 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin,
66 | alignParent, -1, -1);
67 | }
68 |
69 | public static RelativeLayout.LayoutParams createRelative(float width, float height,
70 | int leftMargin, int topMargin, int rightMargin, int bottomMargin, int alignRelative,
71 | int anchorRelative) {
72 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin, -1,
73 | alignRelative, anchorRelative);
74 | }
75 |
76 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int alignParent,
77 | int alignRelative, int anchorRelative) {
78 | return createRelative(width, height, 0, 0, 0, 0, alignParent, alignRelative,
79 | anchorRelative);
80 | }
81 |
82 | public static RelativeLayout.LayoutParams createRelative(int width, int height) {
83 | return createRelative(width, height, 0, 0, 0, 0, -1, -1, -1);
84 | }
85 |
86 | public static RelativeLayout.LayoutParams createRelative(int width, int height,
87 | int alignParent) {
88 | return createRelative(width, height, 0, 0, 0, 0, alignParent, -1, -1);
89 | }
90 |
91 | public static RelativeLayout.LayoutParams createRelative(int width, int height,
92 | int alignRelative, int anchorRelative) {
93 | return createRelative(width, height, 0, 0, 0, 0, -1, alignRelative, anchorRelative);
94 | }
95 |
96 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight,
97 | int gravity, int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
98 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
99 | getSize(height), weight);
100 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin),
101 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
102 | layoutParams.gravity = gravity;
103 | return layoutParams;
104 | }
105 |
106 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight,
107 | int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
108 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
109 | getSize(height), weight);
110 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin),
111 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
112 | return layoutParams;
113 | }
114 |
115 | public static LinearLayout.LayoutParams createLinear(int width, int height, int gravity,
116 | int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
117 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
118 | getSize(height));
119 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin),
120 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
121 | layoutParams.gravity = gravity;
122 | return layoutParams;
123 | }
124 |
125 | public static LinearLayout.LayoutParams createLinear(int width, int height, float leftMargin,
126 | float topMargin, float rightMargin, float bottomMargin) {
127 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
128 | getSize(height));
129 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin),
130 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin));
131 | return layoutParams;
132 | }
133 |
134 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight,
135 | int gravity) {
136 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
137 | getSize(height), weight);
138 | layoutParams.gravity = gravity;
139 | return layoutParams;
140 | }
141 |
142 | public static LinearLayout.LayoutParams createLinear(int width, int height, int gravity) {
143 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width),
144 | getSize(height));
145 | layoutParams.gravity = gravity;
146 | return layoutParams;
147 | }
148 |
149 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight) {
150 | return new LinearLayout.LayoutParams(getSize(width), getSize(height), weight);
151 | }
152 |
153 | public static LinearLayout.LayoutParams createLinear(int width, int height) {
154 | return new LinearLayout.LayoutParams(getSize(width), getSize(height));
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/components/ClippingImageView.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.components;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapShader;
6 | import android.graphics.Canvas;
7 | import android.graphics.Matrix;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.Shader;
11 | import android.view.View;
12 |
13 | public class ClippingImageView extends View {
14 |
15 | private int clipBottom;
16 | private int clipLeft;
17 | private int clipRight;
18 | private int clipTop;
19 | private int orientation;
20 | private RectF drawRect;
21 | private Paint paint;
22 | private Bitmap bmp;
23 | private Matrix matrix;
24 |
25 | private boolean needRadius;
26 | private int radius;
27 | private BitmapShader bitmapShader;
28 | private Paint roundPaint;
29 | private RectF roundRect;
30 | private RectF bitmapRect;
31 | private Matrix shaderMatrix;
32 |
33 | private float animationProgress;
34 | private float animationValues[][];
35 |
36 | public ClippingImageView(Context context) {
37 | super(context);
38 | paint = new Paint();
39 | paint.setFilterBitmap(true);
40 | matrix = new Matrix();
41 | drawRect = new RectF();
42 | bitmapRect = new RectF();
43 | roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
44 | roundRect = new RectF();
45 | shaderMatrix = new Matrix();
46 | }
47 |
48 | public void setAnimationValues(float[][] values) {
49 | animationValues = values;
50 | }
51 |
52 | public float getAnimationProgress() {
53 | return animationProgress;
54 | }
55 |
56 | public void setAnimationProgress(float progress) {
57 | animationProgress = progress;
58 |
59 | setScaleX(animationValues[0][0] + (animationValues[1][0] - animationValues[0][0]) * animationProgress);
60 | setScaleY(animationValues[0][1] + (animationValues[1][1] - animationValues[0][1]) * animationProgress);
61 | setTranslationX(animationValues[0][2] + (animationValues[1][2] - animationValues[0][2]) * animationProgress);
62 | setTranslationY(animationValues[0][3] + (animationValues[1][3] - animationValues[0][3]) * animationProgress);
63 | setClipHorizontal((int) (animationValues[0][4] + (animationValues[1][4] - animationValues[0][4]) * animationProgress));
64 | setClipTop((int) (animationValues[0][5] + (animationValues[1][5] - animationValues[0][5]) * animationProgress));
65 | setClipBottom((int) (animationValues[0][6] + (animationValues[1][6] - animationValues[0][6]) * animationProgress));
66 | setRadius((int) (animationValues[0][7] + (animationValues[1][7] - animationValues[0][7]) * animationProgress));
67 |
68 | invalidate();
69 | }
70 |
71 | public int getClipBottom() {
72 | return clipBottom;
73 | }
74 |
75 | public int getClipHorizontal() {
76 | return clipRight;
77 | }
78 |
79 | public int getClipLeft() {
80 | return clipLeft;
81 | }
82 |
83 | public int getClipRight() {
84 | return clipRight;
85 | }
86 |
87 | public int getClipTop() {
88 | return clipTop;
89 | }
90 |
91 | public int getRadius() {
92 | return radius;
93 | }
94 |
95 | public void onDraw(Canvas canvas) {
96 | if (getVisibility() != VISIBLE) {
97 | return;
98 | }
99 | if (bmp != null) {
100 | float scaleY = getScaleY();
101 | canvas.save();
102 |
103 | if (needRadius) {
104 | shaderMatrix.reset();
105 | roundRect.set(0, 0, getWidth(), getHeight());
106 |
107 | int bitmapW;
108 | int bitmapH;
109 | if (orientation % 360 == 90 || orientation % 360 == 270) {
110 | bitmapW = bmp.getHeight();
111 | bitmapH = bmp.getWidth();
112 | } else {
113 | bitmapW = bmp.getWidth();
114 | bitmapH = bmp.getHeight();
115 | }
116 | float scaleW = getWidth() != 0 ? bitmapW / getWidth() : 1.0f;
117 | float scaleH = getHeight() != 0 ? bitmapH / getHeight() : 1.0f;
118 | float scale = Math.min(scaleW, scaleH);
119 | if (Math.abs(scaleW - scaleH) > 0.00001f) {
120 | int w = (int) Math.floor(getWidth() * scale);
121 | int h = (int) Math.floor(getHeight() * scale);
122 | bitmapRect.set((bitmapW - w) / 2, (bitmapH - h) / 2, w, h);
123 | shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.START);
124 | } else {
125 | bitmapRect.set(0, 0, bmp.getWidth(), bmp.getHeight());
126 | shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL);
127 | }
128 | bitmapShader.setLocalMatrix(shaderMatrix);
129 | canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY);
130 | canvas.drawRoundRect(roundRect, radius, radius, roundPaint);
131 | } else {
132 | if (orientation == 90 || orientation == 270) {
133 | drawRect.set(-getHeight() / 2, -getWidth() / 2, getHeight() / 2, getWidth() / 2);
134 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
135 | matrix.postRotate(orientation, 0, 0);
136 | matrix.postTranslate(getWidth() / 2, getHeight() / 2);
137 | } else if (orientation == 180) {
138 | drawRect.set(-getWidth() / 2, -getHeight() / 2, getWidth() / 2, getHeight() / 2);
139 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
140 | matrix.postRotate(orientation, 0, 0);
141 | matrix.postTranslate(getWidth() / 2, getHeight() / 2);
142 | } else {
143 | drawRect.set(0, 0, getWidth(), getHeight());
144 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL);
145 | }
146 |
147 | canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY);
148 | try {
149 | canvas.drawBitmap(bmp, matrix, paint);
150 | } catch (Exception e) {
151 | e.printStackTrace();
152 | }
153 | }
154 | canvas.restore();
155 | }
156 | }
157 |
158 | public void setClipBottom(int value) {
159 | clipBottom = value;
160 | invalidate();
161 | }
162 |
163 | public void setClipHorizontal(int value) {
164 | clipRight = value;
165 | clipLeft = value;
166 | invalidate();
167 | }
168 |
169 | public void setClipLeft(int value) {
170 | clipLeft = value;
171 | invalidate();
172 | }
173 |
174 | public void setClipRight(int value) {
175 | clipRight = value;
176 | invalidate();
177 | }
178 |
179 | public void setClipTop(int value) {
180 | clipTop = value;
181 | invalidate();
182 | }
183 |
184 | public void setClipVertical(int value) {
185 | clipBottom = value;
186 | clipTop = value;
187 | invalidate();
188 | }
189 |
190 | public void setOrientation(int angle) {
191 | orientation = angle;
192 | }
193 |
194 | public void setImageBitmap(Bitmap bitmap) {
195 | bmp = bitmap;
196 | if (bitmap != null) {
197 | bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
198 | if (needRadius) {
199 | bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
200 | roundPaint.setShader(bitmapShader);
201 | }
202 | }
203 | invalidate();
204 | }
205 |
206 | public void setNeedRadius(boolean value) {
207 | needRadius = value;
208 | }
209 |
210 | public void setRadius(int value) {
211 | radius = value;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/gallery/src/main/java/com/dhc/gallery/utils/NotificationCenter.java:
--------------------------------------------------------------------------------
1 | package com.dhc.gallery.utils;
2 |
3 | import android.os.Looper;
4 | import android.util.SparseArray;
5 |
6 | import java.util.ArrayList;
7 |
8 | public class NotificationCenter {
9 |
10 | private static int totalEvents = 1;
11 |
12 | public static final int didReceivedNewMessages = totalEvents++;
13 | public static final int dialogsNeedReload = totalEvents++;
14 | public static final int closeChats = totalEvents++;
15 | public static final int messagesDeleted = totalEvents++;
16 | public static final int mediaDidLoaded = totalEvents++;
17 | public static final int mediaCountDidLoaded = totalEvents++;
18 | public static final int dialogPhotosLoaded = totalEvents++;
19 | public static final int removeAllMessagesFromDialog = totalEvents++;
20 | public static final int recentImagesDidLoaded = totalEvents++;
21 | public static final int didReplacedPhotoInMemCache = totalEvents++;
22 | public static final int musicDidLoaded = totalEvents++;
23 |
24 | public static final int recordProgressChanged = totalEvents++;
25 | public static final int httpFileDidLoaded = totalEvents++;
26 | public static final int httpFileDidFailedLoad = totalEvents++;
27 | public static final int cameraInitied = totalEvents++;
28 | public static final int messageThumbGenerated = totalEvents++;
29 |
30 | public static final int emojiDidLoaded = totalEvents++;
31 | public static final int recordStopped = totalEvents++;
32 | public static final int FileDidUpload = totalEvents++;
33 | public static final int FileDidFailUpload = totalEvents++;
34 | public static final int FileUploadProgressChanged = totalEvents++;
35 | public static final int FileLoadProgressChanged = totalEvents++;
36 | public static final int FileDidLoaded = totalEvents++;
37 | public static final int FileDidFailedLoad = totalEvents++;
38 | public static final int recordStarted = totalEvents++;
39 |
40 | public static final int screenshotTook = totalEvents++;
41 | public static final int albumsDidLoaded = totalEvents++;
42 |
43 | private SparseArray> observers = new SparseArray<>();
44 | private SparseArray> removeAfterBroadcast = new SparseArray<>();
45 | private SparseArray> addAfterBroadcast = new SparseArray<>();
46 | private ArrayList delayedPosts = new ArrayList<>(10);
47 |
48 | private int broadcasting = 0;
49 | private int[] allowedNotifications;
50 | private boolean animationInProgress;
51 |
52 | public interface NotificationCenterDelegate {
53 | void didReceivedNotification(int id, Object... args);
54 | }
55 |
56 | private class DelayedPost {
57 |
58 | private DelayedPost(int id, Object[] args) {
59 | this.id = id;
60 | this.args = args;
61 | }
62 |
63 | private int id;
64 | private Object[] args;
65 | }
66 |
67 | private static volatile NotificationCenter Instance = null;
68 |
69 | public static NotificationCenter getInstance() {
70 | NotificationCenter localInstance = Instance;
71 | if (localInstance == null) {
72 | synchronized (NotificationCenter.class) {
73 | localInstance = Instance;
74 | if (localInstance == null) {
75 | Instance = localInstance = new NotificationCenter();
76 | }
77 | }
78 | }
79 | return localInstance;
80 | }
81 |
82 | public void setAllowedNotificationsDutingAnimation(int notifications[]) {
83 | allowedNotifications = notifications;
84 | }
85 |
86 | public void setAnimationInProgress(boolean value) {
87 | animationInProgress = value;
88 | if (!animationInProgress && !delayedPosts.isEmpty()) {
89 | for (DelayedPost delayedPost : delayedPosts) {
90 | postNotificationNameInternal(delayedPost.id, true, delayedPost.args);
91 | }
92 | delayedPosts.clear();
93 | }
94 | }
95 |
96 | public boolean isAnimationInProgress() {
97 | return animationInProgress;
98 | }
99 |
100 | public void postNotificationName(int id, Object... args) {
101 | boolean allowDuringAnimation = false;
102 | if (allowedNotifications != null) {
103 | for (int a = 0; a < allowedNotifications.length; a++) {
104 | if (allowedNotifications[a] == id) {
105 | allowDuringAnimation = true;
106 | break;
107 | }
108 | }
109 | }
110 | postNotificationNameInternal(id, allowDuringAnimation, args);
111 | }
112 |
113 | public void postNotificationNameInternal(int id, boolean allowDuringAnimation, Object... args) {
114 | if (Looper.getMainLooper() != Looper.myLooper()){
115 | throw new RuntimeException("addObserver allowed only from MAIN thread");
116 | }
117 |
118 | if (!allowDuringAnimation && animationInProgress) {
119 | DelayedPost delayedPost = new DelayedPost(id, args);
120 | delayedPosts.add(delayedPost);
121 | return;
122 | }
123 | broadcasting++;
124 | ArrayList