Merge pull request #138 from loki-project/ui

Various UI Improvements
pull/145/head
gmbnt 4 years ago committed by GitHub
commit 11237d2009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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>

@ -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>

@ -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>

@ -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="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:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
<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: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:gravity="center_horizontal"
android:orientation="vertical"
android:layout_centerInParent="true">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<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" />
<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" />
</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…
Cancel
Save