Show identicons in user list and settings (fixes #27).
This commit is contained in:
parent
1c3bc5618e
commit
cdece0ef42
13 changed files with 177 additions and 49 deletions
20
app/src/main/res/layout/activity_identicon.xml
Normal file
20
app/src/main/res/layout/activity_identicon.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="25dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/identicon"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginBottom="25dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,29 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/listPreferredItemHeight"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
|
||||
android:orientation="vertical" >
|
||||
android:paddingRight="?android:attr/listPreferredItemPaddingRight" >
|
||||
|
||||
<TextView android:id="@android:id/text1"
|
||||
<ImageView
|
||||
android:id="@+id/identicon"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end" />
|
||||
android:ellipsize="end"
|
||||
android:layout_toRightOf="@id/identicon"
|
||||
android:layout_marginLeft="10dp" />
|
||||
|
||||
<TextView android:id="@android:id/text2"
|
||||
<TextView
|
||||
android:id="@android:id/text2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end" />
|
||||
android:ellipsize="end"
|
||||
android:layout_below="@android:id/text1"
|
||||
android:layout_alignLeft="@android:id/text1" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -78,6 +78,9 @@
|
|||
<!-- Preference title -->
|
||||
<string name="user_status">Status</string>
|
||||
|
||||
<!-- Preference title -->
|
||||
<string name="my_address">My Address</string>
|
||||
|
||||
<!-- Preference title -->
|
||||
<string name="scan_interval_seconds">Scan Interval (seconds)</string>
|
||||
|
||||
|
@ -98,6 +101,11 @@
|
|||
<!-- Preference title -->
|
||||
<string name="version">Version</string>
|
||||
|
||||
<!-- IdenticonFragment -->
|
||||
|
||||
<!-- Device address label and value -->
|
||||
<string name="address_colon">Address: %1$s</string>
|
||||
|
||||
|
||||
<!-- ChatService -->
|
||||
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
android:title="@string/user_status"
|
||||
android:key="user_status" />
|
||||
|
||||
<Preference
|
||||
android:title="@string/my_address"
|
||||
android:key="my_address" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:title="@string/notification_sounds"
|
||||
android:key="notification_sounds"
|
||||
|
|
|
@ -10,7 +10,8 @@ import android.widget._
|
|||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.protocol.ChatService
|
||||
import com.nutomic.ensichat.protocol.body.RequestAddContact
|
||||
import com.nutomic.ensichat.util.{Database, UsersAdapter}
|
||||
import com.nutomic.ensichat.util.Database
|
||||
import com.nutomic.ensichat.views.UsersAdapter
|
||||
|
||||
/**
|
||||
* Lists all nearby, connected devices and allows adding them to be added as contacts.
|
||||
|
|
|
@ -13,7 +13,8 @@ import com.nutomic.ensichat.R
|
|||
import com.nutomic.ensichat.activities.EnsichatActivity
|
||||
import com.nutomic.ensichat.protocol.body.Text
|
||||
import com.nutomic.ensichat.protocol.{Message, Address, ChatService}
|
||||
import com.nutomic.ensichat.util.{Database, MessagesAdapter}
|
||||
import com.nutomic.ensichat.util.Database
|
||||
import com.nutomic.ensichat.views.MessagesAdapter
|
||||
|
||||
/**
|
||||
* Represents a single chat with another specific device.
|
||||
|
|
|
@ -12,7 +12,8 @@ import android.widget.ListView
|
|||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.activities.{AddContactsActivity, EnsichatActivity, MainActivity, SettingsActivity}
|
||||
import com.nutomic.ensichat.protocol.ChatService
|
||||
import com.nutomic.ensichat.util.{Database, UsersAdapter}
|
||||
import com.nutomic.ensichat.util.Database
|
||||
import com.nutomic.ensichat.views.UsersAdapter
|
||||
import scala.collection.JavaConversions._
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package com.nutomic.ensichat.fragments
|
||||
|
||||
import android.app.{AlertDialog, Dialog, DialogFragment}
|
||||
import android.os.Bundle
|
||||
import android.view.{LayoutInflater, View, ViewGroup}
|
||||
import android.widget.{ImageView, TextView}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.protocol.Address
|
||||
import com.nutomic.ensichat.util.IdenticonGenerator
|
||||
|
||||
object IdenticonFragment {
|
||||
private val ExtraAddress = "address"
|
||||
private val ExtraUserName = "user_name"
|
||||
|
||||
def getInstance(address: Address, userName: String): IdenticonFragment = {
|
||||
val bundle = new Bundle()
|
||||
bundle.putString(IdenticonFragment.ExtraAddress, address.toString)
|
||||
bundle.putString(IdenticonFragment.ExtraUserName, userName)
|
||||
|
||||
val fragment = new IdenticonFragment()
|
||||
fragment.setArguments(bundle)
|
||||
fragment
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays identicon, username and address for a user.
|
||||
*
|
||||
* Use [[IdenticonFragment#getInstance]] to invoke.
|
||||
*/
|
||||
class IdenticonFragment extends DialogFragment {
|
||||
|
||||
private lazy val address = new Address(getArguments.getString(IdenticonFragment.ExtraAddress))
|
||||
private lazy val userName = getArguments.getString(IdenticonFragment.ExtraUserName)
|
||||
|
||||
|
||||
override def onCreateView(inflater: LayoutInflater, container: ViewGroup,
|
||||
savedInstanceState: Bundle): View = {
|
||||
getDialog.setTitle(userName)
|
||||
val view = inflater.inflate(R.layout.activity_identicon, container)
|
||||
view.findViewById(R.id.identicon)
|
||||
.asInstanceOf[ImageView]
|
||||
.setImageBitmap(IdenticonGenerator.generate(address, (150, 150), getActivity))
|
||||
view.findViewById(R.id.address)
|
||||
.asInstanceOf[TextView]
|
||||
.setText(getString(R.string.address_colon, address.toString))
|
||||
view
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package com.nutomic.ensichat.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.{Build, Bundle}
|
||||
import android.preference.Preference.OnPreferenceChangeListener
|
||||
import android.preference.Preference.{OnPreferenceClickListener, OnPreferenceChangeListener}
|
||||
import android.preference.{Preference, PreferenceFragment, PreferenceManager}
|
||||
import com.nutomic.ensichat.protocol.Crypto
|
||||
import com.nutomic.ensichat.{BuildConfig, R}
|
||||
import com.nutomic.ensichat.activities.EnsichatActivity
|
||||
import com.nutomic.ensichat.fragments.SettingsFragment._
|
||||
|
@ -13,6 +15,7 @@ object SettingsFragment {
|
|||
|
||||
val KeyUserName = "user_name"
|
||||
val KeyUserStatus = "user_status"
|
||||
val KeyMyAddress = "my_address"
|
||||
val KeyScanInterval = "scan_interval_seconds"
|
||||
val MaxConnections = "max_connections"
|
||||
val Version = "version"
|
||||
|
@ -22,12 +25,14 @@ object SettingsFragment {
|
|||
/**
|
||||
* Settings screen.
|
||||
*/
|
||||
class SettingsFragment extends PreferenceFragment with OnPreferenceChangeListener {
|
||||
class SettingsFragment extends PreferenceFragment with OnPreferenceChangeListener
|
||||
with OnPreferenceClickListener {
|
||||
|
||||
private lazy val database = new Database(getActivity)
|
||||
|
||||
private lazy val name = findPreference(KeyUserName)
|
||||
private lazy val status = findPreference(KeyUserStatus)
|
||||
private lazy val myAddress = findPreference(KeyMyAddress)
|
||||
private lazy val scanInterval = findPreference(KeyScanInterval)
|
||||
private lazy val maxConnections = findPreference(MaxConnections)
|
||||
private lazy val version = findPreference(Version)
|
||||
|
@ -43,6 +48,7 @@ class SettingsFragment extends PreferenceFragment with OnPreferenceChangeListene
|
|||
name.setOnPreferenceChangeListener(this)
|
||||
status.setSummary(prefs.getString(KeyUserStatus, ""))
|
||||
status.setOnPreferenceChangeListener(this)
|
||||
myAddress.setOnPreferenceClickListener(this)
|
||||
|
||||
scanInterval.setOnPreferenceChangeListener(this)
|
||||
scanInterval.setSummary(prefs.getString(
|
||||
|
@ -73,4 +79,16 @@ class SettingsFragment extends PreferenceFragment with OnPreferenceChangeListene
|
|||
true
|
||||
}
|
||||
|
||||
override def onPreferenceClick (preference: Preference): Boolean = {
|
||||
preference.getKey match {
|
||||
case KeyMyAddress =>
|
||||
val fragment = IdenticonFragment.getInstance(new Crypto(getActivity).localAddress,
|
||||
prefs.getString(KeyUserName, ""))
|
||||
fragment.show(getFragmentManager, "dialog")
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ object IdenticonGenerator {
|
|||
/**
|
||||
* Generates an identicon for the key.
|
||||
*
|
||||
* The identicon size is fixed to [[Height]]x[[Width]].
|
||||
* The identicon size is fixed to [[Width]]x[[Height]].
|
||||
*
|
||||
* @param size The size of the bitmap returned.
|
||||
* @param size The size of the bitmap returned in pixels (widthxheight).
|
||||
*/
|
||||
def generate(address: Address, size: (Int, Int), context: Context): Bitmap = {
|
||||
val hash = address.bytes
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package com.nutomic.ensichat.util
|
||||
|
||||
import android.content.Context
|
||||
import android.view.{LayoutInflater, View, ViewGroup}
|
||||
import android.widget.{ArrayAdapter, TextView}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.bluetooth.Device
|
||||
import com.nutomic.ensichat.protocol.User
|
||||
|
||||
/**
|
||||
* Displays [[Device]]s in ListView.
|
||||
*/
|
||||
class UsersAdapter(context: Context) extends
|
||||
ArrayAdapter[User](context, 0) {
|
||||
|
||||
override def getView(position: Int, convertView: View, parent: ViewGroup): View = {
|
||||
val view =
|
||||
if (convertView == null) {
|
||||
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
|
||||
.asInstanceOf[LayoutInflater]
|
||||
.inflate(R.layout.item_user, parent, false)
|
||||
} else
|
||||
convertView
|
||||
val title = view.findViewById(android.R.id.text1).asInstanceOf[TextView]
|
||||
val summary = view.findViewById(android.R.id.text2).asInstanceOf[TextView]
|
||||
val item = getItem(position)
|
||||
title.setText(item.name)
|
||||
summary.setText(item.status)
|
||||
view
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package com.nutomic.ensichat.util
|
||||
package com.nutomic.ensichat.views
|
||||
|
||||
import android.content.Context
|
||||
import android.view.{Gravity, View, ViewGroup}
|
||||
import android.widget.{ArrayAdapter, RelativeLayout, TextView}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.protocol.{Message, Address}
|
||||
import com.nutomic.ensichat.protocol.body.Text
|
||||
import com.nutomic.ensichat.protocol.{Address, Message}
|
||||
|
||||
/**
|
||||
* Displays [[Message]]s in ListView.
|
|
@ -0,0 +1,46 @@
|
|||
package com.nutomic.ensichat.views
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.{LayoutInflater, View, ViewGroup}
|
||||
import android.widget.{ArrayAdapter, ImageView, TextView}
|
||||
import com.nutomic.ensichat.R
|
||||
import com.nutomic.ensichat.fragments.IdenticonFragment
|
||||
import com.nutomic.ensichat.protocol.{Crypto, User}
|
||||
import com.nutomic.ensichat.util.IdenticonGenerator
|
||||
|
||||
/**
|
||||
* Displays [[User]]s in ListView.
|
||||
*/
|
||||
class UsersAdapter(activity: Activity) extends ArrayAdapter[User](activity, 0) with OnClickListener {
|
||||
|
||||
override def getView(position: Int, convertView: View, parent: ViewGroup): View = {
|
||||
val view =
|
||||
if (convertView == null) {
|
||||
activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
|
||||
.asInstanceOf[LayoutInflater]
|
||||
.inflate(R.layout.item_user, parent, false)
|
||||
} else
|
||||
convertView
|
||||
|
||||
val identicon = view.findViewById(R.id.identicon).asInstanceOf[ImageView]
|
||||
val title = view.findViewById(android.R.id.text1).asInstanceOf[TextView]
|
||||
val summary = view.findViewById(android.R.id.text2).asInstanceOf[TextView]
|
||||
|
||||
val user = getItem(position)
|
||||
identicon.setImageBitmap(IdenticonGenerator.generate(user.address, (50, 50), activity))
|
||||
identicon.setOnClickListener(this)
|
||||
identicon.setTag(user)
|
||||
title.setText(user.name)
|
||||
summary.setText(user.status)
|
||||
view
|
||||
}
|
||||
|
||||
override def onClick (v: View): Unit = {
|
||||
val user = v.getTag.asInstanceOf[User]
|
||||
val fragment = IdenticonFragment.getInstance(user.address, user.name)
|
||||
fragment.show(activity.getFragmentManager, "dialog")
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue