Explorar el Código

feat: 搜索交互,获取位置

DoggyZhang hace 3 meses
padre
commit
abb19087ea

+ 2 - 2
app/src/main/AndroidManifest.xml

@@ -28,8 +28,8 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <!--      后续需要再打开-->
-    <!--    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />-->
-    <!--    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
     <queries>
         <package android:name="com.google.android.gms" />

+ 5 - 0
app/src/main/java/com/adealink/weparty/App.kt

@@ -22,6 +22,8 @@ import com.adealink.frame.googleservice.createGoogleService
 import com.adealink.frame.image.imageService
 import com.adealink.frame.initStorageService
 import com.adealink.frame.locale.language.createLanguageManager
+import com.adealink.frame.locale.location.ILocationManager
+import com.adealink.frame.locale.location.createLocationManager
 import com.adealink.frame.log.Log
 import com.adealink.frame.log.XLogHelper
 import com.adealink.frame.log.manager.ILogService
@@ -70,6 +72,7 @@ import com.adealink.weparty.hardware.HardwareManager
 import com.adealink.weparty.hardware.IHardwareManager
 import com.adealink.weparty.image.ImageConfig
 import com.adealink.weparty.locale.LanguageConfig
+import com.adealink.weparty.location.LocationConfig
 import com.adealink.weparty.log.LogConfig
 import com.adealink.weparty.media.IMediaManager
 import com.adealink.weparty.media.MediaConfig
@@ -129,6 +132,8 @@ class App : SplitCompatApplication(), ActivityLifecycleCallbacksExt {
 //    val imService by lazy { IMService.create(IMConfig()) }
     val hardwareManager: IHardwareManager by lazy { HardwareManager() }
 
+    val locationManager: ILocationManager by lazy { createLocationManager(LocationConfig()) }
+
     var appStartTime = 0L
     override fun attachBaseContext(base: Context?) {
         logTime(TAG_TIME_APP_START, "app attachBaseContext start")

+ 12 - 6
app/src/main/java/com/adealink/weparty/location/LocationConfig.kt

@@ -1,9 +1,11 @@
 package com.adealink.weparty.location
 
+import android.annotation.SuppressLint
 import androidx.fragment.app.FragmentActivity
 import com.adealink.frame.data.PermissionRlt
 import com.adealink.frame.locale.location.config.ILocationConfig
 import com.adealink.weparty.location.datasource.local.LocationLocalService
+import com.adealink.weparty.permission.PermissionUtils
 
 class LocationConfig : ILocationConfig {
 
@@ -15,19 +17,23 @@ class LocationConfig : ILocationConfig {
         activity: FragmentActivity,
         permission: String
     ): Boolean {
-        TODO("Not yet implemented")
+        return PermissionUtils.hasPermissions(activity, permission)
     }
 
+    @SuppressLint("CheckResult")
     override fun requestPermissions(
         activity: FragmentActivity,
         vararg permissions: String,
         callback: (PermissionRlt) -> Unit
     ) {
-        TODO("Not yet implemented")
-//        PermissionUtils.getRxPermissions(activity)
-//            .request(*permissions).subscribe { granted ->
-//                callback(granted)
-//            }
+        PermissionUtils.getRxPermissions(activity)
+            .request(*permissions).subscribe { granted ->
+                if (granted) {
+                    callback(PermissionRlt.Granted)
+                } else {
+                    callback(PermissionRlt.Denied)
+                }
+            }
     }
 
 }

+ 0 - 2
app/src/main/java/com/adealink/weparty/location/viewmodel/LocationViewModel.kt

@@ -17,9 +17,7 @@ import com.adealink.weparty.location.constant.TAG_LOCATION_REPORT
 import com.adealink.weparty.location.data.LocationInfo
 import com.adealink.weparty.location.data.ReportLocationReq
 import com.adealink.weparty.location.data.UserCountryInfo
-import com.adealink.weparty.location.datasource.local.LocationLocalService
 import com.adealink.weparty.location.datasource.remote.LocationHttpService
-import com.adealink.weparty.module.profile.ProfileModule
 import kotlinx.coroutines.launch
 
 class LocationViewModel : BaseViewModel(), ILocationViewModel {

+ 26 - 0
app/src/main/java/com/adealink/weparty/ui/MainStartUpFragment.kt

@@ -1,14 +1,18 @@
 package com.adealink.weparty.ui
 
+import android.location.Location
 import android.os.Bundle
 import android.os.SystemClock
 import androidx.core.app.NotificationManagerCompat
 import androidx.lifecycle.lifecycleScope
 import com.adealink.frame.aab.AAB
+import com.adealink.frame.base.IError
 import com.adealink.frame.coroutine.dispatcher.Dispatcher
+import com.adealink.frame.locale.location.OnLocationListener
 import com.adealink.frame.log.Log
 import com.adealink.frame.push.manager.pushService
 import com.adealink.frame.statistics.BaseStatEvent
+import com.adealink.frame.util.runOnUiThread
 import com.adealink.frame.util.safeToLong
 import com.adealink.weparty.App
 import com.adealink.weparty.BuildConfig
@@ -128,6 +132,28 @@ class MainStartUpFragment : BaseFragment() {
 //        walletViewModel?.getUserChargeNotify()
         globalConfigManager.getAllGlobalConfig(true)
 //        GameModule.initRocket()
+
+
+        // TODO: 测试经纬度
+        runOnUiThread {
+            activity?.let {
+                App.instance.locationManager.init(it)
+            }
+            App.instance.locationManager.getLocation(object : OnLocationListener {
+                override fun onFailed(error: IError) {
+                    Log.d("zhangfei", "getLocation fail, ${error.serverCode}, ${error.msg}")
+                }
+
+                override fun onSuccess(location: Location) {
+                    Log.d(
+                        "zhangfei",
+                        "getLocation success, longitude: ${location.longitude}, latitude: ${location.latitude}"
+                    )
+                }
+            })
+        }
+
+
         Log.d(TAG, "minorLoad-end, cost:${SystemClock.elapsedRealtime() - startTs}ms")
     }
 

+ 4 - 1
module/playmate/src/main/java/com/adealink/weparty/playmate/detail/comp/PlaymateToolBarViewComp.kt

@@ -176,7 +176,10 @@ class PlaymateToolBarViewComp(
     }
 
     private fun clickBlack() {
-
+        val act = activity ?: return
+        Router.build(act, Profile.BlackList.PATH)
+            .putExtra(Profile.Common.EXTRA_UID, uid)
+            .start()
     }
 
     companion object {

+ 4 - 2
module/profile/src/main/java/com/adealink/weparty/profile/blacklist/BlackListActivity.kt

@@ -10,8 +10,8 @@ import com.adealink.frame.router.annotation.RouterUri
 import com.adealink.frame.util.statusBarHeight
 import com.adealink.weparty.commonui.BaseActivity
 import com.adealink.weparty.module.profile.Profile
-import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.ActivityProfileBlackListBinding
+import com.adealink.weparty.R as APP_R
 
 @RouterUri(
     path = [Profile.BlackList.PATH],
@@ -32,9 +32,11 @@ class BlackListActivity : BaseActivity() {
     override fun initViews() {
         super.initViews()
         setContentView(binding.root)
+        val statusBarHeight = this@BlackListActivity.statusBarHeight()
+        binding.topBar.setPadding(0, statusBarHeight, 0, 0)
         binding.topBar.updateLayoutParams<ConstraintLayout.LayoutParams> {
             height =
-                getCompatDimension(R.dimen.profile_header_height).toInt() + this@BlackListActivity.statusBarHeight()
+                getCompatDimension(APP_R.dimen.common_top_bar_height).toInt() + this@BlackListActivity.statusBarHeight()
         }
 
     }

+ 4 - 2
module/profile/src/main/java/com/adealink/weparty/profile/report/ReportActivity.kt

@@ -10,8 +10,8 @@ import com.adealink.frame.router.annotation.RouterUri
 import com.adealink.frame.util.statusBarHeight
 import com.adealink.weparty.commonui.BaseActivity
 import com.adealink.weparty.module.profile.Profile
-import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.ActivityProfileReportBinding
+import com.adealink.weparty.R as APP_R
 
 @RouterUri(
     path = [Profile.Report.PATH],
@@ -32,9 +32,11 @@ class ReportActivity : BaseActivity() {
     override fun initViews() {
         super.initViews()
         setContentView(binding.root)
+        val statusBarHeight = this@ReportActivity.statusBarHeight()
+        binding.topBar.setPadding(0, statusBarHeight, 0, 0)
         binding.topBar.updateLayoutParams<ConstraintLayout.LayoutParams> {
             height =
-                getCompatDimension(R.dimen.profile_header_height).toInt() + this@ReportActivity.statusBarHeight()
+                getCompatDimension(APP_R.dimen.common_top_bar_height).toInt() + this@ReportActivity.statusBarHeight()
         }
 
     }

+ 77 - 21
module/profile/src/main/java/com/adealink/weparty/profile/search/SearchActivity.kt

@@ -12,9 +12,11 @@ import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.updateLayoutParams
 import androidx.core.view.updatePadding
+import androidx.lifecycle.MutableLiveData
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.OrientationHelper
 import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.base.Rlt
 import com.adealink.frame.base.fastLazy
 import com.adealink.frame.mvvm.view.viewBinding
 import com.adealink.frame.router.Router
@@ -28,6 +30,7 @@ import com.adealink.weparty.commonui.ext.gone
 import com.adealink.weparty.commonui.ext.onWindowInsets
 import com.adealink.weparty.commonui.ext.show
 import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
+import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
 import com.adealink.weparty.commonui.recycleview.layoutmanager.FlowLayoutManager
 import com.adealink.weparty.module.profile.Profile
 import com.adealink.weparty.profile.databinding.ActivityUserSearchBinding
@@ -39,6 +42,7 @@ import com.adealink.weparty.profile.search.data.SearchResultItemData
 import com.adealink.weparty.profile.search.viewmodel.SearchViewModel
 import com.qmuiteam.qmui.widget.util.QMUIKeyboardHelper
 import com.qmuiteam.qmui.widget.util.QMUIStatusBarHelper
+import com.adealink.weparty.R as APP_R
 
 @RouterUri(
     path = [Profile.Search.PATH],
@@ -55,7 +59,8 @@ class SearchActivity : BaseActivity(),
     private val resultAdapter by fastLazy { MultiTypeListAdapter<SearchResultItemData>() }
 
     private val searchViewModel by viewModels<SearchViewModel>()
-    private var isSearching = false
+    private var isSearching = MutableLiveData<Boolean>()
+    private var isInputEmpty = MutableLiveData<Boolean>()
 
     override fun onBeforeCreate() {
         super.onBeforeCreate()
@@ -78,6 +83,9 @@ class SearchActivity : BaseActivity(),
         resultAdapter.register(SearchItemViewBinder(this))
         binding.rvResult.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
         binding.rvResult.adapter = resultAdapter
+        binding.rvResult.addItemDecoration(
+            VerticalSpaceItemDecoration(20.dp())
+        )
 
         binding.etSearchInput.isClickable = true
         binding.etSearchInput.setOnEditorActionListener(object : OnEditorActionListener {
@@ -86,7 +94,6 @@ class SearchActivity : BaseActivity(),
                     || (actionId == EditorInfo.IME_ACTION_UNSPECIFIED && event != null && event.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN)
                 ) {
                     search(binding.etSearchInput.text?.toString(), false)
-                    binding.etSearchInput.setText(null)
                 }
                 return true
             }
@@ -110,12 +117,11 @@ class SearchActivity : BaseActivity(),
 
             override fun afterTextChanged(s: Editable?) {
                 val input = s?.trim()?.toString()
-                binding.tvSearch.isEnabled = !input.isNullOrEmpty()
+                isInputEmpty.postValue(input.isNullOrEmpty())
             }
         })
         binding.tvSearch.onClick {
             search(binding.etSearchInput.text?.toString(), false)
-            binding.etSearchInput.setText(null)
         }
 
         fitWindow()
@@ -134,16 +140,20 @@ class SearchActivity : BaseActivity(),
             // 键盘显示时使用键盘高度,否则使用导航栏高度
             val bottomInset = if (ime.bottom > 0) ime.bottom else nav.bottom
             view.updatePadding(bottom = bottomInset)
-//            binding.svContent.doOnPreDraw {
-//                binding.svContent.smoothScrollTo(0, bottomInset)
-//            }
             insets
         }
     }
 
     override fun loadData() {
         super.loadData()
-        updateHistoryList(SearchLocalService.getSearchHistory())
+        updateHistoryList(SearchLocalService.getSearchHistory()) { list ->
+            if (list.isEmpty()) {
+                binding.clHistory.gone()
+                return@updateHistoryList
+            }
+            binding.clHistory.show()
+            historyAdapter.submitList(list.map { SearchHistoryItemData(it) })
+        }
     }
 
     private fun search(input: String?, fromHistory: Boolean) {
@@ -151,41 +161,86 @@ class SearchActivity : BaseActivity(),
         if (keyword.isNullOrEmpty()) {
             return
         }
-        //校验非法字符
+        binding.etSearchInput.clearFocus()
+        QMUIKeyboardHelper.hideKeyboard(binding.etSearchInput)
+        hideHistoryList()
 
+        //校验非法字符
+        isSearching.postValue(true)
+        searchViewModel.search(keyword)
 
         if (!fromHistory) {
-            addHistoryList(input)
+            addHistoryList(input) { list ->
+                historyAdapter.submitList(list.map { SearchHistoryItemData(it) })
+            }
         }
     }
 
-    private fun addHistoryList(keyword: String?) {
+    private fun addHistoryList(
+        keyword: String?,
+        commit: ((historyList: List<String>) -> Unit)?
+    ) {
         if (keyword.isNullOrEmpty()) {
             return
         }
         historyList.add(0, keyword)
-        updateHistoryList(historyList)
+        updateHistoryList(historyList, commit)
     }
 
-    private fun updateHistoryList(historyList: List<String>) {
+    private fun updateHistoryList(
+        historyList: List<String>,
+        commit: ((historyList: List<String>) -> Unit)?
+    ) {
         this.historyList = historyList.take(SearchLocalService.MAX_HISTORY_COUNT).toMutableList()
         SearchLocalService.saveSearchHistory(this.historyList)
-        if (historyList.isEmpty()) {
-            binding.clHistory.gone()
-            return
-        }
-        binding.clHistory.show()
-        historyAdapter.submitList(historyList.map { SearchHistoryItemData(it) })
+        commit?.invoke(this.historyList)
     }
 
     override fun observeViewModel() {
         super.observeViewModel()
-        searchViewModel.searchResultLD.observeWithoutCache(this) {
-            isSearching = false
+        isSearching.observe(this) {
+            if (it) {
+                binding.clHistory.gone()
+            }
+        }
+        isInputEmpty.observe(this) {
+            binding.tvSearch.isEnabled = !it
+            if (it) {
+                binding.clSearchResult.gone()
+                if (historyList.isEmpty()) {
+                    binding.clHistory.gone()
+                } else {
+                    binding.clHistory.show()
+                }
+            }
+        }
+        searchViewModel.searchResultLD.observeWithoutCache(this) { rlt ->
+            isSearching.postValue(false)
+            when (rlt) {
+                is Rlt.Failed -> {
+                    binding.clSearchResult.show()
+                    binding.rvResult.gone()
+                    binding.vErrorView.show(
+                        errorEmptyResId = APP_R.drawable.common_list_empty_ic,
+                        title = APP_R.string.commonui_list_empty
+                    )
+                }
 
+                is Rlt.Success -> {
+                    binding.clSearchResult.show()
+                    binding.rvResult.show()
+                    binding.vErrorView.gone()
+                    resultAdapter.submitList(rlt.data)
+                }
+            }
         }
     }
 
+    private fun hideHistoryList() {
+        binding.clHistory.gone()
+    }
+
+
     override fun onClick(
         item: SearchResultItemData,
         pos: Int
@@ -199,6 +254,7 @@ class SearchActivity : BaseActivity(),
         item: SearchHistoryItemData,
         pos: Int
     ) {
+        binding.etSearchInput.setText(item.keyword)
         search(item.keyword, true)
     }
 

+ 4 - 0
module/profile/src/main/java/com/adealink/weparty/profile/search/adapter/SearchHistoryViewBinder.kt

@@ -2,6 +2,7 @@ package com.adealink.weparty.profile.search.adapter
 
 import android.view.LayoutInflater
 import android.view.ViewGroup
+import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
 import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
 import com.adealink.weparty.profile.databinding.LayoutProfileSearchHistoryItemBinding
@@ -14,6 +15,9 @@ class SearchHistoryViewBinder(val listener: OnHistoryClickListener) :
         holder: BindingViewHolder<LayoutProfileSearchHistoryItemBinding>,
         item: SearchHistoryItemData,
     ) {
+        holder.binding.root.onClick {
+            listener.onClick(item, holder.layoutPosition)
+        }
         holder.binding.tvKeyword.text = item.keyword
     }
 

+ 63 - 2
module/profile/src/main/java/com/adealink/weparty/profile/search/viewmodel/SearchViewModel.kt

@@ -1,14 +1,75 @@
 package com.adealink.weparty.profile.search.viewmodel
 
+import com.adealink.frame.base.Rlt
 import com.adealink.frame.mvvm.livedata.ExtMutableLiveData
 import com.adealink.frame.mvvm.viewmodel.BaseViewModel
+import com.adealink.weparty.module.profile.ProfileModule
+import com.adealink.weparty.module.profile.data.UserInfo
+import com.adealink.weparty.profile.search.data.SearchData
 import com.adealink.weparty.profile.search.data.SearchResultItemData
+import kotlinx.coroutines.launch
 
 class SearchViewModel : BaseViewModel() {
 
-    val searchResultLD = ExtMutableLiveData<List<SearchResultItemData>>()
+    val searchResultLD = ExtMutableLiveData<Rlt<List<SearchResultItemData>>>()
 
     fun search(keywork: String) {
-
+        viewModelScope.launch {
+            // TODO: zhangfei 测试
+            searchResultLD.send(
+                Rlt.Success(
+                    listOf(
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                        SearchResultItemData(
+                            SearchData(
+                                ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo(
+                                    "123",
+                                    ""
+                                )
+                            )
+                        ),
+                    )
+                )
+            )
+        }
     }
 }

+ 13 - 1
module/profile/src/main/res/layout/activity_user_search.xml

@@ -144,7 +144,7 @@
             android:gravity="start"
             android:includeFontPadding="false"
             android:singleLine="true"
-            android:text="@string/profile_search_history"
+            android:text="@string/profile_search_contact"
             android:textColor="@color/color_FF1D2129"
             android:textSize="14sp"
             app:layout_constraintEnd_toEndOf="parent"
@@ -164,6 +164,18 @@
             app:layout_constraintTop_toBottomOf="@id/tv_contact"
             tools:listitem="@layout/layout_profile_search_item" />
 
+        <com.adealink.weparty.commonui.widget.CommonEmptyErrorView
+            android:id="@+id/v_error_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="10dp"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/tv_contact"
+            tools:visibility="visible" />
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 

+ 1 - 0
module/profile/src/main/res/values/strings.xml

@@ -26,5 +26,6 @@
     <string name="profile_edit_avatar_upload_fail">头像更新失败</string>
     <string name="profile_search_hint">Please enter search keywords</string>
     <string name="profile_search_history">History</string>
+    <string name="profile_search_contact">联系人</string>
     <string name="profile_search_user_fans">粉丝数 %s</string>
 </resources>