suggestion list on first screen

This commit is contained in:
Dmitriy Ruban 2019-12-26 19:17:06 +02:00
parent 0e4a5f3cd4
commit c5cfb47950
4 changed files with 149 additions and 10 deletions

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/card_bg_color">
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/list_item_height"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/list_item_icon_size_big"
android:layout_height="@dimen/list_item_icon_size_big"
android:layout_marginStart="@dimen/list_item_icon_margin_left"
android:layout_marginLeft="@dimen/list_item_icon_margin_left"
android:layout_marginEnd="@dimen/list_item_icon_margin_right"
android:layout_marginRight="@dimen/list_item_icon_margin_right"
tools:src="@drawable/img_user_picture" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/list_item_title_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="Share to Share Location" />
<net.osmand.telegram.ui.views.TextViewEx
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?attr/android:textColorSecondary"
android:textSize="@dimen/list_item_description_text_size"
app:typeface="@string/font_roboto_regular"
tools:text="for 1 hour" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -115,7 +115,7 @@ class TelegramSettings(private val app: TelegramApplication) {
private var hiddenOnMapChats: Set<Long> = emptySet() private var hiddenOnMapChats: Set<Long> = emptySet()
private var shareDevices: Set<DeviceBot> = emptySet() private var shareDevices: Set<DeviceBot> = emptySet()
private var liveTracksInfo = emptyList<LiveTrackInfo>() private var liveTracksInfo = emptyList<LiveTrackInfo>()
private var lastChatsInfo = ConcurrentHashMap<Long, LastChatInfo>() var lastChatsInfo = ConcurrentHashMap<Long, LastChatInfo>()
var sharingStatusChanges = ConcurrentLinkedQueue<SharingStatus>() var sharingStatusChanges = ConcurrentLinkedQueue<SharingStatus>()

View file

@ -12,6 +12,8 @@ import android.support.v4.app.DialogFragment
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter import android.support.v4.app.FragmentPagerAdapter
import android.support.v4.view.PagerAdapter
import android.support.v4.view.ViewPager
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.ListPopupWindow import android.support.v7.widget.ListPopupWindow
@ -22,7 +24,6 @@ import net.osmand.PlatformUtil
import net.osmand.telegram.R import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.OsmandAidlHelper import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.* import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.ui.LoginDialogFragment.LoginDialogType import net.osmand.telegram.ui.LoginDialogFragment.LoginDialogType
import net.osmand.telegram.ui.MyLocationTabFragment.ActionButtonsListener import net.osmand.telegram.ui.MyLocationTabFragment.ActionButtonsListener
@ -43,7 +44,7 @@ private const val MY_LOCATION_TAB_POS = 0
private const val LIVE_NOW_TAB_POS = 1 private const val LIVE_NOW_TAB_POS = 1
private const val TIMELINE_TAB_POS = 2 private const val TIMELINE_TAB_POS = 2
class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListener, TelegramIncomingMessagesListener { class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListener, TelegramIncomingMessagesListener, DataSetListener {
private val log = PlatformUtil.getLog(MainActivity::class.java) private val log = PlatformUtil.getLog(MainActivity::class.java)
@ -66,6 +67,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
private lateinit var buttonsBar: LinearLayout private lateinit var buttonsBar: LinearLayout
private lateinit var bottomNav: BottomNavigationView private lateinit var bottomNav: BottomNavigationView
private lateinit var coordinatorLayout: CoordinatorLayout private lateinit var coordinatorLayout: CoordinatorLayout
private lateinit var viewPager: ViewPager
private var snackbarShown = false private var snackbarShown = false
@ -81,7 +83,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
paused = false paused = false
val viewPager = findViewById<LockableViewPager>(R.id.view_pager).apply { viewPager = findViewById<LockableViewPager>(R.id.view_pager).apply {
swipeLocked = true swipeLocked = true
offscreenPageLimit = 3 offscreenPageLimit = 3
adapter = ViewPagerAdapter(supportFragmentManager) adapter = ViewPagerAdapter(supportFragmentManager)
@ -484,6 +486,10 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
} }
} }
override fun onDataSetChanged() {
viewPager.adapter?.notifyDataSetChanged()
}
private fun showOsmandMissingDialog() { private fun showOsmandMissingDialog() {
OsmandMissingDialogFragment().show(supportFragmentManager, null) OsmandMissingDialogFragment().show(supportFragmentManager, null)
} }
@ -510,5 +516,13 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
override fun getItem(position: Int) = fragments[position] override fun getItem(position: Int) = fragments[position]
override fun getCount() = fragments.size override fun getCount() = fragments.size
override fun getItemPosition(`object`: Any): Int {
return PagerAdapter.POSITION_NONE
}
} }
} }
interface DataSetListener {
fun onDataSetChanged()
}

View file

@ -20,10 +20,8 @@ import android.text.style.StyleSpan
import android.view.* import android.view.*
import android.view.animation.LinearInterpolator import android.view.animation.LinearInterpolator
import android.widget.* import android.widget.*
import net.osmand.telegram.ADDITIONAL_ACTIVE_TIME_VALUES_SEC import net.osmand.PlatformUtil
import net.osmand.telegram.R import net.osmand.telegram.*
import net.osmand.telegram.SHARE_TYPE_MAP
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.LocationMessages import net.osmand.telegram.helpers.LocationMessages
import net.osmand.telegram.helpers.TelegramHelper import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.TelegramListener import net.osmand.telegram.helpers.TelegramHelper.TelegramListener
@ -31,9 +29,11 @@ import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter import net.osmand.telegram.utils.OsmandFormatter
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import java.util.concurrent.ConcurrentHashMap
private const val SELECTED_CHATS_KEY = "selected_chats" private const val SELECTED_CHATS_KEY = "selected_chats"
private const val SELECTED_CHATS_USERS = "selected_users" private const val SELECTED_CHATS_USERS = "selected_users"
private const val LAST_SHARE_CHAT = 2
private const val SHARE_LOCATION_CHAT = 1 private const val SHARE_LOCATION_CHAT = 1
private const val DEFAULT_CHAT = 0 private const val DEFAULT_CHAT = 0
@ -41,6 +41,8 @@ private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec
class MyLocationTabFragment : Fragment(), TelegramListener { class MyLocationTabFragment : Fragment(), TelegramListener {
private val log = PlatformUtil.getLog(MyLocationTabFragment::class.java)
private var textMarginSmall: Int = 0 private var textMarginSmall: Int = 0
private var textMarginBig: Int = 0 private var textMarginBig: Int = 0
private var searchBoxHeight: Int = 0 private var searchBoxHeight: Int = 0
@ -85,6 +87,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
private var updateEnable: Boolean = false private var updateEnable: Boolean = false
private lateinit var lastChatsInfo: ConcurrentHashMap<Long, TelegramSettings.LastChatInfo>
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -234,6 +238,8 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
} }
} }
lastChatsInfo = settings.lastChatsInfo
return mainView return mainView
} }
@ -517,10 +523,25 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
if (sharingMode && settings.hasAnyChatToShareLocation()) { if (sharingMode && settings.hasAnyChatToShareLocation()) {
adapter.items = sortAdapterItems(items) adapter.items = sortAdapterItems(items)
} else { } else {
items.addAll(0, getLastShareItems(items))
adapter.items = items adapter.items = items
} }
} }
private fun getLastShareItems(items: MutableList<TdApi.Object>): MutableList<TdApi.Object> {
val lastItems: MutableList<TdApi.Object> = mutableListOf()
items.forEach {
val id = when (it) {
is TdApi.Chat -> it.id
else -> -1
}
if (lastChatsInfo.containsKey(id)) {
lastItems.add(LastChat(it as TdApi.Chat, lastChatsInfo[id]!!.livePeriod))
}
}
return lastItems
}
private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<TdApi.Object> { private fun sortAdapterItems(list: MutableList<TdApi.Object>): MutableList<TdApi.Object> {
list.sortWith(Comparator<TdApi.Object> { o1, o2 -> list.sortWith(Comparator<TdApi.Object> { o1, o2 ->
val title1 = when (o1) { val title1 = when (o1) {
@ -553,7 +574,9 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
is TdApi.User -> item.id.toLong() is TdApi.User -> item.id.toLong()
else -> -1 else -> -1
} }
return if (settings.isSharingLocationToChat(id) && sharingMode) { return if (item is LastChat) {
LAST_SHARE_CHAT
} else if (settings.isSharingLocationToChat(id) && sharingMode) {
SHARE_LOCATION_CHAT SHARE_LOCATION_CHAT
} else { } else {
DEFAULT_CHAT DEFAULT_CHAT
@ -572,6 +595,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
.inflate(R.layout.user_list_item, parent, false) .inflate(R.layout.user_list_item, parent, false)
ChatViewHolder(view) ChatViewHolder(view)
} }
LAST_SHARE_CHAT -> {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.last_share_list_item, parent, false)
LastChatViewHolder(view)
}
else -> throw RuntimeException("Unsupported view type: $viewType") else -> throw RuntimeException("Unsupported view type: $viewType")
} }
} }
@ -593,6 +621,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val shareInfo = if (isChat) settings.getChatsShareInfo()[itemId] else null val shareInfo = if (isChat) settings.getChatsShareInfo()[itemId] else null
val photoPath = when (item) { val photoPath = when (item) {
is LastChat -> item.chat.photo?.small?.local?.path
is TdApi.Chat -> item.photo?.small?.local?.path is TdApi.Chat -> item.photo?.small?.local?.path
is TdApi.User -> item.profilePhoto?.small?.local?.path is TdApi.User -> item.profilePhoto?.small?.local?.path
else -> null else -> null
@ -602,6 +631,13 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val currentUserId = telegramHelper.getCurrentUserId() val currentUserId = telegramHelper.getCurrentUserId()
val title = when (item) { val title = when (item) {
is LastChat -> {
if (telegramHelper.isPrivateChat(item.chat) && (item.chat.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getString(R.string.saved_messages)
} else {
item.chat.title
}
}
is TdApi.Chat -> { is TdApi.Chat -> {
if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) { if (telegramHelper.isPrivateChat(item) && (item.type as TdApi.ChatTypePrivate).userId == currentUserId) {
getString(R.string.saved_messages) getString(R.string.saved_messages)
@ -669,6 +705,11 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
settings.shareLocationToChat(itemId, false) settings.shareLocationToChat(itemId, false)
if (shareInfo != null) { if (shareInfo != null) {
telegramHelper.stopSendingLiveLocationToChat(shareInfo) telegramHelper.stopSendingLiveLocationToChat(shareInfo)
app.settings.lastChatsInfo[shareInfo.chatId] = TelegramSettings.LastChatInfo().apply {
chatId = shareInfo.chatId
livePeriod = shareInfo.livePeriod
}
log.info("Save chat to last: ${shareInfo.chatId}")
} }
removeItem(item) removeItem(item)
} }
@ -743,6 +784,24 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
text = description text = description
} }
} }
} else if (holder is LastChatViewHolder) {
val sharingTime = SpannableStringBuilder("${getString(R.string.sharing_time)}: ")
val formattedTime = OsmandFormatter.getFormattedDuration(app, (item as LastChat).time, false)
val start = sharingTime.length
sharingTime.append(formattedTime)
sharingTime.setSpan(StyleSpan(Typeface.BOLD), start, sharingTime.length, 0)
sharingTime.setSpan(ForegroundColorSpan(ContextCompat.getColor(app, R.color.ctrl_active_light)), start, sharingTime.length, 0)
holder.time?.text = sharingTime
holder.container?.setOnClickListener {
if (!AndroidUtils.isLocationPermissionAvailable(view!!.context)) {
AndroidUtils.requestLocationPermission(activity!!)
} else {
settings.shareLocationToChat((item as LastChat).chat.id, true, item.time)
app.shareLocationHelper.startSharingLocation()
(activity as DataSetListener).onDataSetChanged()
}
}
} }
} }
@ -778,9 +837,16 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
val sharingExpiresLine: TextView? = view.findViewById(R.id.expires_line) val sharingExpiresLine: TextView? = view.findViewById(R.id.expires_line)
val gpsPointsLine: TextView? = view.findViewById(R.id.gps_points_line) val gpsPointsLine: TextView? = view.findViewById(R.id.gps_points_line)
} }
inner class LastChatViewHolder(val view: View) : BaseViewHolder(view) {
val container: LinearLayout? = view.findViewById(R.id.container)
val time: TextView? = view.findViewById(R.id.time)
}
} }
interface ActionButtonsListener { interface ActionButtonsListener {
fun switchButtonsVisibility(visible: Boolean) fun switchButtonsVisibility(visible: Boolean)
} }
} }
class LastChat internal constructor(val chat: TdApi.Chat, val time: Long) : TdApi.Chat()