parent
24b12f9778
commit
d64411fa51
@ -0,0 +1,574 @@ |
||||
package com.gyf.csams.activity.model |
||||
|
||||
import android.app.Activity |
||||
import android.app.Application |
||||
import android.content.Context |
||||
import android.graphics.BitmapFactory |
||||
import android.view.inputmethod.InputMethodManager |
||||
import androidx.lifecycle.AndroidViewModel |
||||
import androidx.lifecycle.LiveData |
||||
import androidx.lifecycle.MutableLiveData |
||||
import com.baidu.mapapi.map.* |
||||
import com.baidu.mapapi.model.LatLng |
||||
import com.baidu.mapapi.model.LatLngBounds |
||||
import com.baidu.mapapi.search.core.PoiInfo |
||||
import com.baidu.mapapi.search.core.SearchResult |
||||
import com.baidu.mapapi.search.geocode.* |
||||
import com.baidu.mapapi.search.poi.* |
||||
import com.baidu.mapapi.search.sug.SuggestionResult |
||||
import com.baidu.mapapi.search.sug.SuggestionSearch |
||||
import com.baidu.mapapi.search.sug.SuggestionSearchOption |
||||
import com.gyf.csams.MyLocationListener |
||||
import com.gyf.csams.NOT_IMPL_TIP |
||||
import com.gyf.csams.R |
||||
import com.gyf.lib.uikit.ScaffoldModel |
||||
import com.gyf.lib.uikit.StringForm |
||||
import com.gyf.lib.util.DATETIME_FORMAT |
||||
import com.orhanobut.logger.Logger |
||||
import kotlinx.coroutines.GlobalScope |
||||
import kotlinx.coroutines.launch |
||||
import java.util.* |
||||
|
||||
|
||||
/** |
||||
* 申请活动数据状态管理 |
||||
* |
||||
* @constructor |
||||
* |
||||
* |
||||
* @param application |
||||
*/ |
||||
class ApplyActViewModel(application: Application) : AndroidViewModel(application) { |
||||
val activityName = |
||||
StringForm(formDesc = application.getString(R.string.activity_name), textLength = 10) |
||||
val activityTime = StringForm( |
||||
formDesc = application.getString(R.string.activity_time), |
||||
textLength = DATETIME_FORMAT.length |
||||
) |
||||
val activityAddress = |
||||
StringForm(formDesc = application.getString(R.string.activity_address), textLength = 30) |
||||
val activityDesc = |
||||
StringForm(formDesc = application.getString(R.string.activity_desc), textLength = 50) |
||||
val maxActivitySize = application.resources.getInteger(R.integer.activity_size) |
||||
val activitySize = object : |
||||
StringForm(formDesc = application.getString(R.string.activity_size), textLength = 2) { |
||||
override fun onChange(value: String) { |
||||
if (value.length > textLength) { |
||||
formError.value = "${formDesc}不能超过最大长度$textLength" |
||||
_formValue.value = value.slice(IntRange(0, textLength - 1)) |
||||
} else if (value.matches(Regex("\\d+")) && value.toInt() !in 1..maxActivitySize) { |
||||
Logger.i("活动人数:${value}不合法") |
||||
formError.value = |
||||
application.getString(R.string.activity_size_error, 1, maxActivitySize) |
||||
} else { |
||||
_formValue.value = value |
||||
formError.value = "" |
||||
} |
||||
|
||||
} |
||||
} |
||||
val city = |
||||
object : StringForm(formDesc = application.getString(R.string.city), textLength = 4) { |
||||
override val formPlaceholder = "" |
||||
} |
||||
|
||||
// 默认逆地理编码半径范围 |
||||
private val sDefaultRGCRadius = 500 |
||||
|
||||
private val mGeoCoder: GeoCoder = GeoCoder.newInstance().apply { |
||||
setOnGetGeoCodeResultListener(object : OnGetGeoCoderResultListener { |
||||
override fun onGetGeoCodeResult(p0: GeoCodeResult?) { |
||||
|
||||
} |
||||
|
||||
override fun onGetReverseGeoCodeResult(reverseGeoCodeResult: ReverseGeoCodeResult?) { |
||||
reverseGeoCodeResult?.let { |
||||
GlobalScope.launch { |
||||
updateUI(it) |
||||
} |
||||
} |
||||
|
||||
} |
||||
}) |
||||
} |
||||
|
||||
lateinit var scaffoldModel: ScaffoldModel |
||||
|
||||
private val _mapView = MutableLiveData<MapView>() |
||||
|
||||
val mapView: LiveData<MapView> = _mapView |
||||
|
||||
/** |
||||
* 更新UI |
||||
* |
||||
* @param reverseGeoCodeResult |
||||
*/ |
||||
private fun updateUI(reverseGeoCodeResult: ReverseGeoCodeResult) { |
||||
Logger.i("逆编码更新地点信息") |
||||
var poiInfo = reverseGeoCodeResult.poiList |
||||
val curAddressPoiInfo = PoiInfo() |
||||
curAddressPoiInfo.address = reverseGeoCodeResult.address |
||||
curAddressPoiInfo.location = reverseGeoCodeResult.location |
||||
if (null == poiInfo) { |
||||
poiInfo = ArrayList(2) |
||||
} |
||||
poiInfo.add(0, curAddressPoiInfo) |
||||
|
||||
_poInfo.postValue(poiInfo) |
||||
_selectPoi.postValue(null) |
||||
} |
||||
|
||||
|
||||
fun searchPoiInCity() { |
||||
if (city.formValue.value?.isEmpty() == true || |
||||
address.formValue.value?.isEmpty() == true |
||||
) { |
||||
Logger.i("city=${city.formValue.value},keyword=${address.formValue.value}") |
||||
return |
||||
} else { |
||||
Logger.i("在${city.formValue.value}市内找${address.formValue.value}") |
||||
mPoiSearch.searchInCity( |
||||
PoiCitySearchOption() |
||||
.city(city.formValue.value) |
||||
.keyword(address.formValue.value) |
||||
.pageNum(0) // 分页编号 |
||||
.cityLimit(true) |
||||
.scope(1) |
||||
) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 在地图上定位poi |
||||
* |
||||
* @param suggestInfo |
||||
*/ |
||||
fun locateSuggestPoi(suggestInfo: SuggestionResult.SuggestionInfo) { |
||||
// _sugResult.value?.clear() |
||||
_sugResult.value = mutableListOf() |
||||
_mapView.value?.apply { |
||||
val latLng = suggestInfo.getPt() |
||||
|
||||
_mStatusChangeByItemClick.value = false |
||||
// 将地图平移到 latLng 位置 |
||||
val mapStatusUpdate = MapStatusUpdateFactory.newLatLng(latLng) |
||||
map.setMapStatus(mapStatusUpdate) |
||||
|
||||
// 清除之前的 |
||||
// clearData() |
||||
|
||||
// 显示当前的 |
||||
// if (!showSuggestMarker(latLng)) { |
||||
// searchPoiInCity() |
||||
// } |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 显示定位点 |
||||
* |
||||
* @param latLng |
||||
*/ |
||||
private fun showSuggestMarker(latLng: LatLng?): Boolean { |
||||
if (null == latLng) { |
||||
return false |
||||
} |
||||
_mapView.value?.apply { |
||||
val markerOptions = MarkerOptions() |
||||
.position(latLng) |
||||
.icon(mBitmapDescWaterDrop) |
||||
.scaleX(1.5f) |
||||
.scaleY(1.5f) |
||||
.clickable(true) |
||||
map.addOverlay(markerOptions) |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
val mSuggestionSearch: SuggestionSearch = SuggestionSearch.newInstance().apply { |
||||
setOnGetSuggestionResultListener { it -> |
||||
if (it == null |
||||
|| it.error == SearchResult.ERRORNO.RESULT_NOT_FOUND |
||||
) { |
||||
scaffoldModel.update( |
||||
message = application.getString( |
||||
R.string.search_null |
||||
) |
||||
) |
||||
Logger.i("sug检索不到地点") |
||||
} else { |
||||
it.allSuggestions?.let { |
||||
Logger.i("sug检索到${it.size}个地点") |
||||
_sugResult.value = it |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private val mPoiSearch: PoiSearch = PoiSearch.newInstance().apply { |
||||
setOnGetPoiSearchResultListener( |
||||
object : OnGetPoiSearchResultListener { |
||||
override fun onGetPoiResult( |
||||
poiResult: PoiResult? |
||||
) { |
||||
if (poiResult == null || poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND) { |
||||
scaffoldModel.update( |
||||
message = application.getString( |
||||
R.string.search_null |
||||
) |
||||
) |
||||
Logger.i("Poi检索不到地点") |
||||
} else { |
||||
poiResult.allPoi?.let { |
||||
Logger.i("Poi检索到${it.size}个地点") |
||||
setPoiResult(it) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Suppress("DEPRECATION") |
||||
override fun onGetPoiDetailResult(p0: PoiDetailResult?) { |
||||
Logger.i("$p0") |
||||
} |
||||
|
||||
override fun onGetPoiDetailResult(p0: PoiDetailSearchResult?) { |
||||
Logger.i("$p0") |
||||
} |
||||
|
||||
override fun onGetPoiIndoorResult(p0: PoiIndoorResult?) { |
||||
Logger.i("$p0") |
||||
} |
||||
}) |
||||
} |
||||
|
||||
private val mBitmapDescWaterDrop = BitmapDescriptorFactory.fromBitmap( |
||||
BitmapFactory.decodeResource( |
||||
application.resources, |
||||
R.drawable.icon_binding_point |
||||
) |
||||
) |
||||
|
||||
|
||||
private val mMarkerPoiInfo = mutableMapOf<Marker, PoiInfo>() |
||||
|
||||
private var mPreSelectMarker: Marker? = null |
||||
|
||||
private fun showPoiMarker(poiInfo: PoiInfo?, i: Int) { |
||||
poiInfo?.apply { |
||||
_mapView.value?.apply { |
||||
val markerOptions = MarkerOptions() |
||||
.position(location) |
||||
.icon(mBitmapDescWaterDrop) |
||||
|
||||
// 第一个poi放大显示 |
||||
// if (0 == i) { |
||||
// val infoWindow: InfoWindow = getPoiInfoWindow(poiInfo) |
||||
// markerOptions.scaleX(1.5f).scaleY(1.5f).infoWindow(infoWindow) |
||||
// } |
||||
val marker = map.addOverlay(markerOptions) as Marker |
||||
mMarkerPoiInfo[marker] = poiInfo |
||||
if (0 == i) { |
||||
mPreSelectMarker = marker |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
private fun setPoiResult(poiInfos: List<PoiInfo>?) { |
||||
_mapView.value?.apply { |
||||
if (null == poiInfos || poiInfos.isEmpty()) { |
||||
return |
||||
} |
||||
clearData() |
||||
|
||||
// 将地图平移到 latLng 位置 |
||||
val latLng = poiInfos[0].getLocation() |
||||
map.setMapStatus(mapStatus(latLng)) |
||||
val itr: Iterator<*> = poiInfos.iterator() |
||||
val latLngs: MutableList<LatLng> = ArrayList() |
||||
var poiInfo: PoiInfo? |
||||
var i = 0 |
||||
while (itr.hasNext()) { |
||||
poiInfo = itr.next() as PoiInfo? |
||||
if (null == poiInfo) { |
||||
continue |
||||
} |
||||
showPoiMarker(poiInfo, i) |
||||
latLngs.add(poiInfo.getLocation()) |
||||
i++ |
||||
} |
||||
setBounds(latLngs) |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 最佳视野内显示所有点标记 |
||||
*/ |
||||
private fun setBounds(latLngs: List<LatLng>?) { |
||||
if (null == latLngs || latLngs.isEmpty()) { |
||||
return |
||||
} |
||||
val horizontalPadding = 80 |
||||
val verticalPaddingBottom = 400 |
||||
|
||||
// 构造地理范围对象 |
||||
val builder = LatLngBounds.Builder() |
||||
// 让该地理范围包含一组地理位置坐标 |
||||
builder.include(latLngs) |
||||
|
||||
_mapView.value?.apply { |
||||
// 设置显示在指定相对于MapView的padding中的地图地理范围 |
||||
val mapStatusUpdate = MapStatusUpdateFactory.newLatLngBounds( |
||||
builder.build(), |
||||
horizontalPadding, |
||||
verticalPaddingBottom, |
||||
horizontalPadding, |
||||
verticalPaddingBottom |
||||
) |
||||
// 更新地图 |
||||
map.setMapStatus(mapStatusUpdate) |
||||
// 设置地图上控件与地图边界的距离,包含比例尺、缩放控件、logo、指南针的位置 |
||||
map.setViewPadding( |
||||
0, |
||||
0, |
||||
0, |
||||
verticalPaddingBottom |
||||
) |
||||
} |
||||
|
||||
} |
||||
|
||||
private fun clearData() { |
||||
Logger.i("清空地图数据") |
||||
_mapView.value?.apply { |
||||
map.clear() |
||||
mMarkerPoiInfo.clear() |
||||
mPreSelectMarker = null |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建地图中心点marker |
||||
*/ |
||||
private fun createCenterMarker(mBaiduMap: BaiduMap, mCenter: LatLng) { |
||||
Logger.i("标记坐标${mCenter}为地图中心点") |
||||
val projection: Projection = mBaiduMap.projection ?: return |
||||
val point = projection.toScreenLocation(mCenter) |
||||
val markerOptions = MarkerOptions() |
||||
.position(mCenter) |
||||
.icon(mBitmapDescWaterDrop) |
||||
.flat(false) |
||||
.fixedScreenPosition(point) |
||||
marker = markerOptions |
||||
mBaiduMap.addOverlay(markerOptions) |
||||
} |
||||
|
||||
fun isLatlngEqual(latLng0: LatLng, latLng1: LatLng): Boolean { |
||||
return (latLng0.latitude == latLng1.latitude |
||||
&& latLng0.longitude == latLng1.longitude) |
||||
} |
||||
|
||||
/** |
||||
* 逆地理编码请求 |
||||
* |
||||
* @param latLng |
||||
*/ |
||||
private fun reverseRequest(latLng: LatLng?) { |
||||
Logger.i("逆地理编码请求") |
||||
latLng?.let { |
||||
val reverseGeoCodeOption = ReverseGeoCodeOption().location(it) |
||||
.newVersion(1) // 建议请求新版数据 |
||||
.radius(sDefaultRGCRadius) |
||||
mGeoCoder.reverseGeoCode(reverseGeoCodeOption) |
||||
} |
||||
|
||||
} |
||||
|
||||
private fun mapStatus(mCenter: LatLng): MapStatusUpdate { |
||||
return MapStatusUpdateFactory.newLatLngZoom( |
||||
mCenter, |
||||
16f |
||||
) |
||||
} |
||||
|
||||
fun updateMapStatus(mapStatus: MapStatus?) { |
||||
mapStatus?.target?.let { |
||||
// 如果是点击poi item导致的地图状态更新,则不用做后面的逆地理请求, |
||||
if (_mStatusChangeByItemClick.value == true) { |
||||
if (!isLatlngEqual( |
||||
mCenter, |
||||
it |
||||
) |
||||
) { |
||||
mCenter = it |
||||
} |
||||
_mStatusChangeByItemClick.postValue(false) |
||||
return |
||||
} |
||||
|
||||
if (!isLatlngEqual(mCenter, it)) { |
||||
mCenter = it |
||||
reverseRequest(mCenter) |
||||
} |
||||
} |
||||
} |
||||
|
||||
private lateinit var mCenter: LatLng |
||||
|
||||
private lateinit var marker: MarkerOptions |
||||
|
||||
fun hideKeyBoard(activity: Activity?) { |
||||
Logger.i("隐藏软键盘") |
||||
activity?.apply { |
||||
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |
||||
window.peekDecorView()?.let { |
||||
imm.hideSoftInputFromWindow(it.windowToken, 0) |
||||
} |
||||
} |
||||
} |
||||
|
||||
fun createMapView(context: Context): MapView { |
||||
val mapView = MapView(context).apply { |
||||
|
||||
MyLocationListener.location.value?.let { _ -> |
||||
// 设置初始中心点为用户附近 |
||||
// mCenter = LatLng(it.latitude, it.longitude) |
||||
mCenter = LatLng(39.963175, 116.400244) |
||||
|
||||
map.setMapStatus(mapStatus(mCenter = mCenter)) |
||||
|
||||
map.setOnMapTouchListener { |
||||
hideKeyBoard(context as Activity) |
||||
} |
||||
|
||||
map.setOnMarkerClickListener { |
||||
scaffoldModel.update(message = "确定选中此地址", actionLabel = "确定") { |
||||
val poi = (_selectPoi.value ?: poiInfo.value?.get(0)) |
||||
val address = poi?.address ?: poi?.name ?: "地址获取失败,请再尝试一次" |
||||
if (address.isNotEmpty()) { |
||||
activityAddress.onChange(address) |
||||
} else { |
||||
Logger.w("地址获取失败") |
||||
} |
||||
|
||||
closeMap() |
||||
} |
||||
true |
||||
} |
||||
|
||||
map.removeMarkerClickListener { |
||||
Logger.i("删除标记") |
||||
true |
||||
} |
||||
|
||||
map.setOnMapLoadedCallback { |
||||
Logger.i("地图加载完成!") |
||||
// createCenterMarker(map, mCenter) |
||||
map.addOverlay(MarkerOptions().position(mCenter).icon(mBitmapDescWaterDrop)) |
||||
reverseRequest(mCenter) |
||||
} |
||||
|
||||
map.setOnMapStatusChangeListener(object : |
||||
BaiduMap.OnMapStatusChangeListener { |
||||
override fun onMapStatusChangeStart(p0: MapStatus?) { |
||||
Logger.i("状态开始改变:$p0") |
||||
} |
||||
|
||||
override fun onMapStatusChangeStart( |
||||
p0: MapStatus?, |
||||
p1: Int |
||||
) { |
||||
Logger.i("状态改变:$p0,p1=$p1") |
||||
} |
||||
|
||||
override fun onMapStatusChange(mapStatus: MapStatus?) { |
||||
Logger.i("状态改变:$mapStatus,_mStatusChangeByItemClick.value=${_mStatusChangeByItemClick.value}") |
||||
updateMapStatus(mapStatus = mapStatus) |
||||
map.clear() |
||||
map.addOverlay(MarkerOptions().position(mCenter).icon(mBitmapDescWaterDrop)) |
||||
} |
||||
|
||||
override fun onMapStatusChangeFinish( |
||||
mapStatus: MapStatus? |
||||
) { |
||||
Logger.i("状态改变完成:$mapStatus") |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
_mapView.value = mapView |
||||
return mapView |
||||
} |
||||
|
||||
|
||||
val address = object : StringForm(formDesc = "", textLength = 5) { |
||||
override val formPlaceholder = "" |
||||
|
||||
override fun onChange(value: String) { |
||||
super.onChange(value) |
||||
Logger.i("Sug检索,城市:${city.formValue.value},地点关键词:${value}") |
||||
// _sugResult.value?.clear() |
||||
_sugResult.value = mutableListOf() |
||||
mSuggestionSearch.requestSuggestion( |
||||
SuggestionSearchOption() |
||||
.city(city.formValue.value) |
||||
.keyword(value) |
||||
.citylimit(true) |
||||
) |
||||
} |
||||
} |
||||
|
||||
private val _showMap = MutableLiveData<Boolean>() |
||||
val showMap: LiveData<Boolean> = _showMap |
||||
|
||||
private val _mStatusChangeByItemClick = MutableLiveData(false) |
||||
|
||||
private val _poInfo = MutableLiveData<List<PoiInfo>>() |
||||
val poiInfo: LiveData<List<PoiInfo>> = _poInfo |
||||
|
||||
private val _selectPoi = MutableLiveData<PoiInfo?>() |
||||
val selectPoi: LiveData<PoiInfo?> = _selectPoi |
||||
|
||||
private val _sugResult = MutableLiveData<MutableList<SuggestionResult.SuggestionInfo>>() |
||||
val sugResult: LiveData<MutableList<SuggestionResult.SuggestionInfo>> = _sugResult |
||||
|
||||
fun updateSelectPoi(poiInfo: PoiInfo?) { |
||||
_selectPoi.value = poiInfo |
||||
} |
||||
|
||||
fun updateStatusChangeByItemClick(flag: Boolean) { |
||||
_mStatusChangeByItemClick.value = flag |
||||
} |
||||
|
||||
fun openMap() { |
||||
_showMap.value = true |
||||
} |
||||
|
||||
private fun closeMap() { |
||||
_showMap.value = false |
||||
|
||||
clearData() |
||||
} |
||||
|
||||
private fun destroy() { |
||||
mPoiSearch.destroy() |
||||
|
||||
mSuggestionSearch.destroy() |
||||
|
||||
mapView.value?.onDestroy() |
||||
|
||||
mBitmapDescWaterDrop?.recycle() |
||||
} |
||||
|
||||
/** |
||||
* TODO 提交申请 |
||||
* |
||||
*/ |
||||
fun apply(callback: (message: String) -> Unit) { |
||||
callback(NOT_IMPL_TIP) |
||||
} |
||||
} |
@ -0,0 +1,495 @@ |
||||
package com.gyf.csams.activity.ui |
||||
|
||||
import android.Manifest |
||||
import android.content.pm.PackageManager |
||||
import android.os.Bundle |
||||
import androidx.activity.compose.rememberLauncherForActivityResult |
||||
import androidx.activity.compose.setContent |
||||
import androidx.activity.result.contract.ActivityResultContracts |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import androidx.compose.foundation.clickable |
||||
import androidx.compose.foundation.layout.* |
||||
import androidx.compose.foundation.lazy.LazyColumn |
||||
import androidx.compose.foundation.lazy.rememberLazyListState |
||||
import androidx.compose.foundation.text.KeyboardOptions |
||||
import androidx.compose.material.* |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.LaunchedEffect |
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.livedata.observeAsState |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import androidx.compose.ui.Alignment |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.platform.LocalContext |
||||
import androidx.compose.ui.res.painterResource |
||||
import androidx.compose.ui.res.stringResource |
||||
import androidx.compose.ui.text.input.KeyboardType |
||||
import androidx.compose.ui.unit.dp |
||||
import androidx.compose.ui.viewinterop.AndroidView |
||||
import androidx.core.content.ContextCompat |
||||
import androidx.lifecycle.viewmodel.compose.viewModel |
||||
import com.baidu.location.LocationClient |
||||
import com.baidu.location.LocationClientOption |
||||
import com.baidu.mapapi.map.MapStatusUpdateFactory |
||||
import com.baidu.mapapi.search.sug.SuggestionResult |
||||
import com.google.android.material.datepicker.MaterialDatePicker |
||||
import com.gyf.csams.MainApplication |
||||
import com.gyf.csams.MyLocationListener |
||||
import com.gyf.csams.R |
||||
import com.gyf.csams.activity.model.ApplyActViewModel |
||||
import com.gyf.csams.uikit.Background |
||||
import com.gyf.csams.uikit.BackgroundImage |
||||
import com.gyf.csams.uikit.DescCard |
||||
import com.gyf.lib.uikit.* |
||||
import com.gyf.lib.util.BottomButton |
||||
import com.gyf.lib.util.format |
||||
import com.orhanobut.logger.Logger |
||||
import kotlinx.coroutines.launch |
||||
import java.util.* |
||||
|
||||
|
||||
val location_permissions = arrayOf( |
||||
Manifest.permission.ACCESS_COARSE_LOCATION, |
||||
Manifest.permission.ACCESS_FINE_LOCATION, |
||||
Manifest.permission.ACCESS_WIFI_STATE, |
||||
Manifest.permission.ACCESS_NETWORK_STATE, |
||||
Manifest.permission.CHANGE_WIFI_STATE |
||||
) |
||||
|
||||
|
||||
/** |
||||
* 申请活动 |
||||
* |
||||
*/ |
||||
class ApplyActActivity : AppCompatActivity() { |
||||
|
||||
private lateinit var mLocationClient: LocationClient |
||||
|
||||
override fun onStop() { |
||||
super.onStop() |
||||
mLocationClient.stop() |
||||
} |
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
|
||||
mLocationClient = (application as MainApplication).mLocationClient |
||||
|
||||
setContent { |
||||
Body { scaffoldState -> |
||||
MainColumnFrame(background = { Background(image = BackgroundImage.ApplyActivity) }) { |
||||
val model: ApplyActViewModel = viewModel() |
||||
val scaffoldModel: ScaffoldModel = viewModel() |
||||
model.scaffoldModel = scaffoldModel |
||||
val showMap by model.showMap.observeAsState(false) |
||||
val location by MyLocationListener.location.observeAsState() |
||||
|
||||
when { |
||||
showMap && location != null -> { |
||||
Box { |
||||
val sugResult by model.sugResult.observeAsState() |
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) { |
||||
AndroidView(modifier = Modifier |
||||
.weight(0.6F) |
||||
.fillMaxWidth(), |
||||
factory = { context -> model.createMapView(context) }) |
||||
|
||||
if (sugResult == null || sugResult?.size == 0) { |
||||
PoiItem( |
||||
modifier = Modifier |
||||
.weight(0.4F) |
||||
.fillMaxWidth() |
||||
) |
||||
} |
||||
|
||||
} |
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) { |
||||
|
||||
Search( |
||||
modifier = Modifier |
||||
.weight(0.2F) |
||||
.fillMaxWidth() |
||||
) |
||||
|
||||
sugResult.let { |
||||
if (it.isNullOrEmpty()) { |
||||
Spacer( |
||||
modifier = Modifier |
||||
.weight(0.8F) |
||||
.fillMaxWidth() |
||||
) |
||||
} else { |
||||
SuggestItem( |
||||
modifier = Modifier |
||||
.weight(0.8F) |
||||
.fillMaxWidth(), |
||||
sugResult = it |
||||
) |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
} |
||||
else -> { |
||||
Title(modifier = Modifier.weight(0.2F)) |
||||
Row( |
||||
Modifier |
||||
.weight(0.1F) |
||||
.fillMaxWidth(), horizontalArrangement = Arrangement.Center |
||||
) { |
||||
BaseTextField(form = model.activityName) |
||||
} |
||||
Row( |
||||
Modifier |
||||
.weight(0.1F) |
||||
.fillMaxWidth(), |
||||
horizontalArrangement = Arrangement.Center |
||||
) { |
||||
ActivityTime() |
||||
} |
||||
ActivityLocation( |
||||
modifier = Modifier |
||||
.weight(0.15F) |
||||
.fillMaxWidth() |
||||
) |
||||
DescCard( |
||||
modifier = Modifier.weight(0.3F), |
||||
stringForm = model.activityDesc |
||||
) |
||||
val error by model.activitySize.formError.observeAsState() |
||||
if (error?.isNotEmpty() == true) { |
||||
scaffoldModel.update(message = error) |
||||
} |
||||
Row( |
||||
Modifier |
||||
.weight(0.1F) |
||||
.fillMaxWidth(), horizontalArrangement = Arrangement.Center |
||||
) { |
||||
BaseTextField( |
||||
form = model.activitySize, |
||||
keyboardOptions = |
||||
KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number) |
||||
) |
||||
} |
||||
Spacer(modifier = Modifier.weight(0.05F)) |
||||
BottomButton(modifier = Modifier.fillMaxWidth()) { |
||||
model.apply { scaffoldModel.update(message = it) } |
||||
} |
||||
} |
||||
} |
||||
ShowSnackbar(scaffoldState = scaffoldState) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
private fun SelectIcon(modifier: Modifier = Modifier) { |
||||
IconButton(modifier = modifier, onClick = { |
||||
|
||||
}) { |
||||
Icon( |
||||
painter = painterResource(id = R.drawable.ic_seleted), |
||||
contentDescription = null |
||||
) |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
private fun Search( |
||||
modifier: Modifier = Modifier, |
||||
model: ApplyActViewModel = viewModel() |
||||
) { |
||||
Column( |
||||
modifier = modifier |
||||
.fillMaxWidth() |
||||
// .border(width = 1.dp, color = MaterialTheme.colors.onBackground) |
||||
, |
||||
verticalArrangement = Arrangement.SpaceAround |
||||
) { |
||||
Card(backgroundColor = MaterialTheme.colors.background) { |
||||
Row(modifier = Modifier.fillMaxWidth()) { |
||||
BaseTextField(modifier = Modifier.weight(0.5F), |
||||
form = model.city, leadingIcon = { |
||||
Text( |
||||
text = stringResource(id = R.string.at), |
||||
style = MaterialTheme.typography.subtitle2 |
||||
) |
||||
}, trailingIcon = { |
||||
Text( |
||||
text = stringResource(id = R.string.incity), |
||||
style = MaterialTheme.typography.subtitle2 |
||||
) |
||||
}, textStyle = MaterialTheme.typography.subtitle2 |
||||
) |
||||
BaseTextField(modifier = Modifier.weight(0.5F), form = model.address) |
||||
} |
||||
} |
||||
// Row( |
||||
// modifier = Modifier.fillMaxWidth(), |
||||
// horizontalArrangement = Arrangement.Center |
||||
// ) { |
||||
// OutlinedButton(onClick = { |
||||
// model.searchPoiInCity() |
||||
// }) { |
||||
// Text(text = stringResource(id = R.string.search_btn)) |
||||
// } |
||||
// } |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
@Composable |
||||
private fun SuggestItem( |
||||
modifier: Modifier = Modifier, |
||||
model: ApplyActViewModel = viewModel(), |
||||
sugResult: List<SuggestionResult.SuggestionInfo> |
||||
) { |
||||
val state = rememberLazyListState() |
||||
|
||||
LazyColumn(modifier = modifier, state = state) { |
||||
sugResult.forEach { |
||||
item { |
||||
Card(backgroundColor = MaterialTheme.colors.background) { |
||||
Column( |
||||
modifier = Modifier |
||||
.fillMaxWidth() |
||||
.clickable(onClick = { |
||||
model.hideKeyBoard(this@ApplyActActivity) |
||||
model.locateSuggestPoi(suggestInfo = it) |
||||
}) |
||||
) { |
||||
Text(text = it.key) |
||||
it.address?.let { |
||||
Text(text = it) |
||||
} |
||||
} |
||||
} |
||||
Divider(color = MaterialTheme.colors.onBackground) |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
@Composable |
||||
private fun PoiItem( |
||||
modifier: Modifier = Modifier, |
||||
model: ApplyActViewModel = viewModel() |
||||
) { |
||||
val state = rememberLazyListState() |
||||
val poiInfo by model.poiInfo.observeAsState() |
||||
val selectPoi by model.selectPoi.observeAsState() |
||||
val mapView by model.mapView.observeAsState() |
||||
LazyColumn(modifier = modifier, state = state) { |
||||
poiInfo?.withIndex()?.forEach { it -> |
||||
if (it.value.name?.isNotEmpty() == true || it.value.address?.isNotEmpty() == true) { |
||||
item { |
||||
Card(modifier = Modifier.clickable(onClick = { |
||||
model.updateStatusChangeByItemClick(true) |
||||
val mapStatusUpdate = |
||||
MapStatusUpdateFactory.newLatLng(it.value.getLocation()) |
||||
mapView?.map?.setMapStatus(mapStatusUpdate) |
||||
model.updateSelectPoi(it.value) |
||||
}), backgroundColor = MaterialTheme.colors.background) { |
||||
Row( |
||||
modifier = Modifier |
||||
.fillMaxWidth(), |
||||
horizontalArrangement = Arrangement.SpaceBetween, |
||||
verticalAlignment = Alignment.CenterVertically |
||||
) { |
||||
if (it.index == 0) { |
||||
Text( |
||||
text = "【${it.value.address}】", |
||||
color = MaterialTheme.colors.primary, |
||||
modifier = Modifier.weight(0.8F) |
||||
) |
||||
if (selectPoi == null || selectPoi == it.value) { |
||||
SelectIcon(modifier = Modifier.weight(0.2F)) |
||||
} else { |
||||
Spacer(modifier = Modifier.weight(0.2F)) |
||||
} |
||||
} else { |
||||
Column( |
||||
modifier = Modifier.weight(0.8F) |
||||
) { |
||||
Text( |
||||
text = it.value.name, |
||||
color = MaterialTheme.colors.primary |
||||
) |
||||
it.value.address?.let { |
||||
Text(text = it, color = MaterialTheme.colors.secondary) |
||||
} |
||||
} |
||||
if (selectPoi == it.value) { |
||||
SelectIcon(modifier = Modifier.weight(0.2F)) |
||||
} else { |
||||
Spacer(modifier = Modifier.weight(0.2F)) |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
Spacer(modifier = Modifier.height(10.dp)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
poiInfo?.apply { |
||||
LaunchedEffect(poiInfo) { |
||||
launch { |
||||
if (size > 0) { |
||||
state.animateScrollToItem(0) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
@Composable |
||||
private fun Title(modifier: Modifier = Modifier) { |
||||
Box(modifier = modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { |
||||
Text( |
||||
text = stringResource(id = R.string.activity_application), |
||||
style = MaterialTheme.typography.h4 |
||||
) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 活动时间 |
||||
* |
||||
* @param modifier |
||||
* @param model |
||||
*/ |
||||
@Composable |
||||
private fun ActivityTime( |
||||
modifier: Modifier = Modifier, |
||||
model: ApplyActViewModel = viewModel() |
||||
) { |
||||
val context = LocalContext.current as ApplyActActivity |
||||
val scope = rememberCoroutineScope() |
||||
BaseTextField( |
||||
modifier = modifier, |
||||
form = model.activityTime, readOnly = true |
||||
) { |
||||
IconButton(onClick = { |
||||
scope.launch { |
||||
val picker = MaterialDatePicker |
||||
.Builder |
||||
.datePicker() |
||||
.setSelection(Date().time) |
||||
.build() |
||||
picker.show(context.supportFragmentManager, picker.toString()) |
||||
picker.addOnPositiveButtonClickListener { |
||||
model.activityTime.onChange(Date(it).format()) |
||||
} |
||||
} |
||||
|
||||
}) { |
||||
Icon( |
||||
painter = painterResource(id = R.drawable.ic_date), |
||||
contentDescription = null |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun requestLocation() { |
||||
//如果想获取地址信息,需在配置LocationClientOption类时做相应的设置 |
||||
val option = LocationClientOption() |
||||
option.locationMode = LocationClientOption.LocationMode.Hight_Accuracy |
||||
//可选,是否需要地址信息,默认为不需要,即参数为false |
||||
//如果开发者需要获得当前点的地址信息,此处必须为true |
||||
option.setIsNeedAddress(true) |
||||
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true |
||||
option.setNeedNewVersionRgc(true) |
||||
|
||||
|
||||
mLocationClient.locOption = option |
||||
Logger.i("开始定位") |
||||
mLocationClient.start() |
||||
} |
||||
|
||||
|
||||
private fun checkSelfPermissions(): Int { |
||||
location_permissions.forEach { |
||||
when (val v = ContextCompat.checkSelfPermission(this, it)) { |
||||
PackageManager.PERMISSION_GRANTED -> Logger.i("权限${it}已放通") |
||||
else -> { |
||||
Logger.i("权限${it}检查状态:$v") |
||||
return v |
||||
} |
||||
} |
||||
|
||||
} |
||||
Logger.i("已授权") |
||||
return PackageManager.PERMISSION_GRANTED |
||||
} |
||||
|
||||
/** |
||||
* 活动地点 |
||||
* |
||||
* @param modifier |
||||
* @param model |
||||
*/ |
||||
@Composable |
||||
private fun ActivityLocation( |
||||
modifier: Modifier = Modifier, |
||||
model: ApplyActViewModel = viewModel(), |
||||
scaffoldModel: ScaffoldModel = viewModel() |
||||
) { |
||||
val launcher = rememberLauncherForActivityResult( |
||||
ActivityResultContracts.RequestMultiplePermissions() |
||||
) { it -> |
||||
var isGranted = true |
||||
it.entries.forEach { |
||||
isGranted = isGranted && it.value |
||||
Logger.i("权限:${it.key}授权结果:${it.value}") |
||||
} |
||||
|
||||
if (isGranted) { |
||||
// Permission Accepted: Do something |
||||
requestLocation() |
||||
model.openMap() |
||||
Logger.i("准备打开地图") |
||||
} else { |
||||
// Permission Denied: Do something |
||||
scaffoldModel.update(message = getString(R.string.denined_location_permission)) |
||||
} |
||||
} |
||||
|
||||
BaseTextField(modifier = modifier, form = model.activityAddress, readOnly = true) { |
||||
IconButton(onClick = { |
||||
when (PackageManager.PERMISSION_GRANTED) { |
||||
checkSelfPermissions() -> { |
||||
// Some works that require permission |
||||
requestLocation() |
||||
model.openMap() |
||||
Logger.i("准备打开地图") |
||||
} |
||||
else -> { |
||||
// Asking for permission |
||||
Logger.i("询问权限") |
||||
launcher.launch(location_permissions) |
||||
} |
||||
} |
||||
}) { |
||||
Icon( |
||||
painter = painterResource(id = R.drawable.ic_icon_location), |
||||
contentDescription = null |
||||
) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,12 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="200dp" |
||||
android:height="200dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M789.6,187.35h-77.04c-7.17,0 -13.02,-5.85 -13.02,-13.02v-34.28c0,-13.43 -10.55,-24.88 -24.06,-25.21 -14.01,-0.41 -25.38,10.79 -25.38,24.72v34.85c0,7.17 -5.85,13.02 -13.02,13.02L389.48,187.44c-7.17,0 -13.02,-5.85 -13.02,-13.02v-34.36c0,-13.43 -10.55,-24.88 -24.06,-25.21 -14.01,-0.41 -25.38,10.79 -25.38,24.72v34.85c0,7.17 -5.85,13.02 -13.02,13.02h-79.6c-62.87,-0.08 -113.79,50.84 -113.79,113.71v494.22c0,62.87 50.92,113.79 113.79,113.79h555.11c62.87,0 113.79,-50.92 113.79,-113.79v-494.22c0.08,-62.87 -50.84,-113.79 -113.71,-113.79zM170.05,301.14c0,-35.6 28.84,-64.35 64.35,-64.35h79.6c7.17,0 13.02,5.85 13.02,13.02v34.36c0,13.43 10.55,24.88 24.06,25.21 14.01,0.41 25.38,-10.79 25.38,-24.72v-34.85c0,-7.17 5.85,-13.02 13.02,-13.02h247.6c7.17,0 13.02,5.85 13.02,13.02v34.36c0,13.43 10.55,24.88 24.06,25.21 14.01,0.41 25.38,-10.79 25.38,-24.72v-34.85c0,-7.17 5.85,-13.02 13.02,-13.02h77.04c35.6,0 64.35,28.84 64.35,64.35v37.41a16.95,16.95 0,0 1,-16.97 16.97L187.02,355.53a16.95,16.95 0,0 1,-16.97 -16.97v-37.41zM853.95,795.45c0,35.6 -28.84,64.35 -64.35,64.35L234.4,859.8c-35.51,0 -64.35,-28.84 -64.35,-64.35L170.05,421.94a16.95,16.95 0,0 1,16.97 -16.97h650.03a16.95,16.95 0,0 1,16.97 16.97l-0.08,373.51z" /> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M288.13,573.06h54.13c13.6,0 24.72,-11.04 24.72,-24.72 0,-13.6 -11.04,-24.72 -24.72,-24.72h-54.13c-13.6,0 -24.72,11.04 -24.72,24.72s11.04,24.72 24.72,24.72zM484.97,573.06h54.13c13.6,0 24.72,-11.04 24.72,-24.72 0,-13.6 -11.04,-24.72 -24.72,-24.72h-54.13c-13.6,0 -24.72,11.04 -24.72,24.72 0.08,13.68 11.12,24.72 24.72,24.72zM681.9,573.06h54.13c13.6,0 24.72,-11.04 24.72,-24.72 0,-13.6 -11.04,-24.72 -24.72,-24.72h-54.13c-13.6,0 -24.72,11.04 -24.72,24.72s11.04,24.72 24.72,24.72zM347.2,691.71L293.07,691.71c-13.6,0 -24.72,11.04 -24.72,24.72 0,13.6 11.04,24.72 24.72,24.72h54.13c13.6,0 24.72,-11.04 24.72,-24.72s-11.04,-24.72 -24.72,-24.72zM544.14,691.71L490,691.71c-13.6,0 -24.72,11.04 -24.72,24.72 0,13.6 11.04,24.72 24.72,24.72h54.13c13.6,0 24.72,-11.04 24.72,-24.72 -0.08,-13.68 -11.12,-24.72 -24.72,-24.72zM740.98,691.71h-54.14c-13.6,0 -24.72,11.04 -24.72,24.72 0,13.6 11.04,24.72 24.72,24.72h54.13c13.6,0 24.72,-11.04 24.72,-24.72s-11.04,-24.72 -24.72,-24.72z" /> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="200dp" |
||||
android:height="200dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M698.98,181.33c-136.41,-141.54 -357.56,-141.54 -493.97,0 -136.41,141.57 -136.41,371.1 0,512.65l246.99,254.87 246.99,-254.87c136.41,-141.54 136.41,-371.08 0,-512.65zM451.99,533.84a109.18,109.18 0,0 1,-109.16 -109.22,109.2 109.2,0 0,1 109.16,-109.22 109.2,109.2 0,0 1,109.16 109.22,109.2 109.2,0 0,1 -109.16,109.22z" /> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="200dp" |
||||
android:height="200dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M235.95,472.94l-45.23,45.31 210.09,209.51 432.36,-427.69 -45.01,-45.48 -387.16,382.98z" /> |
||||
</vector> |
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="apply_act_menu">申请活动</string> |
||||
<string name="set_exam_menu">设置题库</string> |
||||
<string name="rename_menu">社团命名</string> |
||||
<string name="join_association">申请入团</string> |
||||
<string name="update_exam">更新题库</string> |
||||
<string name="post_answer">提交答案</string> |
||||
<string name="denined_photo_permission">相册权限请求失败,无法读取相册</string> |
||||
<string name="denined_location_permission">部分权限请求失败,无法获取地理位置</string> |
||||
<string name="at">在</string> |
||||
<string name="city">城市</string> |
||||
<string name="address">地点</string> |
||||
<string name="incity">市内找</string> |
||||
</resources> |
@ -1,16 +0,0 @@ |
||||
<resources xmlns:tools="http://schemas.android.com/tools"> |
||||
<!-- Base application theme. --> |
||||
<style name="Theme.CSAMS" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> |
||||
<!-- Primary brand color. --> |
||||
<item name="colorPrimary">@color/purple_200</item> |
||||
<item name="colorPrimaryVariant">@color/purple_700</item> |
||||
<item name="colorOnPrimary">@color/black</item> |
||||
<!-- Secondary brand color. --> |
||||
<item name="colorSecondary">@color/teal_200</item> |
||||
<item name="colorSecondaryVariant">@color/teal_200</item> |
||||
<item name="colorOnSecondary">@color/black</item> |
||||
<!-- Status bar color. --> |
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> |
||||
<!-- Customize your theme here. --> |
||||
</style> |
||||
</resources> |
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="apply_act_menu">申请活动</string> |
||||
<string name="set_exam_menu">设置题库</string> |
||||
<string name="rename_menu">社团命名</string> |
||||
<string name="join_association">申请入团</string> |
||||
<string name="update_exam">更新题库</string> |
||||
<string name="post_answer">提交答案</string> |
||||
<string name="denined_photo_permission">相册权限请求失败,无法读取相册</string> |
||||
<string name="denined_location_permission">部分权限请求失败,无法获取地理位置</string> |
||||
<string name="at">在</string> |
||||
<string name="city">城市</string> |
||||
<string name="address">地点</string> |
||||
<string name="incity">市内找</string> |
||||
</resources> |
@ -1,3 +1,15 @@ |
||||
<resources> |
||||
|
||||
<string name="apply_act_menu">申请活动</string> |
||||
<string name="set_exam_menu">设置题库</string> |
||||
<string name="rename_menu">社团命名</string> |
||||
<string name="join_association">申请入团</string> |
||||
<string name="update_exam">更新题库</string> |
||||
<string name="post_answer">提交答案</string> |
||||
<string name="denined_photo_permission">相册权限请求失败,无法读取相册</string> |
||||
<string name="denined_location_permission">部分权限请求失败,无法获取地理位置</string> |
||||
<string name="at">在</string> |
||||
<string name="city">城市</string> |
||||
<string name="address">地点</string> |
||||
<string name="incity">市内找</string> |
||||
</resources> |
Binary file not shown.
@ -1,4 +1,3 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest package="com.gyf.lib"> |
||||
|
||||
</manifest> |
@ -0,0 +1,41 @@ |
||||
package com.gyf.lib.util |
||||
|
||||
import android.app.Activity |
||||
import androidx.annotation.StringRes |
||||
import androidx.compose.foundation.background |
||||
import androidx.compose.foundation.layout.Arrangement |
||||
import androidx.compose.foundation.layout.Row |
||||
import androidx.compose.foundation.layout.Spacer |
||||
import androidx.compose.foundation.layout.width |
||||
import androidx.compose.material.MaterialTheme |
||||
import androidx.compose.material.OutlinedButton |
||||
import androidx.compose.material.Text |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.platform.LocalContext |
||||
import androidx.compose.ui.unit.dp |
||||
import com.gyf.lib.R |
||||
|
||||
@Composable |
||||
fun BottomButton( |
||||
modifier: Modifier = Modifier, |
||||
@StringRes confirmDesc: Int = R.string.confirm_btn, |
||||
@StringRes backDesc: Int = R.string.back_btn, |
||||
onConfirm: () -> Unit |
||||
) { |
||||
val context = LocalContext.current as Activity |
||||
Row(modifier = modifier, horizontalArrangement = Arrangement.Center) { |
||||
OutlinedButton( |
||||
onClick = onConfirm, |
||||
modifier = Modifier.background(color = MaterialTheme.colors.primary) |
||||
) { |
||||
Text(text = context.getString(confirmDesc)) |
||||
} |
||||
Spacer(modifier = Modifier.width(10.dp)) |
||||
OutlinedButton(onClick = { |
||||
context.onBackPressed() |
||||
}, modifier = Modifier.background(color = MaterialTheme.colors.secondary)) { |
||||
Text(text = context.getString(backDesc)) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<integer name="activity_size">20</integer> |
||||
</resources> |
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="activity_application">活动申请书</string> |
||||
<string name="activity_name">活动名称</string> |
||||
<string name="activity_time">活动时间</string> |
||||
<string name="confirm_btn">提交</string> |
||||
<string name="back_btn">返回</string> |
||||
<string name="reg_btn">注册</string> |
||||
<string name="activity_address">活动地点</string> |
||||
<string name="activity_size">活动人数</string> |
||||
<string name="activity_size_error">活动人数要在%1d到%2d之间</string> |
||||
<string name="activity_desc">活动介绍</string> |
||||
<string name="search_btn">检索</string> |
||||
<string name="search_null">未找到结果</string> |
||||
</resources> |
@ -0,0 +1,4 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<integer name="activity_size">20</integer> |
||||
</resources> |
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="activity_application">活动申请书</string> |
||||
<string name="activity_name">活动名称</string> |
||||
<string name="activity_time">活动时间</string> |
||||
<string name="confirm_btn">提交</string> |
||||
<string name="back_btn">返回</string> |
||||
<string name="reg_btn">注册</string> |
||||
<string name="activity_address">活动地点</string> |
||||
<string name="activity_size">活动人数</string> |
||||
<string name="activity_size_error">活动人数要在%1d到%2d之间</string> |
||||
<string name="activity_desc">活动介绍</string> |
||||
<string name="search_btn">检索</string> |
||||
<string name="search_null">未找到结果</string> |
||||
</resources> |
@ -0,0 +1,4 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<integer name="activity_size">20</integer> |
||||
</resources> |
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="activity_application">活动申请书</string> |
||||
<string name="activity_name">活动名称</string> |
||||
<string name="activity_time">活动时间</string> |
||||
<string name="confirm_btn">提交</string> |
||||
<string name="back_btn">返回</string> |
||||
<string name="reg_btn">注册</string> |
||||
<string name="activity_address">活动地点</string> |
||||
<string name="activity_size">活动人数</string> |
||||
<string name="activity_size_error">活动人数要在%1d到%2d之间</string> |
||||
<string name="activity_desc">活动介绍</string> |
||||
<string name="search_btn">检索</string> |
||||
<string name="search_null">未找到结果</string> |
||||
</resources> |
Loading…
Reference in new issue