mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 20:18:26 +00:00
commit
11237d2009
11
res/drawable/home_activity_gradient.xml
Normal file
11
res/drawable/home_activity_gradient.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<gradient
|
||||
android:startColor="@android:color/transparent"
|
||||
android:endColor="#000000"
|
||||
android:angle="270" />
|
||||
|
||||
</shape>
|
18
res/drawable/ic_group.xml
Normal file
18
res/drawable/ic_group.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="17dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="17">
|
||||
<path
|
||||
android:pathData="M11.7187,8.2031C12.4511,8.2031 13.1347,8.02 13.7695,7.6538C14.4043,7.2876 14.9047,6.7871 15.271,6.1523C15.6372,5.5176 15.8203,4.834 15.8203,4.1016C15.8203,3.3691 15.6372,2.6855 15.271,2.0508C14.9047,1.416 14.4043,0.9155 13.7695,0.5493C13.1347,0.1831 12.4511,0 11.7187,0C10.9863,0 10.3027,0.1831 9.6679,0.5493C9.0332,0.9155 8.5327,1.416 8.1665,2.0508C7.8003,2.6855 7.6172,3.3691 7.6172,4.1016C7.6172,4.834 7.8003,5.5176 8.1665,6.1523C8.5327,6.7871 9.0332,7.2876 9.6679,7.6538C10.3027,8.02 10.9863,8.2031 11.7187,8.2031ZM19.9218,7.0312C20.7275,7.0312 21.4172,6.7444 21.9909,6.1706C22.5646,5.5969 22.8515,4.9072 22.8515,4.1016C22.8515,3.2959 22.5646,2.6062 21.9909,2.0325C21.4172,1.4587 20.7275,1.1719 19.9218,1.1719C19.1162,1.1719 18.4265,1.4587 17.8527,2.0325C17.279,2.6062 16.9921,3.2959 16.9921,4.1016C16.9921,4.9072 17.279,5.5969 17.8527,6.1706C18.4265,6.7444 19.1162,7.0312 19.9218,7.0312ZM3.5156,7.0312C4.3213,7.0312 5.011,6.7444 5.5847,6.1706C6.1584,5.5969 6.4453,4.9072 6.4453,4.1016C6.4453,3.2959 6.1584,2.6062 5.5847,2.0325C5.011,1.4587 4.3213,1.1719 3.5156,1.1719C2.71,1.1719 2.0203,1.4587 1.4465,2.0325C0.8728,2.6062 0.5859,3.2959 0.5859,4.1016C0.5859,4.9072 0.8728,5.5969 1.4465,6.1706C2.0203,6.7444 2.71,7.0312 3.5156,7.0312ZM11.7187,6.4453C11.084,6.4453 10.5346,6.2134 10.0708,5.7495C9.6069,5.2856 9.375,4.7363 9.375,4.1016C9.375,3.4668 9.6069,2.9175 10.0708,2.4536C10.5346,1.9897 11.084,1.7578 11.7187,1.7578C12.3535,1.7578 12.9028,1.9897 13.3667,2.4536C13.8305,2.9175 14.0625,3.4668 14.0625,4.1016C14.0625,4.7363 13.8305,5.2856 13.3667,5.7495C12.9028,6.2134 12.3535,6.4453 11.7187,6.4453ZM19.9218,5.2734C19.6044,5.2734 19.3298,5.1575 19.0979,4.9255C18.8659,4.6936 18.75,4.4189 18.75,4.1016C18.75,3.7842 18.8659,3.5095 19.0979,3.2776C19.3298,3.0456 19.6044,2.9297 19.9218,2.9297C20.2392,2.9297 20.5139,3.0456 20.7458,3.2776C20.9777,3.5095 21.0937,3.7842 21.0937,4.1016C21.0937,4.4189 20.9777,4.6936 20.7458,4.9255C20.5139,5.1575 20.2392,5.2734 19.9218,5.2734ZM3.5156,5.2734C3.1982,5.2734 2.9236,5.1575 2.6916,4.9255C2.4597,4.6936 2.3437,4.4189 2.3437,4.1016C2.3437,3.7842 2.4597,3.5095 2.6916,3.2776C2.9236,3.0456 3.1982,2.9297 3.5156,2.9297C3.833,2.9297 4.1077,3.0456 4.3396,3.2776C4.5715,3.5095 4.6875,3.7842 4.6875,4.1016C4.6875,4.4189 4.5715,4.6936 4.3396,4.9255C4.1077,5.1575 3.833,5.2734 3.5156,5.2734ZM22.5585,12.1582C22.8027,12.1582 23.0102,12.0727 23.1811,11.9018C23.352,11.7309 23.4374,11.5234 23.4374,11.2793C23.4374,10.4248 23.1384,9.6985 22.5402,9.1003C21.9421,8.5022 21.2158,8.2031 20.3613,8.2031L20.3613,8.2031L19.4824,8.2031C18.8476,8.2031 18.2739,8.374 17.7612,8.7158C18.2739,9.1064 18.7011,9.5459 19.0429,10.0342C19.2138,9.9853 19.3603,9.9609 19.4824,9.9609L19.4824,9.9609L20.3613,9.9609C20.7275,9.9609 21.0388,10.0891 21.2951,10.3454C21.5515,10.6018 21.6796,10.9131 21.6796,11.2793C21.6796,11.5234 21.7651,11.7309 21.936,11.9018C22.1069,12.0727 22.3144,12.1582 22.5585,12.1582ZM0.8789,12.1582C1.123,12.1582 1.3306,12.0727 1.5015,11.9018C1.6724,11.7309 1.7578,11.5234 1.7578,11.2793C1.7578,10.9131 1.886,10.6018 2.1423,10.3454C2.3987,10.0891 2.71,9.9609 3.0762,9.9609L3.0762,9.9609L3.9551,9.9609C4.1016,9.9609 4.248,9.9975 4.3945,10.0708C4.7363,9.5581 5.1636,9.1064 5.6763,8.7158C5.1636,8.374 4.5898,8.2031 3.9551,8.2031L3.9551,8.2031L3.0762,8.2031C2.2217,8.2031 1.4954,8.5022 0.8972,9.1003C0.2991,9.6985 0,10.4248 0,11.2793C0,11.5234 0.0854,11.7309 0.2563,11.9018C0.4272,12.0727 0.6348,12.1582 0.8789,12.1582ZM16.9921,16.4062C17.4804,16.4062 17.8955,16.2353 18.2373,15.8935C18.5791,15.5517 18.75,15.1367 18.75,14.6484L18.75,14.6484L18.75,13.0005C18.75,12.146 18.5058,11.3647 18.0175,10.6567C17.5293,9.9243 16.8518,9.4177 15.9851,9.1369C15.1184,8.8562 14.2456,8.8501 13.3667,9.1186C12.8051,9.2895 12.2497,9.375 11.7004,9.375C11.1511,9.375 10.6079,9.2895 10.0708,9.1186C9.1919,8.8501 8.3191,8.8562 7.4524,9.1369C6.5857,9.4177 5.9082,9.9182 5.4199,10.6384C4.9316,11.3586 4.6875,12.146 4.6875,13.0005L4.6875,13.0005L4.6875,14.6484C4.6875,15.1367 4.8584,15.5517 5.2002,15.8935C5.542,16.2353 5.957,16.4062 6.4453,16.4062L6.4453,16.4062L16.9921,16.4062ZM16.9921,14.6484L6.4453,14.6484L6.4453,13.0005C6.4453,12.3413 6.6772,11.7737 7.1411,11.2976C7.605,10.8215 8.1665,10.5713 8.8257,10.5469C9.7778,10.9375 10.7422,11.1328 11.7187,11.1328C12.6953,11.1328 13.6596,10.9375 14.6118,10.5469C15.271,10.5713 15.8325,10.8215 16.2963,11.2976C16.7602,11.7737 16.9921,12.3413 16.9921,13.0005L16.9921,13.0005L16.9921,14.6484Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M11.7187,8.2031C12.4511,8.2031 13.1347,8.02 13.7695,7.6538C14.4043,7.2876 14.9047,6.7871 15.271,6.1523C15.6372,5.5176 15.8203,4.834 15.8203,4.1016C15.8203,3.3691 15.6372,2.6855 15.271,2.0508C14.9047,1.416 14.4043,0.9155 13.7695,0.5493C13.1347,0.1831 12.4511,0 11.7187,0C10.9863,0 10.3027,0.1831 9.6679,0.5493C9.0332,0.9155 8.5327,1.416 8.1665,2.0508C7.8003,2.6855 7.6172,3.3691 7.6172,4.1016C7.6172,4.834 7.8003,5.5176 8.1665,6.1523C8.5327,6.7871 9.0332,7.2876 9.6679,7.6538C10.3027,8.02 10.9863,8.2031 11.7187,8.2031ZM19.9218,7.0312C20.7275,7.0312 21.4172,6.7444 21.9909,6.1706C22.5646,5.5969 22.8515,4.9072 22.8515,4.1016C22.8515,3.2959 22.5646,2.6062 21.9909,2.0325C21.4172,1.4587 20.7275,1.1719 19.9218,1.1719C19.1162,1.1719 18.4265,1.4587 17.8527,2.0325C17.279,2.6062 16.9921,3.2959 16.9921,4.1016C16.9921,4.9072 17.279,5.5969 17.8527,6.1706C18.4265,6.7444 19.1162,7.0312 19.9218,7.0312ZM3.5156,7.0312C4.3213,7.0312 5.011,6.7444 5.5847,6.1706C6.1584,5.5969 6.4453,4.9072 6.4453,4.1016C6.4453,3.2959 6.1584,2.6062 5.5847,2.0325C5.011,1.4587 4.3213,1.1719 3.5156,1.1719C2.71,1.1719 2.0203,1.4587 1.4465,2.0325C0.8728,2.6062 0.5859,3.2959 0.5859,4.1016C0.5859,4.9072 0.8728,5.5969 1.4465,6.1706C2.0203,6.7444 2.71,7.0312 3.5156,7.0312ZM11.7187,6.4453C11.084,6.4453 10.5346,6.2134 10.0708,5.7495C9.6069,5.2856 9.375,4.7363 9.375,4.1016C9.375,3.4668 9.6069,2.9175 10.0708,2.4536C10.5346,1.9897 11.084,1.7578 11.7187,1.7578C12.3535,1.7578 12.9028,1.9897 13.3667,2.4536C13.8305,2.9175 14.0625,3.4668 14.0625,4.1016C14.0625,4.7363 13.8305,5.2856 13.3667,5.7495C12.9028,6.2134 12.3535,6.4453 11.7187,6.4453ZM19.9218,5.2734C19.6044,5.2734 19.3298,5.1575 19.0979,4.9255C18.8659,4.6936 18.75,4.4189 18.75,4.1016C18.75,3.7842 18.8659,3.5095 19.0979,3.2776C19.3298,3.0456 19.6044,2.9297 19.9218,2.9297C20.2392,2.9297 20.5139,3.0456 20.7458,3.2776C20.9777,3.5095 21.0937,3.7842 21.0937,4.1016C21.0937,4.4189 20.9777,4.6936 20.7458,4.9255C20.5139,5.1575 20.2392,5.2734 19.9218,5.2734ZM3.5156,5.2734C3.1982,5.2734 2.9236,5.1575 2.6916,4.9255C2.4597,4.6936 2.3437,4.4189 2.3437,4.1016C2.3437,3.7842 2.4597,3.5095 2.6916,3.2776C2.9236,3.0456 3.1982,2.9297 3.5156,2.9297C3.833,2.9297 4.1077,3.0456 4.3396,3.2776C4.5715,3.5095 4.6875,3.7842 4.6875,4.1016C4.6875,4.4189 4.5715,4.6936 4.3396,4.9255C4.1077,5.1575 3.833,5.2734 3.5156,5.2734ZM22.5585,12.1582C22.8027,12.1582 23.0102,12.0727 23.1811,11.9018C23.352,11.7309 23.4374,11.5234 23.4374,11.2793C23.4374,10.4248 23.1384,9.6985 22.5402,9.1003C21.9421,8.5022 21.2158,8.2031 20.3613,8.2031L20.3613,8.2031L19.4824,8.2031C18.8476,8.2031 18.2739,8.374 17.7612,8.7158C18.2739,9.1064 18.7011,9.5459 19.0429,10.0342C19.2138,9.9853 19.3603,9.9609 19.4824,9.9609L19.4824,9.9609L20.3613,9.9609C20.7275,9.9609 21.0388,10.0891 21.2951,10.3454C21.5515,10.6018 21.6796,10.9131 21.6796,11.2793C21.6796,11.5234 21.7651,11.7309 21.936,11.9018C22.1069,12.0727 22.3144,12.1582 22.5585,12.1582ZM0.8789,12.1582C1.123,12.1582 1.3306,12.0727 1.5015,11.9018C1.6724,11.7309 1.7578,11.5234 1.7578,11.2793C1.7578,10.9131 1.886,10.6018 2.1423,10.3454C2.3987,10.0891 2.71,9.9609 3.0762,9.9609L3.0762,9.9609L3.9551,9.9609C4.1016,9.9609 4.248,9.9975 4.3945,10.0708C4.7363,9.5581 5.1636,9.1064 5.6763,8.7158C5.1636,8.374 4.5898,8.2031 3.9551,8.2031L3.9551,8.2031L3.0762,8.2031C2.2217,8.2031 1.4954,8.5022 0.8972,9.1003C0.2991,9.6985 0,10.4248 0,11.2793C0,11.5234 0.0854,11.7309 0.2563,11.9018C0.4272,12.0727 0.6348,12.1582 0.8789,12.1582ZM16.9921,16.4062C17.4804,16.4062 17.8955,16.2353 18.2373,15.8935C18.5791,15.5517 18.75,15.1367 18.75,14.6484L18.75,14.6484L18.75,13.0005C18.75,12.146 18.5058,11.3647 18.0175,10.6567C17.5293,9.9243 16.8518,9.4177 15.9851,9.1369C15.1184,8.8562 14.2456,8.8501 13.3667,9.1186C12.8051,9.2895 12.2497,9.375 11.7004,9.375C11.1511,9.375 10.6079,9.2895 10.0708,9.1186C9.1919,8.8501 8.3191,8.8562 7.4524,9.1369C6.5857,9.4177 5.9082,9.9182 5.4199,10.6384C4.9316,11.3586 4.6875,12.146 4.6875,13.0005L4.6875,13.0005L4.6875,14.6484C4.6875,15.1367 4.8584,15.5517 5.2002,15.8935C5.542,16.2353 5.957,16.4062 6.4453,16.4062L6.4453,16.4062L16.9921,16.4062ZM16.9921,14.6484L6.4453,14.6484L6.4453,13.0005C6.4453,12.3413 6.6772,11.7737 7.1411,11.2976C7.605,10.8215 8.1665,10.5713 8.8257,10.5469C9.7778,10.9375 10.7422,11.1328 11.7187,11.1328C12.6953,11.1328 13.6596,10.9375 14.6118,10.5469C15.271,10.5713 15.8325,10.8215 16.2963,11.2976C16.7602,11.7737 16.9921,12.3413 16.9921,13.0005L16.9921,13.0005L16.9921,14.6484Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
12
res/drawable/ic_message.xml
Normal file
12
res/drawable/ic_message.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M4.2929,14.2929C4.4804,14.1054 4.7348,14 5,14L17,14C17.5523,14 18,13.5523 18,13L18,3C18,2.4477 17.5523,2 17,2L3,2C2.4477,2 2,2.4477 2,3L2,16.5858L4.2929,14.2929ZM5.4142,16L1.7071,19.7071C1.0771,20.3371 0,19.8909 0,19L0,3C0,1.3431 1.3431,0 3,0L17,0C18.6569,0 20,1.3431 20,3L20,13C20,14.6569 18.6569,16 17,16L5.4142,16Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</vector>
|
18
res/drawable/ic_plus.xml
Normal file
18
res/drawable/ic_plus.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="23dp"
|
||||
android:height="23dp"
|
||||
android:viewportWidth="23"
|
||||
android:viewportHeight="23">
|
||||
<path
|
||||
android:pathData="M11.4167,0.1111L11.4167,0.1111A1.5278,1.5278 0,0 1,12.9444 1.6389L12.9444,20.5833A1.5278,1.5278 0,0 1,11.4167 22.1111L11.4167,22.1111A1.5278,1.5278 0,0 1,9.8889 20.5833L9.8889,1.6389A1.5278,1.5278 0,0 1,11.4167 0.1111z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M22.4167,11.1111C22.4167,11.9549 21.7327,12.6389 20.8889,12.6389L1.9444,12.6389C1.1007,12.6389 0.4167,11.9549 0.4167,11.1111C0.4167,10.2673 1.1007,9.5833 1.9444,9.5833L20.8889,9.5833C21.7327,9.5833 22.4167,10.2673 22.4167,11.1111Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
@ -1,7 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<gradient android:type="radial" android:gradientRadius="36dp" android:startColor="@color/accent" android:endColor="@android:color/transparent" />
|
||||
</shape>
|
||||
android:shape="oval" />
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
|
||||
<solid android:color="@color/accent" />
|
||||
</shape>
|
@ -1,42 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/default_session_background"
|
||||
android:orientation="vertical">
|
||||
android:background="@drawable/default_session_background" >
|
||||
|
||||
<EditText
|
||||
style="@style/SmallSessionEditText"
|
||||
android:id="@+id/nameEditText"
|
||||
<LinearLayout
|
||||
android:id="@+id/mainContentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
style="@style/SmallSessionEditText"
|
||||
android:id="@+id/nameEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:layout_marginRight="@dimen/large_spacing"
|
||||
android:hint="Enter a group name" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:layout_marginRight="@dimen/large_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Closed groups are end-to-end encrypted group chats for up to 10 members. They provide the same privacy protections as one-on-one sessions." />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/separator" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/emptyStateContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:layout_marginRight="@dimen/large_spacing"
|
||||
android:hint="Enter a group name" />
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:layout_centerInParent="true">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:layout_marginRight="@dimen/large_spacing"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.6"
|
||||
android:textAlignment="center"
|
||||
android:text="Closed groups are end-to-end encrypted group chats for up to 10 members. They provide the same privacy protections as one-on-one sessions." />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="You don't have any contacts yet" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/separator" />
|
||||
<Button
|
||||
style="@style/MediumProminentOutlineButton"
|
||||
android:id="@+id/createNewPrivateChatButton"
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="Start a Session" />
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -40,28 +40,6 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="64dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/createClosedGroupButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_group_white_24dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/joinPublicChatButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginLeft="@dimen/medium_spacing"
|
||||
android:src="@drawable/ic_globe" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</android.support.v7.widget.Toolbar>
|
||||
@ -80,36 +58,18 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<!-- The button below intentionally uses dp for the text size and not sp -->
|
||||
<View
|
||||
android:id="@+id/gradientView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/home_activity_gradient" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
<org.thoughtcrime.securesms.loki.redesign.views.NewConversationButtonSetView
|
||||
android:id="@+id/newConversationButtonSet"
|
||||
android:layout_width="252dp"
|
||||
android:layout_height="212dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="@dimen/new_conversation_button_bottom_offset">
|
||||
|
||||
<View
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:background="@drawable/new_conversation_button_background" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/newConversationButton"
|
||||
android:layout_width="@dimen/new_conversation_button_size"
|
||||
android:layout_height="@dimen/new_conversation_button_size"
|
||||
android:layout_centerInParent="true"
|
||||
android:paddingLeft="1dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:background="@drawable/new_conversation_button_foreground"
|
||||
android:fontFamily="@font/roboto_light"
|
||||
android:textSize="40dp"
|
||||
android:textColor="#121212"
|
||||
android:text="+"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null" />
|
||||
|
||||
</RelativeLayout>
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/large_spacing"
|
||||
android:paddingStart="12dp"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false">
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/massive_spacing"
|
||||
android:layout_marginStart="@dimen/large_spacing"
|
||||
android:layout_marginStart="12dp"
|
||||
android:paddingTop="@dimen/medium_spacing"
|
||||
android:paddingBottom="@dimen/medium_spacing"
|
||||
android:orientation="vertical"
|
||||
|
@ -25,6 +25,7 @@
|
||||
<color name="received_message_background">#222325</color>
|
||||
<color name="sent_message_background">#3F4146</color>
|
||||
<color name="quote_not_found_background">#99FFFFFF</color>
|
||||
<color name="new_conversation_button_collapsed_background">#1F1F1F</color>
|
||||
<!-- Session -->
|
||||
|
||||
<!-- Loki -->
|
||||
|
@ -22,7 +22,8 @@
|
||||
<dimen name="conversation_view_status_indicator_size">14dp</dimen>
|
||||
<dimen name="border_thickness">1dp</dimen>
|
||||
<dimen name="profile_picture_border_thickness">1dp</dimen>
|
||||
<dimen name="new_conversation_button_size">56dp</dimen>
|
||||
<dimen name="new_conversation_button_collapsed_size">60dp</dimen>
|
||||
<dimen name="new_conversation_button_expanded_size">72dp</dimen>
|
||||
<dimen name="tab_bar_height">36dp</dimen>
|
||||
<dimen name="text_view_corner_radius">8dp</dimen>
|
||||
<dimen name="fake_chat_view_bubble_width">224dp</dimen>
|
||||
|
@ -799,7 +799,7 @@ public class ConversationItem extends LinearLayout
|
||||
private void setContactPhoto(@NonNull Recipient recipient) {
|
||||
if (messageRecord == null) return; // TODO: Figure out how this happens
|
||||
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)bodyBubble.getLayoutParams();
|
||||
int groupThreadMargin = (int)(getResources().getDimension(R.dimen.large_spacing) + getResources().getDimension(R.dimen.small_profile_picture_size));
|
||||
int groupThreadMargin = (int)((12 * getResources().getDisplayMetrics().density) + getResources().getDimension(R.dimen.small_profile_picture_size));
|
||||
int defaultMargin = 0;
|
||||
String threadName = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(messageRecord.getThreadId()).getName();
|
||||
boolean isRSSFeed = threadName != null && (threadName.equals("Loki News") || threadName.equals("Session Updates"));
|
||||
|
@ -9,6 +9,7 @@ import android.support.v4.content.Loader
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_create_closed_group.*
|
||||
import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView
|
||||
@ -38,6 +39,10 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), MemberC
|
||||
private val selectedMembers: Set<String>
|
||||
get() { return createClosedGroupAdapter.selectedMembers }
|
||||
|
||||
companion object {
|
||||
public val createNewPrivateChatResultCode = 100
|
||||
}
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
@ -45,12 +50,13 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), MemberC
|
||||
supportActionBar!!.title = "New Closed Group"
|
||||
recyclerView.adapter = createClosedGroupAdapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
createNewPrivateChatButton.setOnClickListener { createNewPrivateChat() }
|
||||
LoaderManager.getInstance(this).initLoader(0, null, this)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_create_closed_group, menu)
|
||||
return true
|
||||
return members.isNotEmpty()
|
||||
}
|
||||
// endregion
|
||||
|
||||
@ -69,6 +75,9 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), MemberC
|
||||
|
||||
private fun update(members: List<String>) {
|
||||
this.members = members
|
||||
mainContentContainer.visibility = if (members.isEmpty()) View.GONE else View.VISIBLE
|
||||
emptyStateContainer.visibility = if (members.isEmpty()) View.VISIBLE else View.GONE
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
// endregion
|
||||
|
||||
@ -82,6 +91,11 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), MemberC
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun createNewPrivateChat() {
|
||||
setResult(createNewPrivateChatResultCode)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onMemberClick(member: String) {
|
||||
createClosedGroupAdapter.onMemberClick(member)
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ import android.support.v7.widget.helper.ItemTouchHelper
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import network.loki.messenger.R
|
||||
@ -33,6 +35,7 @@ import org.thoughtcrime.securesms.loki.getColorWithID
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.push
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.show
|
||||
import org.thoughtcrime.securesms.loki.redesign.views.ConversationView
|
||||
import org.thoughtcrime.securesms.loki.redesign.views.NewConversationButtonSetViewDelegate
|
||||
import org.thoughtcrime.securesms.loki.redesign.views.SeedReminderViewDelegate
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@ -41,7 +44,7 @@ import org.thoughtcrime.securesms.util.GroupUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import kotlin.math.abs
|
||||
|
||||
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate {
|
||||
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
|
||||
private lateinit var glide: GlideRequests
|
||||
|
||||
private val hexEncodedPublicKey: String
|
||||
@ -87,8 +90,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
profileButton.hexEncodedPublicKey = hexEncodedPublicKey
|
||||
profileButton.update()
|
||||
profileButton.setOnClickListener { openSettings() }
|
||||
createClosedGroupButton.setOnClickListener { createClosedGroup() }
|
||||
joinPublicChatButton.setOnClickListener { joinPublicChat() }
|
||||
// Set up seed reminder view
|
||||
val isMasterDevice = (TextSecurePreferences.getMasterHexEncodedPublicKey(this) == null)
|
||||
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
|
||||
@ -125,8 +126,14 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
homeAdapter.changeCursor(null)
|
||||
}
|
||||
})
|
||||
// Set up new conversation button
|
||||
newConversationButton.setOnClickListener { createPrivateChat() }
|
||||
// Set up gradient view
|
||||
val gradientViewLayoutParams = gradientView.layoutParams as RelativeLayout.LayoutParams
|
||||
val displayMetrics = DisplayMetrics()
|
||||
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
val height = displayMetrics.heightPixels
|
||||
gradientViewLayoutParams.topMargin = (0.15 * height.toFloat()).toInt()
|
||||
// Set up new conversation button set
|
||||
newConversationButtonSet.delegate = this
|
||||
// Set up typing observer
|
||||
ApplicationContext.getInstance(this).typingStatusRepository.typingThreads.observe(this, Observer<Set<Long>> { threadIDs ->
|
||||
val adapter = recyclerView.adapter as HomeAdapter
|
||||
@ -176,6 +183,13 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
// bottomSheet.show(supportFragmentManager, bottomSheet.tag)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == CreateClosedGroupActivity.createNewPrivateChatResultCode) {
|
||||
createNewPrivateChat()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
override fun handleSeedReminderViewContinueButtonTapped() {
|
||||
@ -208,17 +222,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
show(intent)
|
||||
}
|
||||
|
||||
private fun createPrivateChat() {
|
||||
override fun createNewPrivateChat() {
|
||||
val intent = Intent(this, CreatePrivateChatActivity::class.java)
|
||||
show(intent)
|
||||
}
|
||||
|
||||
private fun createClosedGroup() {
|
||||
override fun createNewClosedGroup() {
|
||||
val intent = Intent(this, CreateClosedGroupActivity::class.java)
|
||||
show(intent)
|
||||
show(intent, true)
|
||||
}
|
||||
|
||||
private fun joinPublicChat() {
|
||||
override fun joinOpenGroup() {
|
||||
val intent = Intent(this, JoinPublicChatActivity::class.java)
|
||||
show(intent)
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.view.View
|
||||
|
||||
fun PointF.distanceTo(other: PointF): Float {
|
||||
return Math.sqrt(Math.pow(this.x.toDouble() - other.x.toDouble(), 2.toDouble()) + Math.pow(this.y.toDouble() - other.y.toDouble(), 2.toDouble())).toFloat()
|
||||
}
|
||||
|
||||
fun PointF.isLeftOf(view: View, margin: Float = 0.0f): Boolean {
|
||||
return isContainedVerticallyIn(view, margin) && x < view.hitRect.left
|
||||
}
|
||||
|
||||
fun PointF.isAbove(view: View, margin: Float = 0.0f): Boolean {
|
||||
return isContainedHorizontallyIn(view, margin) && y < view.hitRect.top
|
||||
}
|
||||
|
||||
fun PointF.isRightOf(view: View, margin: Float = 0.0f): Boolean {
|
||||
return isContainedVerticallyIn(view, margin) && x > view.hitRect.right
|
||||
}
|
||||
|
||||
fun PointF.isBelow(view: View, margin: Float = 0.0f): Boolean {
|
||||
return isContainedHorizontallyIn(view, margin) && y > view.hitRect.bottom
|
||||
}
|
||||
|
||||
fun PointF.isContainedHorizontallyIn(view: View, margin: Float = 0.0f): Boolean {
|
||||
return x >= view.hitRect.left - margin || x <= view.hitRect.right + margin
|
||||
}
|
||||
|
||||
fun PointF.isContainedVerticallyIn(view: View, margin: Float = 0.0f): Boolean {
|
||||
return y >= view.hitRect.top - margin || x <= view.hitRect.bottom + margin
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||
|
||||
import android.view.ViewGroup
|
||||
|
||||
fun ViewGroup.disableClipping() {
|
||||
clipToPadding = false
|
||||
clipChildren = false
|
||||
clipToOutline = false
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.utilities
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
|
||||
fun View.contains(point: PointF): Boolean {
|
||||
return hitRect.contains(point.x.toInt(), point.y.toInt())
|
||||
}
|
||||
|
||||
val View.hitRect: Rect
|
||||
get() {
|
||||
val rect = Rect()
|
||||
getHitRect(rect)
|
||||
return rect
|
||||
}
|
@ -0,0 +1,296 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.views
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.FloatEvaluator
|
||||
import android.animation.PointFEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.content.Context.VIBRATOR_SERVICE
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Build
|
||||
import android.os.VibrationEffect
|
||||
import android.os.VibrationEffect.DEFAULT_AMPLITUDE
|
||||
import android.os.Vibrator
|
||||
import android.support.annotation.ColorRes
|
||||
import android.support.annotation.DimenRes
|
||||
import android.support.annotation.DrawableRes
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.loki.getColorWithID
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.*
|
||||
import org.thoughtcrime.securesms.loki.toPx
|
||||
|
||||
class NewConversationButtonSetView : RelativeLayout {
|
||||
private var expandedButton: Button? = null
|
||||
private var previousAction: Int? = null
|
||||
private var isExpanded = false
|
||||
var delegate: NewConversationButtonSetViewDelegate? = null
|
||||
|
||||
// region Convenience
|
||||
private val sessionButtonExpandedPosition: PointF get() { return PointF(width.toFloat() / 2 - sessionButton.expandedSize / 2, 0.0f) }
|
||||
private val closedGroupButtonExpandedPosition: PointF get() { return PointF(width.toFloat() - closedGroupButton.expandedSize, height.toFloat() - bottomMargin - closedGroupButton.expandedSize) }
|
||||
private val openGroupButtonExpandedPosition: PointF get() { return PointF(0.0f, height.toFloat() - bottomMargin - openGroupButton.expandedSize) }
|
||||
private val buttonRestPosition: PointF get() { return PointF(width.toFloat() / 2 - mainButton.expandedSize / 2, height.toFloat() - bottomMargin - mainButton.expandedSize) }
|
||||
// endregion
|
||||
|
||||
// region Settings
|
||||
private val maxDragDistance by lazy { toPx(56, resources).toFloat() }
|
||||
private val dragMargin by lazy { toPx(16, resources).toFloat() }
|
||||
private val bottomMargin by lazy { resources.getDimension(R.dimen.new_conversation_button_bottom_offset) }
|
||||
// endregion
|
||||
|
||||
// region Components
|
||||
private val mainButton by lazy { Button(context, true, R.drawable.ic_plus) }
|
||||
private val sessionButton by lazy { Button(context, false, R.drawable.ic_message) }
|
||||
private val closedGroupButton by lazy { Button(context, false, R.drawable.ic_group) }
|
||||
private val openGroupButton by lazy { Button(context, false, R.drawable.ic_globe) }
|
||||
// endregion
|
||||
|
||||
// region Button
|
||||
class Button : RelativeLayout {
|
||||
@DrawableRes private var iconID = 0
|
||||
private var isMain = false
|
||||
|
||||
companion object {
|
||||
val animationDuration = 250.toLong()
|
||||
}
|
||||
|
||||
val expandedSize by lazy { resources.getDimension(R.dimen.new_conversation_button_expanded_size) }
|
||||
val collapsedSize by lazy { resources.getDimension(R.dimen.new_conversation_button_collapsed_size) }
|
||||
private val expandedImageViewPosition by lazy { PointF(0.0f, 0.0f) }
|
||||
private val collapsedImageViewPosition by lazy { PointF((expandedSize - collapsedSize) / 2, (expandedSize - collapsedSize) / 2) }
|
||||
|
||||
private val imageView by lazy {
|
||||
val result = ImageView(context)
|
||||
val size = collapsedSize.toInt()
|
||||
result.layoutParams = LayoutParams(size, size)
|
||||
result.setBackgroundResource(R.drawable.new_conversation_button_background)
|
||||
val background = result.background as GradientDrawable
|
||||
val colorID = if (isMain) R.color.accent else R.color.new_conversation_button_collapsed_background
|
||||
background.color = ColorStateList.valueOf(resources.getColorWithID(colorID, context.theme))
|
||||
result.scaleType = ImageView.ScaleType.CENTER
|
||||
result.setImageResource(iconID)
|
||||
result
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context) { throw IllegalAccessException("Use Button(context:iconID:) instead.") }
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { throw IllegalAccessException("Use Button(context:iconID:) instead.") }
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { throw IllegalAccessException("Use Button(context:iconID:) instead.") }
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { throw IllegalAccessException("Use Button(context:iconID:) instead.") }
|
||||
|
||||
constructor(context: Context, isMain: Boolean, @DrawableRes iconID: Int) : super(context) {
|
||||
this.iconID = iconID
|
||||
this.isMain = isMain
|
||||
disableClipping()
|
||||
val size = resources.getDimension(R.dimen.new_conversation_button_expanded_size).toInt()
|
||||
val layoutParams = LayoutParams(size, size)
|
||||
this.layoutParams = layoutParams
|
||||
addView(imageView)
|
||||
imageView.x = collapsedImageViewPosition.x
|
||||
imageView.y = collapsedImageViewPosition.y
|
||||
}
|
||||
|
||||
fun expand() {
|
||||
animateImageViewColorChange(R.color.new_conversation_button_collapsed_background, R.color.accent)
|
||||
animateImageViewSizeChange(R.dimen.new_conversation_button_collapsed_size, R.dimen.new_conversation_button_expanded_size)
|
||||
animateImageViewPositionChange(collapsedImageViewPosition, expandedImageViewPosition)
|
||||
}
|
||||
|
||||
fun collapse() {
|
||||
animateImageViewColorChange(R.color.accent, R.color.new_conversation_button_collapsed_background)
|
||||
animateImageViewSizeChange(R.dimen.new_conversation_button_expanded_size, R.dimen.new_conversation_button_collapsed_size)
|
||||
animateImageViewPositionChange(expandedImageViewPosition, collapsedImageViewPosition)
|
||||
}
|
||||
|
||||
private fun animateImageViewColorChange(@ColorRes startColorID: Int, @ColorRes endColorID: Int) {
|
||||
val drawable = imageView.background as GradientDrawable
|
||||
val startColor = resources.getColorWithID(startColorID, context.theme)
|
||||
val endColor = resources.getColorWithID(endColorID, context.theme)
|
||||
val animation = ValueAnimator.ofObject(ArgbEvaluator(), startColor, endColor)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val color = animator.animatedValue as Int
|
||||
drawable.color = ColorStateList.valueOf(color)
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
|
||||
private fun animateImageViewSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int) {
|
||||
val layoutParams = imageView.layoutParams
|
||||
val startSize = resources.getDimension(startSizeID)
|
||||
val endSize = resources.getDimension(endSizeID)
|
||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), startSize, endSize)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val size = animator.animatedValue as Float
|
||||
layoutParams.width = size.toInt()
|
||||
layoutParams.height = size.toInt()
|
||||
imageView.layoutParams = layoutParams
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
|
||||
private fun animateImageViewPositionChange(startPosition: PointF, endPosition: PointF) {
|
||||
val animation = ValueAnimator.ofObject(PointFEvaluator(), startPosition, endPosition)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val point = animator.animatedValue as PointF
|
||||
imageView.x = point.x
|
||||
imageView.y = point.y
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
|
||||
fun animatePositionChange(startPosition: PointF, endPosition: PointF) {
|
||||
val animation = ValueAnimator.ofObject(PointFEvaluator(), startPosition, endPosition)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val point = animator.animatedValue as PointF
|
||||
x = point.x
|
||||
y = point.y
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
|
||||
fun animateAlphaChange(startAlpha: Float, endAlpha: Float) {
|
||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), startAlpha, endAlpha)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
alpha = animator.animatedValue as Float
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Lifecycle
|
||||
constructor(context: Context) : super(context) { setUpViewHierarchy() }
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { setUpViewHierarchy() }
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { setUpViewHierarchy() }
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { setUpViewHierarchy() }
|
||||
|
||||
private fun setUpViewHierarchy() {
|
||||
// Set up session button
|
||||
addView(sessionButton)
|
||||
sessionButton.alpha = 0.0f
|
||||
val sessionButtonLayoutParams = sessionButton.layoutParams as LayoutParams
|
||||
sessionButtonLayoutParams.addRule(CENTER_IN_PARENT, TRUE)
|
||||
sessionButtonLayoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE)
|
||||
sessionButtonLayoutParams.bottomMargin = bottomMargin.toInt()
|
||||
// Set up closed group button
|
||||
addView(closedGroupButton)
|
||||
closedGroupButton.alpha = 0.0f
|
||||
val closedGroupButtonLayoutParams = closedGroupButton.layoutParams as LayoutParams
|
||||
closedGroupButtonLayoutParams.addRule(CENTER_IN_PARENT, TRUE)
|
||||
closedGroupButtonLayoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE)
|
||||
closedGroupButtonLayoutParams.bottomMargin = bottomMargin.toInt()
|
||||
// Set up open group button
|
||||
addView(openGroupButton)
|
||||
openGroupButton.alpha = 0.0f
|
||||
val openGroupButtonLayoutParams = openGroupButton.layoutParams as LayoutParams
|
||||
openGroupButtonLayoutParams.addRule(CENTER_IN_PARENT, TRUE)
|
||||
openGroupButtonLayoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE)
|
||||
openGroupButtonLayoutParams.bottomMargin = bottomMargin.toInt()
|
||||
// Set up main button
|
||||
addView(mainButton)
|
||||
val mainButtonLayoutParams = mainButton.layoutParams as LayoutParams
|
||||
mainButtonLayoutParams.addRule(CENTER_IN_PARENT, TRUE)
|
||||
mainButtonLayoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE)
|
||||
mainButtonLayoutParams.bottomMargin = bottomMargin.toInt()
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
val touch = PointF(event.x, event.y)
|
||||
val expandedButton = expandedButton
|
||||
val allButtons = listOf( mainButton, sessionButton, closedGroupButton, openGroupButton )
|
||||
val buttonsExcludingMainButton = listOf( sessionButton, closedGroupButton, openGroupButton )
|
||||
if (allButtons.none { it.contains(touch) }) { return false }
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val vibrator = context.getSystemService(VIBRATOR_SERVICE) as Vibrator
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(50, DEFAULT_AMPLITUDE))
|
||||
} else {
|
||||
vibrator.vibrate(50)
|
||||
}
|
||||
if (!isExpanded && mainButton.contains(touch)) {
|
||||
expand()
|
||||
} else if (buttonsExcludingMainButton.none { it.contains(touch) }) {
|
||||
collapse()
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
mainButton.x = touch.x - mainButton.expandedSize / 2
|
||||
mainButton.y = touch.y - mainButton.expandedSize / 2
|
||||
mainButton.alpha = 1 - (PointF(mainButton.x, mainButton.y).distanceTo(buttonRestPosition) / maxDragDistance)
|
||||
val buttonToExpand = buttonsExcludingMainButton.firstOrNull { button ->
|
||||
var hasUserDraggedBeyondButton = false
|
||||
if (button == openGroupButton && touch.isLeftOf(openGroupButton, dragMargin)) { hasUserDraggedBeyondButton = true }
|
||||
if (button == sessionButton && touch.isAbove(sessionButton, dragMargin)) { hasUserDraggedBeyondButton = true }
|
||||
if (button == closedGroupButton && touch.isRightOf(closedGroupButton, dragMargin)) { hasUserDraggedBeyondButton = true }
|
||||
button.contains(touch) || hasUserDraggedBeyondButton
|
||||
}
|
||||
if (buttonToExpand != null) {
|
||||
if (buttonToExpand == expandedButton) { return true }
|
||||
expandedButton?.collapse()
|
||||
buttonToExpand.expand()
|
||||
this.expandedButton = buttonToExpand
|
||||
} else {
|
||||
expandedButton?.collapse()
|
||||
this.expandedButton = null
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
if (previousAction == MotionEvent.ACTION_MOVE || isExpanded) {
|
||||
expandedButton?.collapse()
|
||||
this.expandedButton = null
|
||||
collapse()
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
if (sessionButton.contains(touch) || touch.isAbove(sessionButton, dragMargin)) { delegate?.createNewPrivateChat() }
|
||||
else if (closedGroupButton.contains(touch) || touch.isRightOf(closedGroupButton, dragMargin)) { delegate?.createNewClosedGroup() }
|
||||
else if (openGroupButton.contains(touch) || touch.isLeftOf(openGroupButton, dragMargin)) { delegate?.joinOpenGroup() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
previousAction = event.action
|
||||
return true
|
||||
}
|
||||
|
||||
private fun expand() {
|
||||
val buttonsExcludingMainButton = listOf( sessionButton, closedGroupButton, openGroupButton )
|
||||
sessionButton.animatePositionChange(buttonRestPosition, sessionButtonExpandedPosition)
|
||||
closedGroupButton.animatePositionChange(buttonRestPosition, closedGroupButtonExpandedPosition)
|
||||
openGroupButton.animatePositionChange(buttonRestPosition, openGroupButtonExpandedPosition)
|
||||
buttonsExcludingMainButton.forEach { it.animateAlphaChange(0.0f, 1.0f) }
|
||||
postDelayed({ isExpanded = true }, Button.animationDuration)
|
||||
}
|
||||
|
||||
private fun collapse() {
|
||||
val allButtons = listOf( mainButton, sessionButton, closedGroupButton, openGroupButton )
|
||||
allButtons.forEach {
|
||||
val currentPosition = PointF(it.x, it.y)
|
||||
it.animatePositionChange(currentPosition, buttonRestPosition)
|
||||
val endAlpha = if (it == mainButton) 1.0f else 0.0f
|
||||
it.animateAlphaChange(it.alpha, endAlpha)
|
||||
}
|
||||
postDelayed({ isExpanded = false }, Button.animationDuration)
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
// region Delegate
|
||||
interface NewConversationButtonSetViewDelegate {
|
||||
|
||||
fun joinOpenGroup()
|
||||
fun createNewPrivateChat()
|
||||
fun createNewClosedGroup()
|
||||
}
|
||||
// endregion
|
Loading…
x
Reference in New Issue
Block a user