feat: 增加联系人增删改查
This commit is contained in:
@@ -20,7 +20,7 @@ android {
|
||||
applicationId "com.ttstd.dialer"
|
||||
|
||||
//There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature.
|
||||
minSdkVersion 23
|
||||
// minSdkVersion 23
|
||||
targetSdkVersion 37
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@@ -95,6 +95,21 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "version"
|
||||
productFlavors {
|
||||
// 用于正常开发和发布的版本
|
||||
normal {
|
||||
dimension "version"
|
||||
minSdkVersion 23 // 你的原始最低版本
|
||||
}
|
||||
// 专门用于调试高版本特性的版本
|
||||
debugApi26 {
|
||||
dimension "version"
|
||||
minSdkVersion 31 // 为了使用 Database Inspector
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
signingConfigs {
|
||||
keypub {
|
||||
storeFile file(rootProject.ext.signingConfigs.keypub.storeFile)
|
||||
@@ -194,9 +209,9 @@ dependencies {
|
||||
implementation project(path: ':iconloader')
|
||||
|
||||
// 添加 Kotlin 标准库
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.10"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
// 添加这行,使用 BOM 统一 Kotlin 相关库的版本
|
||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.2.10"))
|
||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom:$kotlin_version"))
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-rx3:1.11.0'
|
||||
@@ -230,7 +245,9 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
|
||||
|
||||
implementation 'com.google.android.material:material:1.13.0'
|
||||
implementation 'com.google.android.material:material:1.14.0'
|
||||
implementation 'com.googlecode.libphonenumber:libphonenumber:9.0.30'
|
||||
|
||||
//glide
|
||||
implementation 'com.github.bumptech.glide:glide:4.15.1'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.15.1'
|
||||
@@ -242,12 +259,13 @@ dependencies {
|
||||
//RxJava
|
||||
implementation 'io.reactivex.rxjava3:rxjava:3.1.12'
|
||||
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
|
||||
//
|
||||
|
||||
implementation 'com.squareup.moshi:moshi:1.15.2'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.3.2'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.3.2'
|
||||
implementation 'com.squareup.retrofit2:retrofit:3.0.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:3.0.0'
|
||||
// implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
|
||||
// implementation 'com.squareup.retrofit2:adapter-rxjava2:3.0.0'
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava3:3.0.0"
|
||||
//Gson
|
||||
implementation 'com.google.code.gson:gson:2.14.0'
|
||||
@@ -262,7 +280,8 @@ dependencies {
|
||||
|
||||
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
|
||||
/*https://github.com/JeremyLiao/LiveEventBus*/
|
||||
implementation 'com.jeremyliao:live-event-bus-x:1.7.3'
|
||||
// implementation 'io.github.jeremyliao:live-event-bus:1.8.0'
|
||||
implementation 'com.github.neo-turak:LiveEventBus:1.8.1'
|
||||
|
||||
implementation 'com.facebook.rebound:rebound:0.3.8'
|
||||
//MMKV
|
||||
@@ -344,10 +363,8 @@ dependencies {
|
||||
implementation 'com.github.getActivity:Toaster:12.6'
|
||||
// 权限请求框架:https://github.com/getActivity/XXPermissions
|
||||
implementation 'com.github.getActivity:XXPermissions:20.0'
|
||||
//autosize会改变第三方view的大小
|
||||
//https://github.com/JessYanCoding/AndroidAutoSize
|
||||
// implementation 'me.jessyan:autosize:1.2.1'
|
||||
|
||||
implementation 'com.github.zcweng:switch-button:0.0.3@aar'
|
||||
implementation "com.github.kongzue.DialogX:DialogX:0.0.50"
|
||||
}
|
||||
|
||||
// 在 dependencies 之后添加
|
||||
|
||||
@@ -80,6 +80,10 @@
|
||||
android:name=".activity.contact.list.ContactListActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".activity.contact.test.ContactTestActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".activity.app.AppListActivity"
|
||||
android:launchMode="singleTask"
|
||||
|
||||
@@ -5,10 +5,14 @@ import android.view.View;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.databinding.ActivityContactAddBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.filter.NoSpaceInputFilter;
|
||||
import com.ttstd.dialer.mdm.DeviceManagerService;
|
||||
import com.ttstd.dialer.utils.PhoneUtils;
|
||||
|
||||
public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, ActivityContactAddBinding> {
|
||||
|
||||
@@ -39,18 +43,30 @@ public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, Ac
|
||||
protected void initView() {
|
||||
mViewDataBinding.etName.setFilters(new InputFilter[]{new NoSpaceInputFilter()});
|
||||
mViewDataBinding.etPhone.setFilters(new InputFilter[]{new NoSpaceInputFilter()});
|
||||
mViewDataBinding.etRemark.setFilters(new InputFilter[]{new NoSpaceInputFilter()});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mIntegerMutableLiveData.observe(this, new Observer<Long>() {
|
||||
mViewModel.mOnlineIdData.observe(this, new Observer<Long>() {
|
||||
@Override
|
||||
public void onChanged(Long aLong) {
|
||||
if (aLong > 0) {
|
||||
Toaster.show("添加成功");
|
||||
finish();
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
mViewModel.mDbIdData.observe(this, new Observer<Long>() {
|
||||
@Override
|
||||
public void onChanged(Long aLong) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
@@ -59,9 +75,53 @@ public class ContactAddActivity extends BaseMvvmActivity<ContactAddViewModel, Ac
|
||||
}
|
||||
|
||||
public void save(View view) {
|
||||
if (mViewDataBinding.etName.getText() == null) {
|
||||
Toaster.show("请输入姓名");
|
||||
return;
|
||||
}
|
||||
String name = mViewDataBinding.etName.getText().toString();
|
||||
|
||||
if (mViewDataBinding.etPhone.getText() == null) {
|
||||
Toaster.show("请输入手机号码");
|
||||
return;
|
||||
}
|
||||
|
||||
String phone = mViewDataBinding.etPhone.getText().toString();
|
||||
|
||||
if (!PhoneUtils.isValidPhone(phone)) {
|
||||
Toaster.show("手机号码格式错误");
|
||||
return;
|
||||
}
|
||||
|
||||
ContactInfo contactInfo = new ContactInfo();
|
||||
contactInfo.setName(name);
|
||||
contactInfo.setPhoneNumber(phone);
|
||||
if (mViewDataBinding.etRemark.getText() != null) {
|
||||
String remark = mViewDataBinding.etRemark.getText().toString();
|
||||
contactInfo.setNickName(remark);
|
||||
}
|
||||
contactInfo.setEmergency(mViewDataBinding.sbEmergency.isChecked());
|
||||
contactInfo.setShowDesktop(mViewDataBinding.sbShow.isChecked());
|
||||
contactInfo.setCreateTime(System.currentTimeMillis());
|
||||
contactInfo.setUpdateTime(System.currentTimeMillis());
|
||||
mViewModel.addContact(contactInfo);
|
||||
|
||||
}
|
||||
|
||||
public void saveLocalDb(View view) {
|
||||
String name = mViewDataBinding.etName.getText().toString();
|
||||
String phone = mViewDataBinding.etPhone.getText().toString();
|
||||
mViewModel.saveContact(name, phone);
|
||||
String remark = mViewDataBinding.etRemark.getText().toString();
|
||||
ContactInfo contactInfo = new ContactInfo();
|
||||
contactInfo.setName(name);
|
||||
contactInfo.setPhoneNumber(phone);
|
||||
contactInfo.setNickName(remark);
|
||||
contactInfo.setEmergency(mViewDataBinding.sbEmergency.isChecked());
|
||||
contactInfo.setShowDesktop(mViewDataBinding.sbShow.isChecked());
|
||||
contactInfo.setBindSn(DeviceManagerService.getInstance().getSerial());
|
||||
contactInfo.setCreateTime(System.currentTimeMillis());
|
||||
contactInfo.setUpdateTime(System.currentTimeMillis());
|
||||
mViewModel.saveContact(contactInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.ActivityContactAddBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.ObservableEmitter;
|
||||
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
@@ -25,27 +25,77 @@ public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding
|
||||
private static final String TAG = "ContactAddViewModel";
|
||||
private ContactRepository mRepository;
|
||||
|
||||
public MutableLiveData<Long> mOnlineIdData = new MutableLiveData<>();
|
||||
public MutableLiveData<Long> mDbIdData = new MutableLiveData<>();
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new ContactRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<Long> mIntegerMutableLiveData = new MutableLiveData<>();
|
||||
|
||||
public void saveContact(String name, String phone) {
|
||||
Observable.create(new ObservableOnSubscribe<Long>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Long> emitter) throws Throwable {
|
||||
int count = mRepository.getTotalCount() + 1;
|
||||
ContactInfo contactInfo = new ContactInfo(name, phone, count);
|
||||
Logger.e(TAG, "saveContact: " + contactInfo);
|
||||
emitter.onNext(mRepository.insert(contactInfo));
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
public void addContact(ContactInfo contactInfo) {
|
||||
OkHttpManager.getInstance().getContactInsertObservable(contactInfo, getLifecycle())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.flatMap(baseResponse -> {
|
||||
Logger.e(TAG, "addContact", "网络请求响应: " + baseResponse);
|
||||
if (baseResponse.isSuccess()) {
|
||||
Long id = baseResponse.getData();
|
||||
mOnlineIdData.setValue(id);
|
||||
return Observable.just(id);
|
||||
} else {
|
||||
Logger.w(TAG, "业务失败,降级到本地保存: " + baseResponse.getMsg());
|
||||
return saveContactObservable(contactInfo);
|
||||
}
|
||||
})
|
||||
.onErrorResumeNext(throwable -> {
|
||||
Logger.e(TAG, "网络异常,降级到本地保存: " + throwable.getMessage());
|
||||
return saveContactObservable(contactInfo);
|
||||
})
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new Observer<Long>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.d(TAG, "开始添加联系人");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull Long id) {
|
||||
Logger.d(TAG, "联系人保存成功,ID: " + id);
|
||||
if (mOnlineIdData.getValue() == null) {
|
||||
mDbIdData.setValue(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "添加联系人最终失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.d(TAG, "添加联系人流程完成");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Observable<Long> saveContactObservable(ContactInfo contactInfo) {
|
||||
return Observable.create((ObservableOnSubscribe<Long>) emitter -> {
|
||||
Logger.d(TAG, "执行本地保存: " + contactInfo);
|
||||
contactInfo.setPosition(mRepository.getTotalCount() + 1);
|
||||
contactInfo.setLocalId(System.currentTimeMillis());
|
||||
long id = mRepository.insert(contactInfo);
|
||||
Logger.d(TAG, "执行本地保存: id = " + id);
|
||||
emitter.onNext(id);
|
||||
emitter.onComplete();
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
public void saveContact(ContactInfo contactInfo) {
|
||||
saveContactObservable(contactInfo)
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<Long>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
@@ -55,7 +105,7 @@ public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding
|
||||
@Override
|
||||
public void onNext(@NonNull Long aLong) {
|
||||
Logger.e("saveContact", "onNext: " + aLong);
|
||||
mIntegerMutableLiveData.setValue(aLong);
|
||||
mDbIdData.setValue(aLong);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,5 +119,4 @@ public class ContactAddViewModel extends BaseViewModel<ActivityContactAddBinding
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
package com.ttstd.dialer.activity.contact.edit;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.databinding.ActivityContactEditBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.AvatarCacheUtil;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
import com.ttstd.dialer.utils.PhoneUtils;
|
||||
|
||||
public class ContactEditActivity extends BaseMvvmActivity<ContactEditViewModel, ActivityContactEditBinding> {
|
||||
private ContactInfo mContactInfo;
|
||||
|
||||
@Override
|
||||
public boolean setNightMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setfitWindow() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.activity_contact_edit;
|
||||
@@ -33,15 +47,65 @@ public class ContactEditActivity extends BaseMvvmActivity<ContactEditViewModel,
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
|
||||
Intent intent = getIntent();
|
||||
mContactInfo = (ContactInfo) intent.getSerializableExtra("ContactInfo");
|
||||
if (mContactInfo == null) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
mViewDataBinding.setContactInfo(mContactInfo);
|
||||
GlideUtils.loadImageSafe(ContactEditActivity.this, mContactInfo.getAvatar(), mViewDataBinding.nvAvatar, AvatarCacheUtil.getAvatar(ContactEditActivity.this, mContactInfo.getName()));
|
||||
mViewModel.mBooleanMutableLiveData.observe(this, new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(Boolean aBoolean) {
|
||||
if (aBoolean) {
|
||||
Toaster.show("编辑成功");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class BtnClick{
|
||||
public class BtnClick {
|
||||
public void exit(View view) {
|
||||
finish();
|
||||
}
|
||||
|
||||
public void update(View view) {
|
||||
ContactInfo contactInfo = new ContactInfo(mContactInfo);
|
||||
if (mViewDataBinding.etName.getText() == null) {
|
||||
Toaster.show("请输入姓名");
|
||||
return;
|
||||
}
|
||||
String name = mViewDataBinding.etName.getText().toString();
|
||||
|
||||
if (mViewDataBinding.etPhone.getText() == null) {
|
||||
Toaster.show("请输入手机号码");
|
||||
return;
|
||||
}
|
||||
|
||||
String phone = mViewDataBinding.etPhone.getText().toString();
|
||||
|
||||
if (!PhoneUtils.isValidPhone(phone)) {
|
||||
Toaster.show("手机号码格式错误");
|
||||
return;
|
||||
}
|
||||
|
||||
contactInfo.setName(name);
|
||||
contactInfo.setPhoneNumber(phone);
|
||||
if (mViewDataBinding.etRemark.getText() != null) {
|
||||
String remark = mViewDataBinding.etRemark.getText().toString();
|
||||
contactInfo.setNickName(remark);
|
||||
} else {
|
||||
contactInfo.setNickName("");
|
||||
}
|
||||
contactInfo.setEmergency(mViewDataBinding.sbEmergency.isChecked());
|
||||
contactInfo.setShowDesktop(mViewDataBinding.sbShow.isChecked());
|
||||
contactInfo.setUpdateTime(System.currentTimeMillis());
|
||||
|
||||
mViewModel.updateContact(mContactInfo.getId(), contactInfo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,42 @@
|
||||
package com.ttstd.dialer.activity.contact.edit;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.databinding.ActivityContactEditBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.network.BaseObserver;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
|
||||
public class ContactEditViewModel extends BaseViewModel <ActivityContactEditBinding, ActivityEvent>{
|
||||
public class ContactEditViewModel extends BaseViewModel<ActivityContactEditBinding, ActivityEvent> {
|
||||
|
||||
public MutableLiveData<Boolean> mBooleanMutableLiveData = new MutableLiveData<>();
|
||||
|
||||
public void updateContact(long id, ContactInfo contactInfo) {
|
||||
OkHttpManager.getInstance().getContactUpdateObservable(id, contactInfo, getLifecycle())
|
||||
.safeSubscribe(new BaseObserver<BaseResponse<Void>>() {
|
||||
@Override
|
||||
public void onSuccess(BaseResponse<Void> baseResponse) {
|
||||
Log.e("updateContact", "onSuccess: " + baseResponse);
|
||||
if (baseResponse.isSuccess()) {
|
||||
mBooleanMutableLiveData.postValue(true);
|
||||
} else {
|
||||
mBooleanMutableLiveData.postValue(false);
|
||||
Toaster.show(baseResponse.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
Log.e("updateContact", "onFailure: " + e.getMessage());
|
||||
mBooleanMutableLiveData.postValue(false);
|
||||
Toaster.show("网络错误,请稍后再试");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,21 @@ import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.kongzue.dialogx.dialogs.TipDialog;
|
||||
import com.kongzue.dialogx.dialogs.WaitDialog;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.activity.contact.add.ContactAddActivity;
|
||||
import com.ttstd.dialer.activity.contact.edit.ContactEditActivity;
|
||||
import com.ttstd.dialer.activity.contact.test.ContactTestActivity;
|
||||
import com.ttstd.dialer.adapter.ContactInfoAdapter;
|
||||
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.databinding.ActivityContactListBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.fragment.dialog.call.CallFragment;
|
||||
import com.ttstd.dialer.fragment.dialog.contact.call.CallFragment;
|
||||
import com.ttstd.dialer.fragment.dialog.contact.delete.ContactDeleteDialogFragment;
|
||||
import com.ttstd.dialer.fragment.dialog.contact.edit.EditDialogFragment;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.view.ItemTouchHelperCallback;
|
||||
|
||||
@@ -29,6 +36,9 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
private ContactInfoAdapter mContactInfoAdapter;
|
||||
|
||||
private List<ContactInfo> mContactInfos;
|
||||
private EditDialogFragment mEditDialogFragment;
|
||||
private ContactDeleteDialogFragment mContactDeleteDialogFragment;
|
||||
;
|
||||
|
||||
@Override
|
||||
public boolean setNightMode() {
|
||||
@@ -55,6 +65,13 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
mViewDataBinding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
mViewDataBinding.swipeRefreshLayout.setRefreshing(true);
|
||||
mViewModel.getAllContacts();
|
||||
}
|
||||
});
|
||||
mContactInfoAdapter = new ContactInfoAdapter();
|
||||
mContactInfoAdapter.setItemMoveCallback(new ContactInfoAdapter.ItemMoveCallback() {
|
||||
@Override
|
||||
@@ -76,12 +93,50 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
|
||||
}
|
||||
});
|
||||
mContactInfoAdapter.setOnClickListener(new ContactInfoAdapter.OnClickListener() {
|
||||
mContactInfoAdapter.setOnClickListener(new ContactInfoAdapter.ClickListener() {
|
||||
@Override
|
||||
public void onClick(ContactInfo contactInfo) {
|
||||
new CallFragment(contactInfo).show(getSupportFragmentManager(), "CallFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoreOperationClick(ContactInfo contactInfo) {
|
||||
mEditDialogFragment = new EditDialogFragment(contactInfo);
|
||||
mEditDialogFragment.setContactOperateListener(new EditDialogFragment.ContactOperationListener() {
|
||||
@Override
|
||||
public void onContactEdit(ContactInfo contactInfo) {
|
||||
Intent intent = new Intent(ContactListActivity.this, ContactEditActivity.class);
|
||||
intent.putExtra("ContactInfo", contactInfo);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactDelete(ContactInfo contactInfo) {
|
||||
mContactDeleteDialogFragment = new ContactDeleteDialogFragment(contactInfo);
|
||||
mContactDeleteDialogFragment.setContactOperateListener(new ContactDeleteDialogFragment.ContactOperationListener() {
|
||||
@Override
|
||||
public void onCancel(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(ContactInfo contactInfo) {
|
||||
WaitDialog.show("正在删除联系人...");
|
||||
mViewModel.deleteContact(contactInfo.getId());
|
||||
}
|
||||
});
|
||||
mContactDeleteDialogFragment.show(getSupportFragmentManager(), "ContactDeleteDialogFragment");
|
||||
}
|
||||
});
|
||||
mEditDialogFragment.show(getSupportFragmentManager(), "EditDialogFragment");
|
||||
}
|
||||
});
|
||||
|
||||
// 设置ItemTouchHelper,实现拖动和滑动删除
|
||||
ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mContactInfoAdapter);
|
||||
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
|
||||
@@ -98,9 +153,25 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
Logger.e(TAG, "mContactListData: " + contactInfos);
|
||||
mContactInfos = contactInfos;
|
||||
mContactInfoAdapter.setContactInfos(mContactInfos);
|
||||
mViewDataBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
if (contactInfos == null) {
|
||||
|
||||
} else {
|
||||
Logger.e(TAG, "mContactListData: " + contactInfos);
|
||||
mContactInfos = contactInfos;
|
||||
mContactInfoAdapter.setContactInfos(mContactInfos);
|
||||
}
|
||||
}
|
||||
});
|
||||
mViewModel.mDeleteLiveData.observe(this, new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(Boolean aBoolean) {
|
||||
if (aBoolean) {
|
||||
TipDialog.show("删除成功", WaitDialog.TYPE.SUCCESS);
|
||||
mViewModel.getAllContacts();
|
||||
} else {
|
||||
TipDialog.show("删除失败", WaitDialog.TYPE.ERROR);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -139,9 +210,13 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
public void exit(View view) {
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
public void addContact(View view) {
|
||||
startActivity(new Intent(ContactListActivity.this, ContactAddActivity.class));
|
||||
}
|
||||
|
||||
public void testContact(View view) {
|
||||
startActivity(new Intent(ContactListActivity.this, ContactTestActivity.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,13 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.databinding.ActivityContactListBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.manager.ContactManager;
|
||||
import com.ttstd.dialer.network.BaseObserver;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
@@ -26,24 +30,67 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
public class ContactListViewModel extends BaseViewModel<ActivityContactListBinding, ActivityEvent> {
|
||||
private static final String TAG = "ContactListViewModel";
|
||||
private ContactRepository mRepository;
|
||||
private ContactManager mContactManager;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new ContactRepository(context);
|
||||
mContactManager = ContactManager.getInstance(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContacts() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
mContactManager.getContacts(getLifecycle(), new ContactManager.ContactCallback() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
public void onSuccess(List<ContactInfo> contacts) {
|
||||
Logger.e(TAG, "获取联系人成功: " + contacts.size());
|
||||
mContactListData.setValue(contacts);
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
Logger.e(TAG, "获取联系人失败: " + e.getMessage());
|
||||
mContactListData.setValue(null);
|
||||
}
|
||||
});
|
||||
|
||||
// OkHttpManager.getInstance().getContactListObservable(getLifecycle())
|
||||
// .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
// .subscribe(new BaseObserver<BaseResponse<List<ContactInfo>>>() {
|
||||
// @Override
|
||||
// public void onSuccess(BaseResponse<List<ContactInfo>> listBaseResponse) {
|
||||
// Log.e("getAllContacts", "onSuccess: " + listBaseResponse);
|
||||
// if (listBaseResponse.isSuccess()) {
|
||||
// List<ContactInfo> contactInfos = listBaseResponse.getData();
|
||||
// List<ContactInfo> sorted = contactInfos.stream().sorted(new Comparator<ContactInfo>() {
|
||||
// @Override
|
||||
// public int compare(ContactInfo t0, ContactInfo t1) {
|
||||
// return Integer.compare(t0.getPosition(), t1.getPosition());
|
||||
// }
|
||||
// }).collect(Collectors.toList());
|
||||
// mContactListData.setValue(sorted);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(Throwable e) {
|
||||
// Log.e("getAllContacts", "onFailure: " + e.getMessage());
|
||||
// mContactListData.setValue(null);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private void getAllContactsFromDB() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@@ -55,7 +102,7 @@ public class ContactListViewModel extends BaseViewModel<ActivityContactListBindi
|
||||
@Override
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Logger.e("getAllContacts", "onNext: ");
|
||||
mContactListData.setValue(contactInfos);
|
||||
// mContactListData.setValue(contactInfos);
|
||||
|
||||
// List<Contact> sorted = contacts.stream().sorted(new Comparator<Contact>() {
|
||||
// @Override
|
||||
@@ -81,13 +128,13 @@ public class ContactListViewModel extends BaseViewModel<ActivityContactListBindi
|
||||
public void updateItemPosition(ContactInfo contactInfo) {
|
||||
Logger.e(TAG, "updateItemPosition: " + contactInfo);
|
||||
Observable.create(new ObservableOnSubscribe<Integer>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
|
||||
int id = mRepository.update(contactInfo);
|
||||
emitter.onNext(id);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
|
||||
int id = mRepository.update(contactInfo);
|
||||
emitter.onNext(id);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@@ -113,4 +160,22 @@ public class ContactListViewModel extends BaseViewModel<ActivityContactListBindi
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> mDeleteLiveData = new MutableLiveData<>();
|
||||
|
||||
public void deleteContact(long id) {
|
||||
OkHttpManager.getInstance().getContactDeleteObservable(id, getLifecycle())
|
||||
.safeSubscribe(new BaseObserver<BaseResponse>() {
|
||||
@Override
|
||||
public void onSuccess(BaseResponse baseResponse) {
|
||||
Logger.e("deleteContact", "onSuccess: " + baseResponse);
|
||||
mDeleteLiveData.setValue(baseResponse.isSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
Logger.e("deleteContact", "onFailure: " + e.getMessage());
|
||||
mDeleteLiveData.setValue(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
package com.ttstd.dialer.activity.contact.test;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.activity.contact.add.ContactAddActivity;
|
||||
import com.ttstd.dialer.adapter.ContactInfoAdapter;
|
||||
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.databinding.ActivityContactTestBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.fragment.dialog.contact.call.CallFragment;
|
||||
import com.ttstd.dialer.manager.ContactManager;
|
||||
import com.ttstd.dialer.manager.ContactSyncManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.view.ItemTouchHelperCallback;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ContactTestActivity extends BaseMvvmActivity<ContactTestViewModel, ActivityContactTestBinding> {
|
||||
|
||||
private static final String TAG = "ContactTestActivity";
|
||||
private static final int REQUEST_CODE_CALL = 7897;
|
||||
|
||||
private ContactInfoAdapter mOnlineContactInfoAdapter;
|
||||
private ContactInfoAdapter mLocalContactInfoAdapter;
|
||||
|
||||
private List<ContactInfo> mOnlineContactInfos;
|
||||
private List<ContactInfo> mLocalContactInfos;
|
||||
|
||||
@Override
|
||||
public boolean setNightMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setfitWindow() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.activity_contact_test;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataBinding() {
|
||||
mViewModel.setContext(this);
|
||||
mViewModel.setVDBinding(mViewDataBinding);
|
||||
mViewModel.setLifecycle(getLifecycleSubject());
|
||||
mViewDataBinding.setClick(new BtnClick());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
mOnlineContactInfoAdapter = new ContactInfoAdapter();
|
||||
mOnlineContactInfoAdapter.setItemMoveCallback(new ContactInfoAdapter.ItemMoveCallback() {
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Logger.e(TAG, "mOnlineContactInfoAdapter onItemMove: ");
|
||||
ContactInfo fromContactInfo = mOnlineContactInfos.get(fromPosition);
|
||||
int fromContactPosition = fromContactInfo.getPosition();
|
||||
ContactInfo toContactInfo = mOnlineContactInfos.get(toPosition);
|
||||
int toContactPosition = toContactInfo.getPosition();
|
||||
fromContactInfo.setPosition(toContactPosition);
|
||||
mViewModel.updateItemPosition(fromContactInfo);
|
||||
toContactInfo.setPosition(fromContactPosition);
|
||||
mViewModel.updateItemPosition(toContactInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRemoved(int position) {
|
||||
Logger.e(TAG, "mOnlineContactInfoAdapter onItemRemoved: ");
|
||||
|
||||
}
|
||||
});
|
||||
mOnlineContactInfoAdapter.setOnClickListener(new ContactInfoAdapter.ClickListener() {
|
||||
@Override
|
||||
public void onClick(ContactInfo contactInfo) {
|
||||
new CallFragment(contactInfo).show(getSupportFragmentManager(), "CallFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoreOperationClick(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
});
|
||||
// 设置ItemTouchHelper,实现拖动和滑动删除
|
||||
ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mOnlineContactInfoAdapter);
|
||||
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
|
||||
touchHelper.attachToRecyclerView(mViewDataBinding.rvOnline);
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
|
||||
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
mViewDataBinding.rvOnline.setLayoutManager(linearLayoutManager);
|
||||
mViewDataBinding.rvOnline.setAdapter(mOnlineContactInfoAdapter);
|
||||
|
||||
mLocalContactInfoAdapter = new ContactInfoAdapter();
|
||||
mLocalContactInfoAdapter.setItemMoveCallback(new ContactInfoAdapter.ItemMoveCallback() {
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Logger.e(TAG, "mLocalContactInfoAdapter onItemMove: ");
|
||||
ContactInfo fromContactInfo = mOnlineContactInfos.get(fromPosition);
|
||||
int fromContactPosition = fromContactInfo.getPosition();
|
||||
ContactInfo toContactInfo = mOnlineContactInfos.get(toPosition);
|
||||
int toContactPosition = toContactInfo.getPosition();
|
||||
fromContactInfo.setPosition(toContactPosition);
|
||||
mViewModel.updateItemPosition(fromContactInfo);
|
||||
toContactInfo.setPosition(fromContactPosition);
|
||||
mViewModel.updateItemPosition(toContactInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRemoved(int position) {
|
||||
Logger.e(TAG, "mLocalContactInfoAdapter onItemRemoved: ");
|
||||
|
||||
}
|
||||
});
|
||||
mLocalContactInfoAdapter.setOnClickListener(new ContactInfoAdapter.ClickListener() {
|
||||
@Override
|
||||
public void onClick(ContactInfo contactInfo) {
|
||||
new CallFragment(contactInfo).show(getSupportFragmentManager(), "CallFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoreOperationClick(ContactInfo contactInfo) {
|
||||
|
||||
}
|
||||
});
|
||||
// 设置ItemTouchHelper,实现拖动和滑动删除
|
||||
ItemTouchHelper.Callback callbackLocal = new ItemTouchHelperCallback(mLocalContactInfoAdapter);
|
||||
ItemTouchHelper touchHelperLocal = new ItemTouchHelper(callbackLocal);
|
||||
touchHelperLocal.attachToRecyclerView(mViewDataBinding.rvLocal);
|
||||
|
||||
LinearLayoutManager linearLayoutManagerLocal = new LinearLayoutManager(this);
|
||||
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
mViewDataBinding.rvLocal.setLayoutManager(linearLayoutManagerLocal);
|
||||
mViewDataBinding.rvLocal.setAdapter(mLocalContactInfoAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mOnlineContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
if (contactInfos == null) {
|
||||
|
||||
} else {
|
||||
mViewDataBinding.tvOnline.setText("在线联系人:" + contactInfos.size() + "个");
|
||||
Logger.e(TAG, "mOnlineContactListData: " + contactInfos);
|
||||
mOnlineContactInfos = contactInfos;
|
||||
mOnlineContactInfoAdapter.setContactInfos(mOnlineContactInfos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mLocalContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
if (contactInfos == null) {
|
||||
|
||||
} else {
|
||||
mViewDataBinding.tvLocal.setText("本地联系人:" + contactInfos.size() + "个");
|
||||
Logger.e(TAG, "mLocalContactListData: " + contactInfos);
|
||||
mLocalContactInfos = contactInfos;
|
||||
mLocalContactInfoAdapter.setContactInfos(mLocalContactInfos);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
if (requestCode == REQUEST_CODE_CALL) {
|
||||
// 检查所有权限的结果是否都已授予
|
||||
boolean allGranted = true;
|
||||
for (int result : grantResults) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
allGranted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if (allGranted) {
|
||||
// onAllPermissionsGranted(); // 权限全部获取成功
|
||||
// } else {
|
||||
// // 处理权限被拒绝的情况
|
||||
// handlePermissionDenied();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mViewModel.getAllContacts();
|
||||
mViewModel.getAllContactsFromDB();
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
public void exit(View view) {
|
||||
finish();
|
||||
}
|
||||
|
||||
public void getOnlineContact(View view) {
|
||||
mViewModel.getAllContacts();
|
||||
}
|
||||
|
||||
public void getLocalContact(View view) {
|
||||
mViewModel.getAllContactsFromDB();
|
||||
}
|
||||
|
||||
public void compareContact(View view) {
|
||||
ContactManager.getInstance(ContactTestActivity.this).compareContacts(mOnlineContactInfos, mLocalContactInfos);
|
||||
}
|
||||
|
||||
public void syncContact(View view) {
|
||||
ContactSyncManager.getInstance(ContactTestActivity.this).syncPendingContacts();
|
||||
}
|
||||
|
||||
|
||||
public void addContact(View view) {
|
||||
startActivity(new Intent(ContactTestActivity.this, ContactAddActivity.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.ttstd.dialer.activity.contact.test;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.databinding.ActivityContactTestBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.network.BaseObserver;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.ObservableEmitter;
|
||||
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class ContactTestViewModel extends BaseViewModel<ActivityContactTestBinding, ActivityEvent> {
|
||||
private static final String TAG = "ContactListViewModel";
|
||||
private ContactRepository mRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mRepository = new ContactRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mOnlineContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContacts() {
|
||||
OkHttpManager.getInstance().getContactListObservable(getLifecycle())
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new BaseObserver<BaseResponse<List<ContactInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(BaseResponse<List<ContactInfo>> listBaseResponse) {
|
||||
Log.e("getAllContacts", "onSuccess: " + listBaseResponse);
|
||||
if (listBaseResponse.isSuccess()) {
|
||||
List<ContactInfo> contactInfos = listBaseResponse.getData();
|
||||
List<ContactInfo> sorted = contactInfos.stream().sorted(new Comparator<ContactInfo>() {
|
||||
@Override
|
||||
public int compare(ContactInfo t0, ContactInfo t1) {
|
||||
return Integer.compare(t0.getPosition(), t1.getPosition());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
mOnlineContactListData.setValue(sorted);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
Log.e("getAllContacts", "onFailure: " + e.getMessage());
|
||||
mOnlineContactListData.setValue(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mLocalContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContactsFromDB() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("getAllContacts", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Logger.e("getAllContacts", "onNext: ");
|
||||
// mLocalContactListData.setValue(contactInfos);
|
||||
|
||||
List<ContactInfo> sorted = contactInfos.stream().sorted(new Comparator<ContactInfo>() {
|
||||
@Override
|
||||
public int compare(ContactInfo o1, ContactInfo o2) {
|
||||
return Integer.compare(o1.getPosition(), o2.getPosition());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
mLocalContactListData.setValue(sorted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("getAllContacts", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("getAllContacts", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateItemPosition(ContactInfo contactInfo) {
|
||||
Logger.e(TAG, "updateItemPosition: " + contactInfo);
|
||||
Observable.create(new ObservableOnSubscribe<Integer>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
|
||||
int id = mRepository.update(contactInfo);
|
||||
emitter.onNext(id);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e("updateItemPosition", "onComplete: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull Integer integer) {
|
||||
Logger.e("updateItemPosition", "onNext: " + integer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e("updateItemPosition", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e("updateItemPosition", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
@@ -35,14 +36,12 @@ import com.ttstd.dialer.wallpager.WallpaperScrollHelper;
|
||||
|
||||
import net.lucode.hackware.magicindicator.ViewPagerHelper;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope;
|
||||
import kotlinx.coroutines.CoroutineScopeKt;
|
||||
import kotlinx.coroutines.Job;
|
||||
import kotlinx.coroutines.flow.FlowKt;
|
||||
|
||||
public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBinding> {
|
||||
private static final String TAG = "MainActivity";
|
||||
@@ -94,14 +93,14 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
mViewModel.setVDBinding(mViewDataBinding);
|
||||
mViewModel.setLifecycle(getLifecycleSubject());
|
||||
mViewDataBinding.setClick(new BtnClick());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
Log.e(TAG, "initView: ");
|
||||
|
||||
weatherUpdateManager = WeatherUpdateManager.Companion.getInstance();
|
||||
observeWeatherUpdates();
|
||||
// observeWeatherUpdates();
|
||||
|
||||
showSystemWallpaperBehindActivity();
|
||||
|
||||
@@ -149,7 +148,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
mScaleCircleNavigator.setCircleClickListener(new ScaleCircleNavigator.OnCircleClickListener() {
|
||||
@Override
|
||||
public void onClick(int index) {
|
||||
mViewDataBinding.viewPager.setCurrentItem(index);
|
||||
mViewDataBinding.viewPager.setCurrentItem(index, true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -160,7 +159,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
Logger.e(TAG, "onPageScrolled: position = " + position);
|
||||
if (mCurrentIndex == -1 && position == 0) {
|
||||
mViewDataBinding.viewPager.setCurrentItem(mDefaultIndex);
|
||||
mViewDataBinding.viewPager.setCurrentItem(mDefaultIndex, true);
|
||||
mCurrentIndex = mDefaultIndex;
|
||||
} else {
|
||||
mCurrentIndex = position;
|
||||
@@ -179,7 +178,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
});
|
||||
mViewDataBinding.magicIndicator.setNavigator(mScaleCircleNavigator);
|
||||
ViewPagerHelper.bind(mViewDataBinding.magicIndicator, mViewDataBinding.viewPager);
|
||||
mViewDataBinding.viewPager.setCurrentItem(mDefaultIndex);
|
||||
mViewDataBinding.viewPager.setCurrentItem(mDefaultIndex, true);
|
||||
|
||||
Logger.e(TAG, "initView: mCurrentIndex = " + mCurrentIndex);
|
||||
Logger.e(TAG, "initView: mDefaultIndex = " + mDefaultIndex);
|
||||
@@ -200,6 +199,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
Log.e(TAG, "initData: ");
|
||||
registerReceivers();
|
||||
AppManager.getInstance().addProgressCallback(new AppManager.ProgressCallback() {
|
||||
@Override
|
||||
@@ -246,6 +246,15 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
Log.e(TAG, "onNewIntent: " + intent.getAction());
|
||||
if (Intent.ACTION_MAIN.equals(intent.getAction())) {
|
||||
mViewDataBinding.viewPager.setCurrentItem(mDefaultIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
@@ -266,33 +275,45 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
wallpaperScrollHelper.onDestroy();
|
||||
}
|
||||
|
||||
if (weatherNowJob != null) {
|
||||
weatherNowJob.cancel(null);
|
||||
}
|
||||
if (weatherHourlyJob != null) {
|
||||
weatherHourlyJob.cancel(null);
|
||||
}
|
||||
if (weatherDailyJob != null) {
|
||||
weatherDailyJob.cancel(null);
|
||||
}
|
||||
// if (weatherNowJob != null) {
|
||||
// weatherNowJob.cancel(null);
|
||||
// }
|
||||
// if (weatherHourlyJob != null) {
|
||||
// weatherHourlyJob.cancel(null);
|
||||
// }
|
||||
// if (weatherDailyJob != null) {
|
||||
// weatherDailyJob.cancel(null);
|
||||
// }
|
||||
}
|
||||
|
||||
private void observeWeatherUpdates() {
|
||||
// 观察当前天气更新
|
||||
weatherNowJob = weatherUpdateManager.observeWeatherNow(weatherScope, weatherNowResponse -> {
|
||||
if (weatherNowResponse != null) {
|
||||
Logger.e(TAG, "weatherNowResponse = " + weatherNowResponse);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
// private void observeWeatherUpdates() {
|
||||
// // 观察当前天气更新
|
||||
// weatherNowJob = weatherUpdateManager.observeWeatherNow(weatherScope, weatherNowResponse -> {
|
||||
// if (weatherNowResponse != null) {
|
||||
// Logger.e(TAG, "observeWeatherUpdates", "weatherNowResponse = " + weatherNowResponse);
|
||||
// }
|
||||
// return null;
|
||||
// });
|
||||
//
|
||||
// weatherHourlyJob = weatherUpdateManager.observeWeatherHourly(weatherScope, weatherHourlyResponse -> {
|
||||
// if (weatherHourlyResponse != null) {
|
||||
// Logger.e(TAG, "observeWeatherUpdates", "weatherHourlyResponse = " + weatherHourlyResponse);
|
||||
// }
|
||||
// return null;
|
||||
// });
|
||||
//
|
||||
// weatherDailyJob = weatherUpdateManager.observeWeatherDaily(weatherScope, weatherDailyResponse -> {
|
||||
// if (weatherDailyResponse != null) {
|
||||
// Logger.e(TAG, "observeWeatherUpdates", "weatherDailyResponse = " + weatherDailyResponse);
|
||||
// }
|
||||
// return null;
|
||||
// });
|
||||
// }
|
||||
|
||||
private void showSystemWallpaperBehindActivity() {
|
||||
Window window = getWindow();
|
||||
|
||||
// 关键:让系统壁纸显示在当前窗口后面
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
|
||||
|
||||
// 窗口背景透明
|
||||
window.setBackgroundDrawableResource(android.R.color.transparent);
|
||||
}
|
||||
@@ -357,7 +378,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
|
||||
mApkPagerAdapter.setFragments(mFragments);
|
||||
mViewDataBinding.viewPager.setPageCount(mFragments.size());
|
||||
mViewDataBinding.viewPager.setCurrentItem(mCurrentIndex);
|
||||
mViewDataBinding.viewPager.setCurrentItem(mCurrentIndex, true);
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.ttstd.dialer.activity.main.MainActivity;
|
||||
import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.databinding.ActivitySettingsUtilsBinding;
|
||||
import com.ttstd.dialer.mdm.DeviceManagerService;
|
||||
import com.ttstd.dialer.service.main.MainService;
|
||||
import com.ttstd.dialer.utils.CameraUtil;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
@@ -169,7 +170,7 @@ public class SettingsUtilsActivity extends BaseMvvmActivity<SettingsUtilsViewMod
|
||||
//设置一个file文件
|
||||
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), fileBody);
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("sn", SystemUtils.getSerial());
|
||||
params.put("sn", DeviceManagerService.getInstance().getSerial());
|
||||
params.put("createtime", String.valueOf(createTime));
|
||||
// Call<BaseResponse> call = NetInterfaceManager.getInstance().getScreenshotCall().sendScreenshot(params, body);
|
||||
// call.enqueue(new RetryCallback<BaseResponse>(call, 10, 30 * 1000) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.ttstd.dialer.base.mvvm.BaseMvvmActivity;
|
||||
import com.ttstd.dialer.bean.req.SnLocationReq;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.databinding.ActivityWeatherMainBinding;
|
||||
import com.ttstd.dialer.manager.MapManager;
|
||||
import com.ttstd.dialer.utils.DateUtil;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
@@ -84,6 +85,7 @@ public class WeatherMainActivity extends BaseMvvmActivity<WeatherMainViewModel,
|
||||
mHourlyWeatherAdapter.setWeatherHourlyList(weatherHourlies);
|
||||
}
|
||||
});
|
||||
|
||||
mViewModel.mWeatherDailyListData.observe(this, new Observer<List<WeatherDaily>>() {
|
||||
@Override
|
||||
public void onChanged(List<WeatherDaily> weatherDailies) {
|
||||
@@ -103,10 +105,12 @@ public class WeatherMainActivity extends BaseMvvmActivity<WeatherMainViewModel,
|
||||
}
|
||||
});
|
||||
|
||||
boolean manually = mMMKV.decodeBool(CommonConfig.MANUALLY_SELECT_LOCATION, false);
|
||||
boolean manually = mMMKV.decodeBool(CommonConfig.MANUALLY_SELECT_LOCATION, CommonConfig.MANUALLY_SELECT_LOCATION_DEFAULT_VALUE);
|
||||
if (manually) {
|
||||
|
||||
} else {
|
||||
MapManager.getInstance().startLocation();
|
||||
|
||||
LiveEventBus.get(CommonConfig.LOCATION_CHANGED_KEY, SnLocationReq.class)
|
||||
.observeSticky(this, new Observer<SnLocationReq>() {
|
||||
@Override
|
||||
@@ -117,7 +121,6 @@ public class WeatherMainActivity extends BaseMvvmActivity<WeatherMainViewModel,
|
||||
mViewModel.getWeather10D(snLocationReq.getAdCode());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBindi
|
||||
|
||||
public void getWeatherNow(String adCode) {
|
||||
Logger.e(TAG, "getWeatherNow: " + adCode);
|
||||
WeatherManager.getInstance().getWeatherNow(adCode, new Callback<WeatherNowResponse>() {
|
||||
WeatherManager.getInstance().getWeatherNowAdCode(adCode, new Callback<WeatherNowResponse>() {
|
||||
@Override
|
||||
public void onSuccess(WeatherNowResponse response) {
|
||||
Logger.e("getWeatherNow", "onSuccess: " + response);
|
||||
@@ -52,7 +52,7 @@ public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBindi
|
||||
|
||||
public void getWeather24h(String adCode) {
|
||||
Logger.e(TAG, "getWeather24h: " + adCode);
|
||||
WeatherManager.getInstance().getWeather24h(adCode, new Callback<WeatherHourlyResponse>() {
|
||||
WeatherManager.getInstance().getWeather24HourAdCode(adCode, new Callback<WeatherHourlyResponse>() {
|
||||
@Override
|
||||
public void onSuccess(WeatherHourlyResponse weatherHourlyResponse) {
|
||||
Logger.e("getWeather24h", "onSuccess: " + weatherHourlyResponse);
|
||||
@@ -79,7 +79,7 @@ public class WeatherMainViewModel extends BaseViewModel<ActivityWeatherMainBindi
|
||||
|
||||
public void getWeather10D(String adCode) {
|
||||
Logger.e(TAG, "getWeather10D: " + adCode);
|
||||
WeatherManager.getInstance().getWeather10D(adCode, new Callback<WeatherDailyResponse>() {
|
||||
WeatherManager.getInstance().getWeather10Day(adCode, new Callback<WeatherDailyResponse>() {
|
||||
@Override
|
||||
public void onSuccess(WeatherDailyResponse weatherDailyResponse) {
|
||||
Logger.e("getWeather10D", "onSuccess: ");
|
||||
|
||||
@@ -13,6 +13,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.shehuan.niv.NiceImageView;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.AvatarCacheUtil;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -42,14 +44,18 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
void onItemRemoved(int position);
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
public interface ClickListener {
|
||||
void onClick(ContactInfo contactInfo);
|
||||
|
||||
void onLongClick(ContactInfo contactInfo);
|
||||
|
||||
void onMoreOperationClick(ContactInfo contactInfo);
|
||||
}
|
||||
|
||||
private OnClickListener mOnClickListener;
|
||||
private ClickListener mClickListener;
|
||||
|
||||
public void setOnClickListener(OnClickListener onClickListener) {
|
||||
mOnClickListener = onClickListener;
|
||||
public void setOnClickListener(ClickListener clickListener) {
|
||||
mClickListener = clickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -63,6 +69,7 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
public void onBindViewHolder(@NonNull ContactInfoHolder holder, int position) {
|
||||
ContactInfo contactInfo = mContactInfos.get(position);
|
||||
String name = contactInfo.getName();
|
||||
GlideUtils.loadImageSafe(mContext, contactInfo.getAvatar(), holder.nv_avatar, AvatarCacheUtil.getAvatar(mContext, name));
|
||||
holder.tv_name.setText(name);
|
||||
String phone = contactInfo.getPhoneNumber();
|
||||
holder.tv_phone.setText(phone);
|
||||
@@ -70,8 +77,25 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Logger.e(TAG, "onClick: " + contactInfo);
|
||||
if (mOnClickListener != null) {
|
||||
mOnClickListener.onClick(contactInfo);
|
||||
if (mClickListener != null) {
|
||||
mClickListener.onClick(contactInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
// holder.root.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
// @Override
|
||||
// public boolean onLongClick(View view) {
|
||||
// if (mClickListener != null) {
|
||||
// mClickListener.onLongClick(contactInfo);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
holder.clOperation.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (mClickListener != null) {
|
||||
mClickListener.onMoreOperationClick(contactInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -116,13 +140,14 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
}
|
||||
|
||||
public class ContactInfoHolder extends RecyclerView.ViewHolder {
|
||||
ConstraintLayout root;
|
||||
ConstraintLayout root, clOperation;
|
||||
NiceImageView nv_avatar;
|
||||
TextView tv_name, tv_phone;
|
||||
|
||||
public ContactInfoHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
root = itemView.findViewById(R.id.root);
|
||||
clOperation = itemView.findViewById(R.id.cl_operation);
|
||||
nv_avatar = itemView.findViewById(R.id.nv_avatar);
|
||||
tv_name = itemView.findViewById(R.id.tv_name);
|
||||
tv_phone = itemView.findViewById(R.id.tv_phone);
|
||||
|
||||
@@ -13,6 +13,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.shehuan.niv.NiceImageView;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.AvatarCacheUtil;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -63,6 +65,7 @@ public class HomeContactAdapter extends RecyclerView.Adapter<HomeContactAdapter.
|
||||
public void onBindViewHolder(@NonNull ContactInfoHolder holder, int position) {
|
||||
ContactInfo contactInfo = mContactInfos.get(position);
|
||||
String name = contactInfo.getName();
|
||||
GlideUtils.loadImageSafe(mContext, contactInfo.getAvatar(), holder.nv_avatar, AvatarCacheUtil.getAvatar(mContext, name));
|
||||
holder.tv_name.setText(name);
|
||||
String phone = contactInfo.getPhoneNumber();
|
||||
holder.tv_phone.setText(phone);
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.databinding.BindingAdapter;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
|
||||
public class ImageViewAdapter {
|
||||
@BindingAdapter("android:src")
|
||||
@@ -34,10 +35,7 @@ public class ImageViewAdapter {
|
||||
*/
|
||||
@BindingAdapter({"imageUrl", "error"})
|
||||
public static void loadImage(ImageView imageView, String url, Drawable error) {
|
||||
Glide.with(imageView.getContext())
|
||||
.load(url)
|
||||
.error(error)
|
||||
.into(imageView);
|
||||
GlideUtils.loadImageSafe(imageView.getContext(), url, imageView, error);
|
||||
}
|
||||
|
||||
@BindingAdapter({"imageAvatarUrl", "error"})
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BaseApplication extends Application {
|
||||
super.onCreate();
|
||||
Logger.e(TAG, "onCreate: ");
|
||||
mAppContext = getApplicationContext();
|
||||
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
catchException();
|
||||
}
|
||||
@@ -103,13 +103,8 @@ public class BaseApplication extends Application {
|
||||
AppManager.init(this);
|
||||
MapManager.init(this);
|
||||
MapManager.getInstance().initMap();
|
||||
boolean manually = mMMKV.decodeBool(CommonConfig.MANUALLY_SELECT_LOCATION, false);
|
||||
Logger.e(TAG, "init: manually location " + manually);
|
||||
if (manually) {
|
||||
MapManager.getInstance().startLocation();
|
||||
|
||||
} else {
|
||||
MapManager.getInstance().startLocation();
|
||||
}
|
||||
WeatherManager.init(this);
|
||||
IconCacheManager.init(this);
|
||||
}
|
||||
@@ -129,7 +124,7 @@ public class BaseApplication extends Application {
|
||||
return;
|
||||
}
|
||||
JPushInterface.init(this);
|
||||
JPushInterface.setAlias(this, 0, SystemUtils.getSerial());
|
||||
JPushInterface.setAlias(this, 0, DeviceManagerService.getInstance().getSerial());
|
||||
|
||||
// 调整点二:App用户同意了隐私政策授权,并且开发者确定要开启推送服务后调用
|
||||
// JCore 5.0.4+会自动处理授权状态,可不需要显式设置true
|
||||
|
||||
@@ -24,10 +24,6 @@ import com.ttstd.dialer.utils.Logger;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* @author: lml
|
||||
* @date: 2021/12/15
|
||||
*/
|
||||
public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends ViewDataBinding> extends BaseDialogFragment {
|
||||
protected String mTag = this.getClass().getSimpleName();
|
||||
/**
|
||||
@@ -43,11 +39,8 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
protected VM mViewModel;
|
||||
protected VDB mViewDataBinding;
|
||||
protected Class<VM> vmClass;
|
||||
//
|
||||
// protected Toolbar toolbar;
|
||||
// protected View statusBarView;
|
||||
//
|
||||
protected Bundle bundle;//来自getArguments()
|
||||
|
||||
protected Bundle bundle;
|
||||
protected Bundle savedInstanceState;
|
||||
|
||||
// protected Context context;
|
||||
@@ -64,7 +57,6 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
// this.context = context;
|
||||
ctx = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
@@ -82,14 +74,16 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
//ViewDataBinding
|
||||
mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
|
||||
mViewDataBinding.setLifecycleOwner(this);
|
||||
|
||||
//ViewModel
|
||||
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
mViewModel = new ViewModelProvider(this).get(vmClass);
|
||||
//
|
||||
try {
|
||||
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
mViewModel = new ViewModelProvider(this).get(vmClass);
|
||||
} catch (Exception e) {
|
||||
Logger.e(mTag, "Failed to create ViewModel: " + e.getMessage());
|
||||
throw new RuntimeException("Failed to create ViewModel", e);
|
||||
}
|
||||
|
||||
return mViewDataBinding.getRoot();
|
||||
}
|
||||
|
||||
@@ -98,33 +92,16 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// if (initStatusBarToolBar()) {
|
||||
// toolbar = getToolbar();
|
||||
// }
|
||||
//注册eventbus
|
||||
// if (getClass().isAnnotationPresent(BindEventBus.class))
|
||||
// EventBusManager.register(this);
|
||||
//
|
||||
mViewDataBinding.setLifecycleOwner(getViewLifecycleOwner());
|
||||
|
||||
// fitsLayoutOverlap();
|
||||
initDataBinding();
|
||||
initView(bundle = getArguments());
|
||||
//
|
||||
initData(this.savedInstanceState = savedInstanceState);
|
||||
//
|
||||
|
||||
if (mIsVisible) {
|
||||
onEnter();
|
||||
}
|
||||
mHasPrepare = true;
|
||||
//
|
||||
// LiveDataBus.get().with(ConstantUtils.DATA_BUS_LOADING_FRAGMENT, Boolean.class).observe(getActivity(), bool -> {
|
||||
// L.e(" >> LiveDataBus >> DATA_BUS_LOADING_FRAGMENT: %s", bool);
|
||||
// if(bool) {
|
||||
// showLoading(R.string.str_please_wait);
|
||||
// } else {
|
||||
// hideLoading();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,10 +109,7 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
super.onDestroyView();
|
||||
mHasPrepare = false;
|
||||
mViewDataBinding = null;
|
||||
//移除eventbus
|
||||
// if (getClass().isAnnotationPresent(BindEventBus.class))
|
||||
// EventBusManager.unregister(this);
|
||||
//
|
||||
mViewModel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,15 +127,13 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchData() {
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected abstract int getLayoutId();
|
||||
|
||||
// protected abstract Toolbar getToolbar();
|
||||
|
||||
// protected View getStatusView() {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
protected abstract void initDataBinding();
|
||||
|
||||
protected abstract void initView(Bundle bundle);
|
||||
@@ -171,29 +143,10 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// fitsLayoutOverlap();
|
||||
}
|
||||
|
||||
// protected boolean isImmersionBarEnabled() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// protected boolean initStatusBarToolBar() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
// private void fitsLayoutOverlap() {
|
||||
// if (!isImmersionBarEnabled()) return;
|
||||
// if (statusBarView != null) {
|
||||
// ImmersionBar.setStatusBarView(getActivity(), statusBarView);
|
||||
// }
|
||||
// if (toolbar != null) {
|
||||
// ImmersionBar.setTitleBar(getActivity(), toolbar);
|
||||
// }
|
||||
// }
|
||||
|
||||
protected void hideInputMethod(Activity activity) {
|
||||
if (activity == null) return;
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||
View view = activity.getCurrentFocus();
|
||||
if (view != null) {
|
||||
@@ -202,6 +155,7 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
}
|
||||
|
||||
protected void hideInputMethod(Activity activity, EditText editText) {
|
||||
if (activity == null || editText == null) return;
|
||||
InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||
View view = activity.getCurrentFocus();
|
||||
if (view != null) {
|
||||
@@ -210,64 +164,15 @@ public abstract class BaseMvvmDialogFragment<VM extends ViewModel, VDB extends V
|
||||
}
|
||||
|
||||
protected void showInputMethod(EditText editText) {
|
||||
if (editText == null) return;
|
||||
InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);
|
||||
}
|
||||
|
||||
|
||||
// private CustomDialog mWaitDialog;
|
||||
//
|
||||
// public void showLoading(@StringRes int contentID) {
|
||||
// showLoading(contentID, R.color.white);
|
||||
// }
|
||||
//
|
||||
// public void showLoading(@StringRes int contentID, @ColorRes int color) {
|
||||
// hideLoading();
|
||||
// DialogX.init(getActivity());
|
||||
// if (color == R.color.white) {
|
||||
// mWaitDialog = DialogXUtil.getInstance().showLoading(getActivity(), getString(contentID), getResources().getColor(color));
|
||||
// } else {
|
||||
// mWaitDialog = DialogXUtil.getInstance().showLoading_black(getActivity(), getString(contentID), getResources().getColor(color));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void updateLoadingTip(@StringRes int messageID, int percent) {
|
||||
// try {
|
||||
// if (mWaitDialog != null && mWaitDiaLogger.isShow()) {
|
||||
// TextView tvTip = mWaitDialog.getCustomView().findViewById(R.id.tv_load_tip);
|
||||
// if (tvTip != null)
|
||||
// tvTip.setText(getResources().getString(messageID) + (percent == -1 ? "" : percent + "%"));
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public boolean isShowLoading() {
|
||||
// return mWaitDialog != null && mWaitDiaLogger.isShow();
|
||||
// }
|
||||
//
|
||||
// public void hideLoading() {
|
||||
// try {
|
||||
// boolean isShow = isShowLoading();
|
||||
// L.d(" >> hideLoading :: isShow: %s", isShow);
|
||||
// if (isShow)
|
||||
// mWaitDiaLogger.dismiss();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 進入界面
|
||||
*/
|
||||
protected void onEnter() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 離開界面
|
||||
*/
|
||||
protected void onExit() {
|
||||
|
||||
}
|
||||
|
||||
@@ -84,7 +84,6 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
//ViewDataBinding
|
||||
mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false);
|
||||
mViewDataBinding.setLifecycleOwner(this);
|
||||
|
||||
//ViewModel
|
||||
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||
@@ -97,6 +96,7 @@ public abstract class BaseMvvmFragment<VM extends ViewModel, VDB extends ViewDat
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mViewDataBinding.setLifecycleOwner(getViewLifecycleOwner());
|
||||
|
||||
// if (initStatusBarToolBar()) {
|
||||
// toolbar = getToolbar();
|
||||
|
||||
@@ -19,12 +19,17 @@ public class CommonConfig {
|
||||
public static final String WECHAT_AUTO_ACCEPT_CALL= "wechat_auto_accept_call_key";
|
||||
public static final String WECHAT_AUTO_HNADS_FREE= "wechat_auto_hands_free_key";
|
||||
|
||||
/*是否手动选择地址*/
|
||||
public static final String MANUALLY_SELECT_LOCATION = "manually_select_location_key";
|
||||
public static final boolean MANUALLY_SELECT_LOCATION_DEFAULT_VALUE = false;
|
||||
/*是否手动选择地址*/
|
||||
public static final String MANUALLY_LOCATION_ID = "manually_location_id_key";
|
||||
|
||||
/*地址改变时发送*/
|
||||
public static final String LOCATION_CHANGED_KEY = "map_location_changed";
|
||||
public static final String LOCATION_ID_CHANGED_KEY = "map_Location_ID_changed";
|
||||
|
||||
|
||||
/*当前定位地址*/
|
||||
public static final String CURRENT_LOCATION_MAP_ADDRESS_KEY = "current_map_location_map_address";
|
||||
public static final String CURRENT_LOCATION_MAP_LOCATION_DESCRIBE_KEY = "current_map_location_map_location_describe";
|
||||
|
||||
@@ -41,5 +41,17 @@ public interface ContactDao {
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE name LIKE :searchQuery OR phoneNumber LIKE :searchQuery")
|
||||
List<ContactInfo> searchContacts(String searchQuery);
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE sync_status = :status ORDER BY create_time ASC")
|
||||
List<ContactInfo> getContactsBySyncStatus(int status);
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE sync_status != 1 ORDER BY create_time ASC")
|
||||
List<ContactInfo> getUnsyncedContacts();
|
||||
|
||||
@Query("UPDATE contacts SET sync_status = :status, local_id = :localId, update_time = :updateTime WHERE id = :id")
|
||||
int updateSyncStatus(long id, int status, Long localId, long updateTime);
|
||||
|
||||
@Query("UPDATE contacts SET sync_status = :status WHERE id = :id")
|
||||
int updateSyncStatusById(long id, int status);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,14 @@ package com.ttstd.dialer.db.contact;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
@@ -14,25 +17,81 @@ import java.util.Objects;
|
||||
@Entity(tableName = "contacts")
|
||||
public class ContactInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4899154548784231165L;
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private int id;
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@SerializedName(value = "nickName", alternate = {"nick_name"})
|
||||
private String nickName;
|
||||
|
||||
@SerializedName(value = "phoneNumber", alternate = {"phone_number"})
|
||||
private String phoneNumber;
|
||||
|
||||
private String avatar;
|
||||
private String wxid;
|
||||
|
||||
private int position;
|
||||
|
||||
private boolean emergency;
|
||||
|
||||
@SerializedName(value = "showDesktop", alternate = {"show_desktop"})
|
||||
private boolean showDesktop;
|
||||
|
||||
@SerializedName(value = "bindPhone", alternate = {"bind_phone"})
|
||||
private String bindPhone;
|
||||
|
||||
@SerializedName(value = "bindSn", alternate = {"bind_sn"})
|
||||
private String bindSn;
|
||||
|
||||
@SerializedName(value = "updateTime", alternate = {"update_time"})
|
||||
@ColumnInfo(name = "update_time")
|
||||
private long updateTime;
|
||||
|
||||
@SerializedName(value = "createTime", alternate = {"create_time"})
|
||||
@ColumnInfo(name = "create_time")
|
||||
private long createTime;
|
||||
|
||||
@ColumnInfo(name = "local_id")
|
||||
private Long localId;
|
||||
|
||||
@ColumnInfo(name = "sync_status")
|
||||
private int syncStatus;
|
||||
|
||||
public ContactInfo() {
|
||||
|
||||
}
|
||||
|
||||
// 本地添加
|
||||
@Ignore
|
||||
public ContactInfo(String name, String phoneNumber, int position) {
|
||||
this.name = name;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@Ignore
|
||||
public ContactInfo(ContactInfo contactInfo) {
|
||||
this.id = contactInfo.getId();
|
||||
this.name = contactInfo.name;
|
||||
this.nickName = contactInfo.nickName;
|
||||
this.phoneNumber = contactInfo.phoneNumber;
|
||||
this.avatar = contactInfo.avatar;
|
||||
this.position = contactInfo.position;
|
||||
this.emergency = contactInfo.emergency;
|
||||
this.showDesktop = contactInfo.showDesktop;
|
||||
this.bindPhone = contactInfo.bindPhone;
|
||||
this.bindSn = contactInfo.bindSn;
|
||||
this.updateTime = contactInfo.updateTime;
|
||||
this.createTime = contactInfo.createTime;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -44,6 +103,14 @@ public class ContactInfo implements Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
@@ -60,14 +127,6 @@ public class ContactInfo implements Serializable {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public String getWxid() {
|
||||
return wxid;
|
||||
}
|
||||
|
||||
public void setWxid(String wxid) {
|
||||
this.wxid = wxid;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
@@ -76,6 +135,70 @@ public class ContactInfo implements Serializable {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public boolean isEmergency() {
|
||||
return emergency;
|
||||
}
|
||||
|
||||
public void setEmergency(boolean emergency) {
|
||||
this.emergency = emergency;
|
||||
}
|
||||
|
||||
public boolean isShowDesktop() {
|
||||
return showDesktop;
|
||||
}
|
||||
|
||||
public void setShowDesktop(boolean showDesktop) {
|
||||
this.showDesktop = showDesktop;
|
||||
}
|
||||
|
||||
public String getBindPhone() {
|
||||
return bindPhone;
|
||||
}
|
||||
|
||||
public void setBindPhone(String bindPhone) {
|
||||
this.bindPhone = bindPhone;
|
||||
}
|
||||
|
||||
public String getBindSn() {
|
||||
return bindSn;
|
||||
}
|
||||
|
||||
public void setBindSn(String bindSn) {
|
||||
this.bindSn = bindSn;
|
||||
}
|
||||
|
||||
public long getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(long updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Long getLocalId() {
|
||||
return localId;
|
||||
}
|
||||
|
||||
public void setLocalId(Long localId) {
|
||||
this.localId = localId;
|
||||
}
|
||||
|
||||
public int getSyncStatus() {
|
||||
return syncStatus;
|
||||
}
|
||||
|
||||
public void setSyncStatus(int syncStatus) {
|
||||
this.syncStatus = syncStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof ContactInfo) {
|
||||
|
||||
@@ -60,4 +60,20 @@ public class ContactRepository {
|
||||
public int deleteAll() {
|
||||
return mContactDao.deleteAll();
|
||||
}
|
||||
|
||||
public List<ContactInfo> getContactsBySyncStatus(int status) {
|
||||
return mContactDao.getContactsBySyncStatus(status);
|
||||
}
|
||||
|
||||
public List<ContactInfo> getUnsyncedContacts() {
|
||||
return mContactDao.getUnsyncedContacts();
|
||||
}
|
||||
|
||||
public int updateSyncStatus(long id, int status, Long localId, long updateTime) {
|
||||
return mContactDao.updateSyncStatus(id, status, localId, updateTime);
|
||||
}
|
||||
|
||||
public int updateSyncStatusById(long id, int status) {
|
||||
return mContactDao.updateSyncStatusById(id, status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class ContactViewModel extends AndroidViewModel {
|
||||
private ContactRepository mRepository;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ttstd.dialer.db.contact;
|
||||
|
||||
|
||||
public interface SyncStatus {
|
||||
int PENDING = 0;
|
||||
int SYNCED = 1;
|
||||
int FAILED = 2;
|
||||
|
||||
static String getStatusName(int status) {
|
||||
switch (status) {
|
||||
case PENDING:
|
||||
return "待同步";
|
||||
case SYNCED:
|
||||
return "已同步";
|
||||
case FAILED:
|
||||
return "同步失败";
|
||||
default:
|
||||
return "未知状态";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,22 @@ import android.text.InputFilter;
|
||||
import android.text.Spanned;
|
||||
|
||||
/**
|
||||
* 过滤输入中的空格(包括普通空格和全角空格)
|
||||
* 过滤输入中的空格、换行等特殊字符
|
||||
*/
|
||||
public class NoSpaceInputFilter implements InputFilter {
|
||||
@Override
|
||||
public CharSequence filter(CharSequence source, int start, int end,
|
||||
Spanned dest, int dstart, int dend) {
|
||||
// 遍历输入的字符序列,过滤掉所有空格
|
||||
// 遍历输入的字符序列,过滤掉所有特殊字符
|
||||
StringBuilder filtered = new StringBuilder();
|
||||
for (int i = start; i < end; i++) {
|
||||
char c = source.charAt(i);
|
||||
// 过滤普通空格(ASCII 32)和全角空格(Unicode 12288)
|
||||
if (c != ' ' && c != '\u3000') {
|
||||
// 过滤以下字符:
|
||||
// 1. 普通空格(ASCII 32)
|
||||
// 2. 全角空格(Unicode 12288)
|
||||
// 3. 换行符(\n, \r)
|
||||
// 4. 制表符(\t)
|
||||
if (!Character.isWhitespace(c)) {
|
||||
filtered.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class AppFragment extends BaseMvvmFragment<AppViewModel, FragmentAppBindi
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
Logger.e(TAG, "initData: ");
|
||||
Logger.e(TAG, "initData: " + mViewModel.mAppUpdateData);
|
||||
mViewModel.mAppUpdateData.observe(this, new Observer<Integer>() {
|
||||
mViewModel.mAppUpdateData.observe(getViewLifecycleOwner(), new Observer<Integer>() {
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
if (integer > 0) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.ttstd.dialer.adapter.HomeContactAdapter;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmFragment;
|
||||
import com.ttstd.dialer.databinding.FragmentContactBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.fragment.dialog.call.CallFragment;
|
||||
import com.ttstd.dialer.fragment.dialog.contact.call.CallFragment;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.view.EqualSpaceDecoration;
|
||||
|
||||
@@ -60,7 +60,8 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
mViewModel.preloadData();
|
||||
mViewModel.mContactListData.observe(getViewLifecycleOwner(), new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
Logger.e(TAG, "mContactListData: " + contactInfos);
|
||||
|
||||
@@ -13,18 +13,32 @@ import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.ObservableEmitter;
|
||||
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.functions.Consumer;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class ContactViewModel extends BaseViewModel<FragmentContactBinding, FragmentEvent> {
|
||||
private ContactRepository mRepository;
|
||||
private boolean isDataLoaded = false;
|
||||
|
||||
public void preloadData() {
|
||||
if (isDataLoaded) return;
|
||||
|
||||
getAllContactsObservable()
|
||||
.subscribe(new Consumer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void accept(List<ContactInfo> contactInfos) throws Throwable {
|
||||
mContactListData.postValue(contactInfos);
|
||||
isDataLoaded = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
@@ -34,17 +48,20 @@ public class ContactViewModel extends BaseViewModel<FragmentContactBinding, Frag
|
||||
|
||||
public MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContacts() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
public Observable<List<ContactInfo>> getAllContactsObservable() {
|
||||
return Observable.fromCallable(new Callable<List<ContactInfo>>() {
|
||||
@Override
|
||||
public List<ContactInfo> call() throws Exception {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
return contactInfos;
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.STOP))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public void getAllContacts() {
|
||||
getAllContactsObservable()
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.ttstd.dialer.fragment.dialog.call;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.FragmentCallBinding;
|
||||
|
||||
public class CallViewModel extends BaseViewModel<FragmentCallBinding, FragmentEvent> {
|
||||
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ttstd.dialer.fragment.dialog.call;
|
||||
package com.ttstd.dialer.fragment.dialog.contact.call;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
@@ -23,14 +23,14 @@ import androidx.fragment.app.FragmentTransaction;
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmDialogFragment;
|
||||
import com.ttstd.dialer.databinding.FragmentCallBinding;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentContactCallBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.service.DialerAccessibilityService;
|
||||
import com.ttstd.dialer.utils.AccessibilityServiceHelper;
|
||||
import com.ttstd.dialer.utils.ApkUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, FragmentCallBinding> {
|
||||
public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, DialogFragmentContactCallBinding> {
|
||||
private static final String TAG = "CallFragment";
|
||||
|
||||
private static final int REQUEST_CODE_CALL = 7897;
|
||||
@@ -47,7 +47,7 @@ public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, Fragment
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.fragment_call;
|
||||
return R.layout.dialog_fragment_contact_call;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.call;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentContactCallBinding;
|
||||
|
||||
public class CallViewModel extends BaseViewModel<DialogFragmentContactCallBinding, FragmentEvent> {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.delete;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmDialogFragment;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentDeleteContactBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.AvatarCacheUtil;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
public class ContactDeleteDialogFragment extends BaseMvvmDialogFragment<ContactDeleteViewModel, DialogFragmentDeleteContactBinding> {
|
||||
|
||||
private static final String TAG = "EditDialogFragment";
|
||||
private Activity mContext;
|
||||
private ContactInfo mContactInfo;
|
||||
|
||||
public interface ContactOperationListener {
|
||||
void onCancel(ContactInfo contactInfo);
|
||||
|
||||
void onDelete(ContactInfo contactInfo);
|
||||
}
|
||||
|
||||
private ContactOperationListener mContactOperationListener;
|
||||
|
||||
public void setContactOperateListener(ContactOperationListener contactOperationListener) {
|
||||
mContactOperationListener = contactOperationListener;
|
||||
}
|
||||
|
||||
public ContactDeleteDialogFragment(ContactInfo contactInfo) {
|
||||
mContactInfo = contactInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.dialog_fragment_delete_contact;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataBinding() {
|
||||
mContext = getActivity();
|
||||
mViewModel.setContext(mContext);
|
||||
mViewModel.setVDBinding(mViewDataBinding);
|
||||
mViewModel.setLifecycle(getLifecycleSubject());
|
||||
mViewDataBinding.setClick(new BtnClick());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
if (mContactInfo != null) {
|
||||
mViewDataBinding.setContactInfo(mContactInfo);
|
||||
GlideUtils.loadImageSafe(mContext, mContactInfo.getAvatar(), mViewDataBinding.contactAvatar, AvatarCacheUtil.getAvatar(mContext, mContactInfo.getName()));
|
||||
} else {
|
||||
Toaster.show("无联系人信息");
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchData() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (getDialog() != null) {
|
||||
Window window = getDialog().getWindow();
|
||||
if (window == null) return;
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.gravity = Gravity.CENTER;
|
||||
window.setAttributes(params);
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
getDialog().setCancelable(true);
|
||||
getDialog().setCanceledOnTouchOutside(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(FragmentManager manager, String tag) {
|
||||
DialogFragment fragment = (DialogFragment) manager.findFragmentByTag(tag);
|
||||
if (fragment != null && fragment.isAdded()
|
||||
&& fragment.getDialog() != null && fragment.getDialog().isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FragmentTransaction ft = manager.beginTransaction();
|
||||
ft.add(this, tag);
|
||||
ft.commitAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
Logger.e(TAG, "show: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
public void onCancel(View view) {
|
||||
if (mContactOperationListener != null) {
|
||||
mContactOperationListener.onCancel(mContactInfo);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
public void onDelete(View view) {
|
||||
if (mContactOperationListener != null) {
|
||||
mContactOperationListener.onDelete(mContactInfo);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.delete;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentDeleteContactBinding;
|
||||
|
||||
public class ContactDeleteViewModel extends BaseViewModel<DialogFragmentDeleteContactBinding, FragmentEvent> {
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.edit;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmDialogFragment;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentEditContactBinding;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.utils.AvatarCacheUtil;
|
||||
import com.ttstd.dialer.utils.GlideUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
public class EditDialogFragment extends BaseMvvmDialogFragment<EditViewModel, DialogFragmentEditContactBinding> {
|
||||
|
||||
private static final String TAG = "EditDialogFragment";
|
||||
private Activity mContext;
|
||||
private ContactInfo mContactInfo;
|
||||
|
||||
public interface ContactOperationListener {
|
||||
void onContactEdit(ContactInfo contactInfo);
|
||||
|
||||
void onContactDelete(ContactInfo contactInfo);
|
||||
}
|
||||
|
||||
private ContactOperationListener mContactOperationListener;
|
||||
|
||||
public void setContactOperateListener(ContactOperationListener contactOperationListener) {
|
||||
mContactOperationListener = contactOperationListener;
|
||||
}
|
||||
|
||||
public EditDialogFragment(ContactInfo contactInfo) {
|
||||
mContactInfo = contactInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.dialog_fragment_edit_contact;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataBinding() {
|
||||
mContext = getActivity();
|
||||
mViewModel.setContext(mContext);
|
||||
mViewModel.setVDBinding(mViewDataBinding);
|
||||
mViewModel.setLifecycle(getLifecycleSubject());
|
||||
mViewDataBinding.setClick(new BtnClick());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
if (mContactInfo != null) {
|
||||
mViewDataBinding.setContactInfo(mContactInfo);
|
||||
GlideUtils.loadImageSafe(mContext, mContactInfo.getAvatar(), mViewDataBinding.contactAvatar, AvatarCacheUtil.getAvatar(mContext, mContactInfo.getName()));
|
||||
} else {
|
||||
Toaster.show("无联系人信息");
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchData() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (getDialog() != null) {
|
||||
Window window = getDialog().getWindow();
|
||||
if (window == null) return;
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.gravity = Gravity.CENTER;
|
||||
window.setAttributes(params);
|
||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
getDialog().setCancelable(true);
|
||||
getDialog().setCanceledOnTouchOutside(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(FragmentManager manager, String tag) {
|
||||
DialogFragment fragment = (DialogFragment) manager.findFragmentByTag(tag);
|
||||
if (fragment != null && fragment.isAdded()
|
||||
&& fragment.getDialog() != null && fragment.getDialog().isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FragmentTransaction ft = manager.beginTransaction();
|
||||
ft.add(this, tag);
|
||||
ft.commitAllowingStateLoss();
|
||||
} catch (Exception e) {
|
||||
Logger.e(TAG, "show: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public class BtnClick {
|
||||
public void onEditContact(View view) {
|
||||
if (mContactOperationListener != null) {
|
||||
mContactOperationListener.onContactEdit(mContactInfo);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
public void onDeleteContact(View view) {
|
||||
if (mContactOperationListener != null) {
|
||||
mContactOperationListener.onContactDelete(mContactInfo);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ttstd.dialer.fragment.dialog.contact.edit;
|
||||
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.ttstd.dialer.base.mvvm.BaseViewModel;
|
||||
import com.ttstd.dialer.databinding.DialogFragmentEditContactBinding;
|
||||
|
||||
public class EditViewModel extends BaseViewModel<DialogFragmentEditContactBinding, FragmentEvent> {
|
||||
}
|
||||
@@ -8,21 +8,32 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus;
|
||||
import com.qweather.sdk.response.weather.WeatherDaily;
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.activity.contact.list.ContactListActivity;
|
||||
import com.ttstd.dialer.activity.weather.main.WeatherMainActivity;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmFragment;
|
||||
import com.ttstd.dialer.bean.req.SnLocationReq;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.databinding.FragmentHomeBinding;
|
||||
import com.ttstd.dialer.manager.WeatherUpdateManager;
|
||||
import com.ttstd.dialer.utils.ApkUtils;
|
||||
import com.ttstd.dialer.utils.DateUtil;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.utils.LunarCalendarFestivalUtils;
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope;
|
||||
import kotlinx.coroutines.CoroutineScopeKt;
|
||||
import kotlinx.coroutines.Job;
|
||||
|
||||
/**
|
||||
* A simple {@link Fragment} subclass.
|
||||
* Use the {@link HomeFragment#newInstance} factory method to
|
||||
@@ -33,6 +44,12 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
|
||||
private Activity mContext;
|
||||
private LunarCalendarFestivalUtils mFestivalUtils;
|
||||
private WeatherUpdateManager weatherUpdateManager;
|
||||
|
||||
private final CoroutineScope weatherScope = CoroutineScopeKt.MainScope();
|
||||
private Job weatherNowJob;
|
||||
private Job weatherHourlyJob;
|
||||
private Job weatherDailyJob;
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
@@ -91,12 +108,20 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
mFestivalUtils = new LunarCalendarFestivalUtils();
|
||||
weatherUpdateManager = WeatherUpdateManager.Companion.getInstance();
|
||||
observeWeatherUpdates();
|
||||
setTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
|
||||
LiveEventBus.get(CommonConfig.LOCATION_CHANGED_KEY, SnLocationReq.class)
|
||||
.observeSticky(this, new Observer<SnLocationReq>() {
|
||||
@Override
|
||||
public void onChanged(SnLocationReq snLocationReq) {
|
||||
mViewDataBinding.tvLocation.setText(snLocationReq.getDistrict());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,6 +143,58 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
unregisterReceivers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (weatherNowJob != null) {
|
||||
weatherNowJob.cancel(null);
|
||||
}
|
||||
if (weatherHourlyJob != null) {
|
||||
weatherHourlyJob.cancel(null);
|
||||
}
|
||||
if (weatherDailyJob != null) {
|
||||
weatherDailyJob.cancel(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void observeWeatherUpdates() {
|
||||
// 观察当前天气更新
|
||||
weatherNowJob = weatherUpdateManager.observeWeatherNow(weatherScope, weatherNowResponse -> {
|
||||
if (weatherNowResponse != null) {
|
||||
Logger.e(TAG, "observeWeatherUpdates", "weatherNowResponse = " + weatherNowResponse);
|
||||
mViewDataBinding.tvWeather.setText(weatherNowResponse.getNow().getText());
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
weatherHourlyJob = weatherUpdateManager.observeWeatherHourly(weatherScope, weatherHourlyResponse -> {
|
||||
if (weatherHourlyResponse != null) {
|
||||
Logger.e(TAG, "observeWeatherUpdates", "weatherHourlyResponse = " + weatherHourlyResponse);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
weatherDailyJob = weatherUpdateManager.observeWeatherDaily(weatherScope, weatherDailyResponse -> {
|
||||
if (weatherDailyResponse != null) {
|
||||
Logger.e(TAG, "observeWeatherUpdates", "weatherDailyResponse = " + weatherDailyResponse);
|
||||
|
||||
WeatherDaily weatherDaily = weatherDailyResponse.getDaily().get(0);
|
||||
String iconDay = weatherDaily.getIconDay();
|
||||
// 获取资源ID
|
||||
String fileName = "qweather_" + iconDay; // 替换为你的文件名
|
||||
int resId = mContext.getResources().getIdentifier(fileName, "raw", mContext.getPackageName());
|
||||
if (resId != 0) {
|
||||
mViewDataBinding.ivQweatherIcon.setImageDrawable(mContext.getDrawable(resId));
|
||||
} else {
|
||||
// 处理错误
|
||||
Logger.e("GlideLoad", "Raw resource not found: " + fileName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void registerReceivers() {
|
||||
registerTimeReceiver();
|
||||
}
|
||||
@@ -152,14 +229,16 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Logger.i("TimeReceiver", "onReceive: " + action);
|
||||
switch (action) {
|
||||
case Intent.ACTION_DATE_CHANGED:
|
||||
case Intent.ACTION_TIMEZONE_CHANGED:
|
||||
case Intent.ACTION_TIME_CHANGED:
|
||||
case Intent.ACTION_TIME_TICK:
|
||||
setTime();
|
||||
break;
|
||||
default:
|
||||
if (!TextUtils.isEmpty(action)) {
|
||||
switch (action) {
|
||||
case Intent.ACTION_DATE_CHANGED:
|
||||
case Intent.ACTION_TIMEZONE_CHANGED:
|
||||
case Intent.ACTION_TIME_CHANGED:
|
||||
case Intent.ACTION_TIME_TICK:
|
||||
setTime();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,8 +246,7 @@ public class HomeFragment extends BaseMvvmFragment<HomeViewModel, FragmentHomeBi
|
||||
private void setTime() {
|
||||
if (isAdded()) {
|
||||
mViewDataBinding.tvTime.setText(DateUtil.formatDateHour());
|
||||
mViewDataBinding.tvDate.setText(DateUtil.formatDateDay());
|
||||
mViewDataBinding.tvWeek.setText(DateUtil.convertToChineseWeekdayAll());
|
||||
mViewDataBinding.tvDate.setText(DateUtil.formatDateDay() + "\t" + DateUtil.convertToChineseWeekdayAll());
|
||||
mViewDataBinding.tvLunar.setText(mFestivalUtils.getLunarCalendar());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,12 @@ public class AppManager {
|
||||
}
|
||||
|
||||
public static final List<String> DEFAULT_APP_PACKAGES = new ArrayList<String>() {{
|
||||
this.add("com.android.settings");
|
||||
this.add("com.android.dialer");
|
||||
this.add("com.android.camera2");
|
||||
this.add("com.android.messaging");
|
||||
this.add("com.android.contacts");
|
||||
this.add("com.android.messaging");
|
||||
this.add("com.android.settings");
|
||||
this.add("com.android.camera2");
|
||||
|
||||
this.add("com.tencent.mm");
|
||||
this.add("com.jiangjia.gif");
|
||||
this.add("com.ss.android.ugc.aweme");
|
||||
|
||||
322
app/src/main/java/com/ttstd/dialer/manager/ContactManager.java
Normal file
322
app/src/main/java/com/ttstd/dialer/manager/ContactManager.java
Normal file
@@ -0,0 +1,322 @@
|
||||
package com.ttstd.dialer.manager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.network.BaseObserver;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.ObservableEmitter;
|
||||
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
|
||||
public class ContactManager {
|
||||
private static final String TAG = "ContactManager";
|
||||
private static volatile ContactManager instance;
|
||||
|
||||
private ContactRepository mRepository;
|
||||
private Context mContext;
|
||||
|
||||
// 同步状态常量
|
||||
private static final int SYNC_STATUS_SYNCED = 1; // 已同步
|
||||
private static final int SYNC_STATUS_UNSYNCED = 0; // 未同步
|
||||
private static final int SYNC_STATUS_DELETED = 2; // 已删除(待同步删除)
|
||||
|
||||
private ContactManager(Context context) {
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mRepository = new ContactRepository(mContext);
|
||||
}
|
||||
|
||||
public static ContactManager getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (ContactManager.class) {
|
||||
if (instance == null) {
|
||||
instance = new ContactManager(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系人列表(优先从网络获取,失败则从本地数据库获取)
|
||||
*
|
||||
* @param lifecycle RxLifecycle 生命周期绑定
|
||||
* @param callback 回调接口
|
||||
*/
|
||||
public void getContacts(BehaviorSubject<ActivityEvent> lifecycle, ContactCallback callback) {
|
||||
Logger.e(TAG, "开始获取联系人列表");
|
||||
|
||||
OkHttpManager.getInstance().getContactListObservable(lifecycle)
|
||||
.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
|
||||
.subscribe(new BaseObserver<BaseResponse<List<ContactInfo>>>() {
|
||||
@Override
|
||||
public void onSuccess(BaseResponse<List<ContactInfo>> listBaseResponse) {
|
||||
Log.e(TAG, "网络请求成功: " + listBaseResponse);
|
||||
if (listBaseResponse.isSuccess()) {
|
||||
List<ContactInfo> networkContacts = listBaseResponse.getData();
|
||||
if (networkContacts != null && !networkContacts.isEmpty()) {
|
||||
// 在子线程中处理数据库同步
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
try {
|
||||
// 同步网络和本地数据
|
||||
syncContacts(networkContacts);
|
||||
// 返回排序后的联系人列表
|
||||
List<ContactInfo> sortedContacts = networkContacts.stream()
|
||||
.sorted((c1, c2) -> Integer.compare(c1.getPosition(), c2.getPosition()))
|
||||
.collect(Collectors.toList());
|
||||
emitter.onNext(sortedContacts);
|
||||
emitter.onComplete();
|
||||
} catch (Exception e) {
|
||||
emitter.onError(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e(TAG, "开始处理联系人数据");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Logger.e(TAG, "联系人数据处理完成,数量: " + contactInfos.size());
|
||||
if (callback != null) {
|
||||
callback.onSuccess(contactInfos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "处理联系人数据失败: " + e.getMessage());
|
||||
if (callback != null) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e(TAG, "联系人数据处理完成");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 网络返回空数据,从本地获取
|
||||
getLocalContacts(callback);
|
||||
}
|
||||
} else {
|
||||
// 网络请求业务失败,从本地获取
|
||||
getLocalContacts(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
Log.e(TAG, "网络请求失败: " + e.getMessage());
|
||||
// 网络请求失败,从本地获取
|
||||
getLocalContacts(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 从本地数据库获取联系人
|
||||
*/
|
||||
private void getLocalContacts(ContactCallback callback) {
|
||||
Logger.e(TAG, "从本地数据库获取联系人");
|
||||
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
try {
|
||||
List<ContactInfo> localContacts = mRepository.getAllContacts();
|
||||
List<ContactInfo> sortedContacts = localContacts.stream()
|
||||
.sorted((c1, c2) -> Integer.compare(c1.getPosition(), c2.getPosition()))
|
||||
.collect(Collectors.toList());
|
||||
emitter.onNext(sortedContacts);
|
||||
emitter.onComplete();
|
||||
} catch (Exception e) {
|
||||
emitter.onError(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Logger.e(TAG, "开始获取本地联系人");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Logger.e(TAG, "获取本地联系人成功,数量: " + contactInfos.size());
|
||||
if (callback != null) {
|
||||
callback.onSuccess(contactInfos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Logger.e(TAG, "获取本地联系人失败: " + e.getMessage());
|
||||
if (callback != null) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Logger.e(TAG, "获取本地联系人完成");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步网络和本地联系人数据(增删改查对比)
|
||||
*
|
||||
* @param networkContacts 网络联系人列表
|
||||
*/
|
||||
private void syncContacts(List<ContactInfo> networkContacts) {
|
||||
Logger.e(TAG, "开始同步联系人数据");
|
||||
|
||||
// 获取本地所有联系人
|
||||
List<ContactInfo> localContacts = mRepository.getAllContacts();
|
||||
|
||||
// 创建 Map 以便快速查找
|
||||
// 网络联系人:以 id 为 key
|
||||
Map<Long, ContactInfo> networkMap = new HashMap<>();
|
||||
for (ContactInfo networkContact : networkContacts) {
|
||||
networkMap.put(networkContact.getId(), networkContact);
|
||||
}
|
||||
|
||||
// 本地联系人:以 id 为 key
|
||||
Map<Long, ContactInfo> localMap = new HashMap<>();
|
||||
for (ContactInfo localContact : localContacts) {
|
||||
localMap.put(localContact.getId(), localContact);
|
||||
}
|
||||
|
||||
Logger.e(TAG, "网络联系人数量: " + networkMap.size() + ", 本地联系人数量: " + localMap.size());
|
||||
|
||||
// 1. 处理新增和更新:遍历网络联系人
|
||||
for (ContactInfo networkContact : networkContacts) {
|
||||
ContactInfo localContact = localMap.get(networkContact.getId());
|
||||
|
||||
if (localContact == null) {
|
||||
// 本地不存在,需要新增
|
||||
Logger.e(TAG, "新增联系人: " + networkContact.getName());
|
||||
networkContact.setSyncStatus(SYNC_STATUS_SYNCED);
|
||||
networkContact.setLocalId(null);
|
||||
mRepository.insert(networkContact);
|
||||
} else {
|
||||
// 本地存在,检查是否需要更新(比较 updateTime)
|
||||
if (networkContact.getUpdateTime() > localContact.getUpdateTime()) {
|
||||
Logger.e(TAG, "更新联系人: " + networkContact.getName());
|
||||
networkContact.setSyncStatus(SYNC_STATUS_SYNCED);
|
||||
networkContact.setLocalId(localContact.getLocalId());
|
||||
mRepository.update(networkContact);
|
||||
} else {
|
||||
Logger.e(TAG, "联系人无变化: " + networkContact.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理删除:遍历本地联系人,找出网络中不存在的
|
||||
for (ContactInfo localContact : localContacts) {
|
||||
if (!networkMap.containsKey(localContact.getId())) {
|
||||
if (localContact.getSyncStatus() == SYNC_STATUS_SYNCED) {
|
||||
Logger.e(TAG, "删除联系人: " + localContact.getName());
|
||||
mRepository.delete(localContact);
|
||||
} else {
|
||||
Logger.e(TAG, "联系人未同步,不删除: " + localContact.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.e(TAG, "联系人同步完成");
|
||||
}
|
||||
|
||||
public void compareContacts(List<ContactInfo> networkContacts, List<ContactInfo> localContacts) {
|
||||
Logger.e(TAG, "开始比较联系人数据");
|
||||
|
||||
// 创建 Map 以便快速查找
|
||||
// 网络联系人:以 id 为 key
|
||||
Map<Long, ContactInfo> networkMap = new HashMap<>();
|
||||
for (ContactInfo networkContact : networkContacts) {
|
||||
networkMap.put(networkContact.getId(), networkContact);
|
||||
}
|
||||
|
||||
// 本地联系人:以 id 为 key
|
||||
Map<Long, ContactInfo> localMap = new HashMap<>();
|
||||
for (ContactInfo localContact : localContacts) {
|
||||
localMap.put(localContact.getId(), localContact);
|
||||
}
|
||||
|
||||
Logger.e(TAG, "网络联系人数量: " + networkMap.size() + ", 本地联系人数量: " + localMap.size());
|
||||
|
||||
// 1. 处理新增和更新:遍历网络联系人
|
||||
for (ContactInfo networkContact : networkContacts) {
|
||||
ContactInfo localContact = localMap.get(networkContact.getId());
|
||||
|
||||
if (localContact == null) {
|
||||
// 本地不存在,需要新增
|
||||
Logger.e(TAG, "新增联系人: " + networkContact.getName());
|
||||
networkContact.setSyncStatus(SYNC_STATUS_SYNCED);
|
||||
networkContact.setLocalId(null);
|
||||
// mRepository.insert(networkContact);
|
||||
} else {
|
||||
// 本地存在,检查是否需要更新(比较 updateTime)
|
||||
if (networkContact.getUpdateTime() > localContact.getUpdateTime()) {
|
||||
Logger.e(TAG, "更新联系人: " + networkContact.getName());
|
||||
networkContact.setSyncStatus(SYNC_STATUS_SYNCED);
|
||||
networkContact.setLocalId(localContact.getLocalId());
|
||||
// mRepository.update(networkContact);
|
||||
} else {
|
||||
Logger.e(TAG, "联系人无变化: " + networkContact.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理删除:遍历本地联系人,找出网络中不存在的
|
||||
for (ContactInfo localContact : localContacts) {
|
||||
if (!networkMap.containsKey(localContact.getId())) {
|
||||
if (localContact.getSyncStatus() == SYNC_STATUS_SYNCED) {
|
||||
Logger.e(TAG, "删除联系人: " + localContact.getName());
|
||||
// mRepository.delete(localContact);
|
||||
} else {
|
||||
Logger.e(TAG, "联系人未同步,不删除: " + localContact.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.e(TAG, "联系人比较完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 联系人回调接口
|
||||
*/
|
||||
public interface ContactCallback {
|
||||
void onSuccess(List<ContactInfo> contacts);
|
||||
|
||||
void onFailure(Throwable e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.ttstd.dialer.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.db.contact.ContactRepository;
|
||||
import com.ttstd.dialer.db.contact.SyncStatus;
|
||||
import com.ttstd.dialer.network.OkHttpManager;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class ContactSyncManager {
|
||||
private static final String TAG = "ContactSyncManager";
|
||||
private static volatile ContactSyncManager INSTANCE;
|
||||
|
||||
private ContactRepository mRepository;
|
||||
private CompositeDisposable mDisposable;
|
||||
|
||||
private ContactSyncManager(Context context) {
|
||||
mRepository = new ContactRepository(context);
|
||||
mDisposable = new CompositeDisposable();
|
||||
}
|
||||
|
||||
public static ContactSyncManager getInstance(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (ContactSyncManager.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new ContactSyncManager(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void syncPendingContacts() {
|
||||
Observable.fromCallable(() -> {
|
||||
List<ContactInfo> pendingContacts = mRepository.getUnsyncedContacts();
|
||||
Logger.d(TAG, "查询到 " + pendingContacts.size() + " 个待同步联系人");
|
||||
return pendingContacts;
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.flatMapIterable(pendingContacts -> pendingContacts)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.flatMap(contactInfo -> syncSingleContactObservable(contactInfo))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
result -> Logger.d(TAG, "同步完成: " + result),
|
||||
throwable -> Logger.e(TAG, "同步流程异常: " + throwable.getMessage())
|
||||
);
|
||||
}
|
||||
|
||||
private Observable<String> syncSingleContactObservable(ContactInfo contactInfo) {
|
||||
return OkHttpManager.getInstance().getContactInsertObservable(contactInfo)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.flatMap(baseResponse -> {
|
||||
if (baseResponse.isSuccess()) {
|
||||
Long onlineId = baseResponse.getData();
|
||||
return saveSuccessSyncStatus(contactInfo.getId(), onlineId)
|
||||
.map(v -> "成功: " + contactInfo.getName());
|
||||
} else {
|
||||
return saveFailedSyncStatus(contactInfo.getId())
|
||||
.flatMap(v -> Observable.error(new Exception("业务失败: " + baseResponse.getMsg())));
|
||||
}
|
||||
})
|
||||
.onErrorResumeNext(throwable -> {
|
||||
return saveFailedSyncStatus(contactInfo.getId())
|
||||
.map(v -> "失败: " + contactInfo.getName());
|
||||
});
|
||||
}
|
||||
|
||||
private Observable<Object> saveSuccessSyncStatus(long contactId, Long onlineId) {
|
||||
return Observable.fromAction(() -> {
|
||||
mRepository.updateSyncStatus(contactId, SyncStatus.SYNCED, onlineId, System.currentTimeMillis());
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
private Observable<Object> saveFailedSyncStatus(long contactId) {
|
||||
return Observable.fromAction(() -> {
|
||||
mRepository.updateSyncStatusById(contactId, SyncStatus.FAILED);
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (!mDisposable.isDisposed()) {
|
||||
mDisposable.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ import com.tencent.mmkv.MMKV;
|
||||
import com.ttstd.dialer.bean.req.SnLocationReq;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.gson.GsonUtils;
|
||||
import com.ttstd.dialer.mdm.DeviceManagerService;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.utils.SystemUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -258,7 +258,7 @@ public class MapManager {
|
||||
mMMKV.encode("MapError", "-");
|
||||
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("sn", SystemUtils.getSerial());
|
||||
params.put("sn", DeviceManagerService.getInstance().getSerial());
|
||||
params.put("address", bdLocation.getAddrStr());
|
||||
params.put("location_describe", bdLocation.getLocationDescribe());
|
||||
params.put("longitude", bdLocation.getLongitude());
|
||||
|
||||
@@ -15,9 +15,11 @@ import com.qweather.sdk.response.error.ErrorResponse;
|
||||
import com.qweather.sdk.response.weather.WeatherDailyResponse;
|
||||
import com.qweather.sdk.response.weather.WeatherHourlyResponse;
|
||||
import com.qweather.sdk.response.weather.WeatherNowResponse;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.ttstd.dialer.BuildConfig;
|
||||
import com.ttstd.dialer.bean.CityInfo;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.gson.GsonUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.utils.NativeUtils;
|
||||
|
||||
@@ -34,26 +36,30 @@ import io.reactivex.rxjava3.core.ObservableOnSubscribe;
|
||||
import io.reactivex.rxjava3.core.Observer;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import kotlinx.coroutines.CoroutineScope;
|
||||
import kotlinx.coroutines.CoroutineStart;
|
||||
import kotlinx.coroutines.Dispatchers;
|
||||
import kotlinx.coroutines.GlobalScope;
|
||||
|
||||
public class WeatherManager {
|
||||
private static final String TAG = "WeatherManager";
|
||||
|
||||
private static final String WEATHER_NOW_CACHE = "weather_now_cache_key";
|
||||
private static final String WEATHER_24_HOUR_CACHE = "weather_24_hour_cache";
|
||||
private static final String WEATHER_10_DAY_CACHE = "weather_10_day_cache";
|
||||
|
||||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static WeatherManager INSTANCE;
|
||||
private static volatile WeatherManager INSTANCE;
|
||||
private Context mContext;
|
||||
private QWeather mQWeather;
|
||||
private Map<String, String> LocationIDMap = new HashMap<>();
|
||||
private boolean loadCsvFinish = false;
|
||||
private String mAdCode;
|
||||
private WeatherUpdateManager weatherUpdateManager;
|
||||
private String mLocationId;
|
||||
private WeatherUpdateManager mWeatherUpdateManager;
|
||||
|
||||
private WeatherManager(Context context) {
|
||||
this.mContext = context.getApplicationContext();
|
||||
weatherUpdateManager = WeatherUpdateManager.Companion.getInstance();
|
||||
mWeatherUpdateManager = WeatherUpdateManager.Companion.getInstance();
|
||||
mAdCode = mMMKV.decodeString(CommonConfig.CURRENT_LOCATION_AD_CODE_KEY, "");
|
||||
initCsv();
|
||||
try {
|
||||
// 通过SDK提供的JWTGenerator设置令牌生成器,其实现自TokenGenerator接口
|
||||
@@ -67,11 +73,29 @@ public class WeatherManager {
|
||||
Logger.e(TAG, "QWeatherUtils: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
WeatherNowResponse weatherNowResponse = getWeatherNowCache();
|
||||
if (weatherNowResponse != null) {
|
||||
mWeatherUpdateManager.publishWeatherNowUpdate(weatherNowResponse);
|
||||
|
||||
}
|
||||
WeatherHourlyResponse weatherHourlyResponse = getWeather24hCache();
|
||||
if (weatherHourlyResponse != null) {
|
||||
mWeatherUpdateManager.publishWeatherHourlyUpdate(weatherHourlyResponse);
|
||||
}
|
||||
WeatherDailyResponse weatherDailyResponse = getWeather10DCache();
|
||||
if (weatherDailyResponse != null) {
|
||||
mWeatherUpdateManager.publishWeatherDailyUpdate(weatherDailyResponse);
|
||||
}
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new WeatherManager(context);
|
||||
synchronized (WeatherManager.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new WeatherManager(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,16 +122,20 @@ public class WeatherManager {
|
||||
}
|
||||
}
|
||||
|
||||
public String getAdCode() {
|
||||
return mAdCode;
|
||||
}
|
||||
|
||||
private void initCsv() {
|
||||
Observable.create(new ObservableOnSubscribe<List<CityInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<CityInfo>> emitter) throws Throwable {
|
||||
long time = System.currentTimeMillis();
|
||||
List<CityInfo> cityInfos = CsvDeserializer.deserializeFromAssets(mContext, "China-City-List-latest.csv");
|
||||
Logger.e(TAG, "subscribe: deserializeFromAssets time = " + (System.currentTimeMillis() - time) + "ms");
|
||||
emitter.onNext(cityInfos);
|
||||
}
|
||||
})
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<CityInfo>> emitter) throws Throwable {
|
||||
long time = System.currentTimeMillis();
|
||||
List<CityInfo> cityInfos = CsvDeserializer.deserializeFromAssets(mContext, "China-City-List-latest.csv");
|
||||
Logger.e(TAG, "subscribe: deserializeFromAssets time = " + (System.currentTimeMillis() - time) + "ms");
|
||||
emitter.onNext(cityInfos);
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<CityInfo>>() {
|
||||
@@ -155,9 +183,19 @@ public class WeatherManager {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void getWeatherNow(String adCode, Callback<WeatherNowResponse> callback) {
|
||||
public void refreshweather() {
|
||||
if (!TextUtils.isEmpty(mAdCode)) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void getWeatherNowAdCode(String adCode, Callback<WeatherNowResponse> callback) {
|
||||
String locationID = getLocationID(adCode);
|
||||
Logger.e(TAG, "getWeatherNow: locationID = " + locationID);
|
||||
Logger.e(TAG, "getWeatherNowAdCode: locationID = " + locationID);
|
||||
getWeatherNow(locationID, callback);
|
||||
}
|
||||
|
||||
public void getWeatherNow(String locationID, Callback<WeatherNowResponse> callback) {
|
||||
WeatherParameter parameter = new WeatherParameter(locationID)
|
||||
.lang(Lang.ZH_HANS)
|
||||
.unit(Unit.METRIC);
|
||||
@@ -165,7 +203,9 @@ public class WeatherManager {
|
||||
@Override
|
||||
public void onSuccess(WeatherNowResponse weatherNowResponse) {
|
||||
Logger.e(TAG, "getWeatherNow", "onSuccess: " + weatherNowResponse);
|
||||
weatherUpdateManager.publishWeatherNowUpdate(weatherNowResponse);
|
||||
mWeatherUpdateManager.publishWeatherNowUpdate(weatherNowResponse);
|
||||
mMMKV.encode(WEATHER_NOW_CACHE, GsonUtils.toJSONString(weatherNowResponse));
|
||||
|
||||
if (callback != null) {
|
||||
callback.onSuccess(weatherNowResponse);
|
||||
}
|
||||
@@ -187,17 +227,23 @@ public class WeatherManager {
|
||||
});
|
||||
}
|
||||
|
||||
public void getWeather24h(String adCode, Callback<WeatherHourlyResponse> callback) {
|
||||
public void getWeather24HourAdCode(String adCode, Callback<WeatherHourlyResponse> callback) {
|
||||
String locationID = getLocationID(adCode);
|
||||
Logger.e(TAG, "getWeatherNow: locationID = " + locationID);
|
||||
Logger.e(TAG, "getWeather24HourAdCode: locationID = " + locationID);
|
||||
getWeather24Hour(locationID, callback);
|
||||
}
|
||||
|
||||
public void getWeather24Hour(String locationID, Callback<WeatherHourlyResponse> callback) {
|
||||
WeatherParameter parameter = new WeatherParameter(locationID)
|
||||
.lang(Lang.ZH_HANS)
|
||||
.unit(Unit.METRIC);
|
||||
mQWeather.weather24h(parameter, new Callback<WeatherHourlyResponse>() {
|
||||
@Override
|
||||
public void onSuccess(WeatherHourlyResponse weatherHourlyResponse) {
|
||||
Logger.e(TAG, "getWeather24h", "onSuccess: " + weatherHourlyResponse);
|
||||
weatherUpdateManager.publishWeatherHourlyUpdate(weatherHourlyResponse);
|
||||
Logger.e(TAG, "getWeather24Hour", "onSuccess: " + weatherHourlyResponse);
|
||||
mWeatherUpdateManager.publishWeatherHourlyUpdate(weatherHourlyResponse);
|
||||
mMMKV.encode(WEATHER_24_HOUR_CACHE, GsonUtils.toJSONString(weatherHourlyResponse));
|
||||
|
||||
if (callback != null) {
|
||||
callback.onSuccess(weatherHourlyResponse);
|
||||
}
|
||||
@@ -219,17 +265,23 @@ public class WeatherManager {
|
||||
});
|
||||
}
|
||||
|
||||
public void getWeather10D(String adCode, Callback<WeatherDailyResponse> callback) {
|
||||
public void getWeather10DayAdCode(String adCode, Callback<WeatherDailyResponse> callback) {
|
||||
String locationID = getLocationID(adCode);
|
||||
Logger.e(TAG, "getWeather10D: locationID = " + locationID);
|
||||
Logger.e(TAG, "getWeather10Day: locationID = " + locationID);
|
||||
getWeather10Day(locationID, callback);
|
||||
}
|
||||
|
||||
public void getWeather10Day(String locationID, Callback<WeatherDailyResponse> callback) {
|
||||
WeatherParameter parameter = new WeatherParameter(locationID)
|
||||
.lang(Lang.ZH_HANS)
|
||||
.unit(Unit.METRIC);
|
||||
mQWeather.weather10d(parameter, new Callback<WeatherDailyResponse>() {
|
||||
@Override
|
||||
public void onSuccess(WeatherDailyResponse weatherDailyResponse) {
|
||||
Logger.e(TAG, "getWeather10D", "onSuccess: " + weatherDailyResponse);
|
||||
weatherUpdateManager.publishWeatherDailyUpdate(weatherDailyResponse);
|
||||
Logger.e(TAG, "getWeather10Day", "onSuccess: " + weatherDailyResponse);
|
||||
mWeatherUpdateManager.publishWeatherDailyUpdate(weatherDailyResponse);
|
||||
mMMKV.encode(WEATHER_10_DAY_CACHE, GsonUtils.toJSONString(weatherDailyResponse));
|
||||
|
||||
if (callback != null) {
|
||||
callback.onSuccess(weatherDailyResponse);
|
||||
}
|
||||
@@ -251,5 +303,28 @@ public class WeatherManager {
|
||||
});
|
||||
}
|
||||
|
||||
public WeatherNowResponse getWeatherNowCache() {
|
||||
String weatherNowCache = mMMKV.decodeString(WEATHER_NOW_CACHE);
|
||||
if (!TextUtils.isEmpty(weatherNowCache)) {
|
||||
return GsonUtils.toJavaObject(weatherNowCache, WeatherNowResponse.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public WeatherHourlyResponse getWeather24hCache() {
|
||||
String weather24hCache = mMMKV.decodeString(WEATHER_24_HOUR_CACHE);
|
||||
if (!TextUtils.isEmpty(weather24hCache)) {
|
||||
return GsonUtils.toJavaObject(weather24hCache, WeatherHourlyResponse.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public WeatherDailyResponse getWeather10DCache() {
|
||||
String weather10DCache = mMMKV.decodeString(WEATHER_10_DAY_CACHE);
|
||||
if (!TextUtils.isEmpty(weather10DCache)) {
|
||||
return GsonUtils.toJavaObject(weather10DCache, WeatherDailyResponse.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,15 +13,18 @@ import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.bean.DeveloperOptions;
|
||||
import com.ttstd.dialer.bean.req.SnHardwareInfoReq;
|
||||
import com.ttstd.dialer.bean.req.SnLocationReq;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.mdm.DeviceManagerService;
|
||||
import com.ttstd.dialer.network.api.ContactApi;
|
||||
import com.ttstd.dialer.network.api.SnApi;
|
||||
import com.ttstd.dialer.network.interceptor.AuthInterceptor;
|
||||
import com.ttstd.dialer.utils.FileUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.utils.SystemUtils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
@@ -48,7 +51,7 @@ public class OkHttpManager {
|
||||
private static final String TAG = "OkHttpManager";
|
||||
|
||||
// 超时时间(抽成常量,便于统一维护)
|
||||
private static final int DEFAULT_TIMEOUT_SECONDS = 5;
|
||||
private static final int DEFAULT_TIMEOUT_SECONDS = 30;
|
||||
// 缓存大小 64MB(使用更语义化的命名)
|
||||
private static final long CACHE_SIZE_BYTES = 1024 * 1024 * 64L;
|
||||
// 缓存目录名称(避免硬编码)
|
||||
@@ -296,6 +299,10 @@ public class OkHttpManager {
|
||||
.compose(RxLifecycle.bindUntilEvent(provider, ActivityEvent.DESTROY));
|
||||
}
|
||||
|
||||
public <T> T getApiService(Class<T> tClass) {
|
||||
return mRetrofit.create(tClass);
|
||||
}
|
||||
|
||||
public <T> Observable<T> schedule(Observable<T> observable) {
|
||||
return observable
|
||||
// 子线程执行请求
|
||||
@@ -305,36 +312,61 @@ public class OkHttpManager {
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getSnRegisterObservable(BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(mRetrofit.create(SnApi.class).register(SystemUtils.getSerial(), Build.MODEL), provider);
|
||||
return schedule(getApiService(SnApi.class).register(DeviceManagerService.getInstance().getSerial(), Build.MODEL), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<Void>> getUpdateHardwareInfoObservable(SnHardwareInfoReq snHardwareInfoReq) {
|
||||
RequestBody body = convertToRequestBodyjson(snHardwareInfoReq);
|
||||
return schedule(mRetrofit.create(SnApi.class).updateHardwareInfo(body));
|
||||
return schedule(getApiService(SnApi.class).updateHardwareInfo(body));
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getUploadScreenshotObservable(MultipartBody.Part part) {
|
||||
return schedule(mRetrofit.create(SnApi.class).uploadScreenshot(part));
|
||||
return schedule(getApiService(SnApi.class).uploadScreenshot(part));
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getUploadLocationObservable(SnLocationReq locationReq, BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(mRetrofit.create(SnApi.class).uploadLocation(convertToRequestBodyjson(locationReq)), provider);
|
||||
return schedule(getApiService(SnApi.class).uploadLocation(convertToRequestBodyjson(locationReq)), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getUploadLocationObservable(SnLocationReq locationReq) {
|
||||
return schedule(mRetrofit.create(SnApi.class).uploadLocation(convertToRequestBodyjson(locationReq)));
|
||||
return schedule(getApiService(SnApi.class).uploadLocation(convertToRequestBodyjson(locationReq)));
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<DeveloperOptions>> getDeveloperOptionsObservable(BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(mRetrofit.create(SnApi.class).getDeveloperOptions(), provider);
|
||||
return schedule(getApiService(SnApi.class).getDeveloperOptions(), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<DeveloperOptions>> getDeveloperOptionsObservable() {
|
||||
return schedule(mRetrofit.create(SnApi.class).getDeveloperOptions());
|
||||
return schedule(getApiService(SnApi.class).getDeveloperOptions());
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getUploadInstallApksObservable(RequestBody body) {
|
||||
return schedule(mRetrofit.create(SnApi.class).uploadInstallApks(body));
|
||||
return schedule(getApiService(SnApi.class).uploadInstallApks(body));
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<List<ContactInfo>>> getContactListObservable(BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(getApiService(ContactApi.class).getContactList(), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<Long>> getContactInsertObservable(ContactInfo contactInfo, BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(getApiService(ContactApi.class).insertContact(convertToRequestBodyjson(contactInfo)), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<Long>> getContactInsertObservable(ContactInfo contactInfo) {
|
||||
return schedule(getApiService(ContactApi.class).insertContact(convertToRequestBodyjson(contactInfo)));
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<ContactInfo>> getContactFormObservable(long id, BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(getApiService(ContactApi.class).getContactForm(id), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<Void>> getContactUpdateObservable(long id, ContactInfo contactInfo, BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(getApiService(ContactApi.class).updateContact(id, convertToRequestBodyjson(contactInfo)), provider);
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getContactDeleteObservable(long id, BehaviorSubject<ActivityEvent> provider) {
|
||||
return schedule(getApiService(ContactApi.class).deleteContact(id), provider);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,4 +16,11 @@ public class UrlConstants {
|
||||
/*上传设备已安装应用列表*/
|
||||
public static final String UPLOAD_INSTALL_APKS = "upload_install_apks";
|
||||
|
||||
|
||||
public static final String CONTACT_LIST = "contact/list";
|
||||
public static final String CONTACT_INSERT = "contact/insert";
|
||||
public static final String CONTACT_FORM = "contact/form";
|
||||
public static final String CONTACT_UPDATE = "contact/update";
|
||||
public static final String CONTACT_DELETE = "contact/delete";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ttstd.dialer.network.api;
|
||||
|
||||
import com.ttstd.dialer.bean.BaseResponse;
|
||||
import com.ttstd.dialer.db.contact.ContactInfo;
|
||||
import com.ttstd.dialer.network.UrlConstants;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import okhttp3.RequestBody;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface ContactApi {
|
||||
@GET(UrlConstants.CONTACT_LIST)
|
||||
Observable<BaseResponse<List<ContactInfo>>> getContactList(
|
||||
);
|
||||
|
||||
@POST(UrlConstants.CONTACT_INSERT)
|
||||
Observable<BaseResponse<Long>> insertContact(
|
||||
@Body RequestBody body
|
||||
);
|
||||
|
||||
@GET(UrlConstants.CONTACT_FORM)
|
||||
Observable<BaseResponse<ContactInfo>> getContactForm(
|
||||
@Query("id") Long id
|
||||
);
|
||||
|
||||
@PUT(UrlConstants.CONTACT_UPDATE)
|
||||
Observable<BaseResponse<Void>> updateContact(
|
||||
@Query("id") long id,
|
||||
@Body RequestBody body
|
||||
);
|
||||
|
||||
@DELETE(UrlConstants.CONTACT_DELETE)
|
||||
Observable<BaseResponse> deleteContact(
|
||||
@Query("id") Long id
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.ttstd.dialer.network.interceptor;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.ttstd.dialer.mdm.DeviceManagerService;
|
||||
@@ -51,6 +53,10 @@ public class AuthInterceptor implements Interceptor {
|
||||
headersMap.put("X-Timestamp", String.valueOf(timestamp));
|
||||
String sign = SecurityUtils.generateSign(headersMap);
|
||||
headersMap.put("X-Sign", sign);
|
||||
Log.e("AuthInterceptor", "intercept: X-Device-SN = " + sn);
|
||||
Log.e("AuthInterceptor", "intercept: X-Nonce = " + nonce);
|
||||
Log.e("AuthInterceptor", "intercept: X-Timestamp = " + timestamp);
|
||||
Log.e("AuthInterceptor", "intercept: X-Sign = " + sign);
|
||||
|
||||
// 2. 构建请求头(所有参数放header,防止URL被抓包泄露)
|
||||
Headers headers = Headers.of(headersMap);
|
||||
|
||||
@@ -16,6 +16,7 @@ import android.view.WindowManager;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.blankj.utilcode.util.NetworkUtils;
|
||||
import com.hjq.toast.Toaster;
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus;
|
||||
import com.shehuan.niv.NiceImageView;
|
||||
@@ -26,6 +27,7 @@ import com.ttstd.dialer.activity.main.MainActivity;
|
||||
import com.ttstd.dialer.base.BaseService;
|
||||
import com.ttstd.dialer.bean.req.SnLocationReq;
|
||||
import com.ttstd.dialer.config.CommonConfig;
|
||||
import com.ttstd.dialer.manager.ContactSyncManager;
|
||||
import com.ttstd.dialer.utils.ApkUtils;
|
||||
import com.ttstd.dialer.utils.Logger;
|
||||
import com.ttstd.dialer.utils.SystemUtils;
|
||||
@@ -34,7 +36,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class MainService extends BaseService {
|
||||
public class MainService extends BaseService implements NetworkUtils.OnNetworkStatusChangedListener {
|
||||
private static final String TAG = "MainService";
|
||||
|
||||
public static final String SHOW_FLOAT_WINDOW_ACTION = "show_float_window";
|
||||
@@ -50,6 +52,17 @@ public class MainService extends BaseService {
|
||||
private WindowManager.LayoutParams mLayoutParams;
|
||||
private boolean mFloatWindowShowing = false;
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
Logger.e(TAG, "onDisconnected: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(NetworkUtils.NetworkType networkType) {
|
||||
Logger.e(TAG, "onConnected: networkType = " + networkType);
|
||||
ContactSyncManager.getInstance(this).syncPendingContacts();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
@@ -60,6 +73,9 @@ public class MainService extends BaseService {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Logger.e(TAG, "onCreate: ");
|
||||
|
||||
NetworkUtils.registerNetworkStatusChangedListener(this);
|
||||
|
||||
// 初始化ViewModel(绑定上下文+View回调)
|
||||
mViewModel = new MainServiceModel();
|
||||
// 绑定Service生命周期(关键:让请求跟随生命周期)
|
||||
@@ -250,6 +266,7 @@ public class MainService extends BaseService {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
NetworkUtils.unregisterNetworkStatusChangedListener(this);
|
||||
// 务必在服务销毁时移除 View,防止内存泄漏或系统崩溃
|
||||
if (floatingView != null) {
|
||||
mWindowManager.removeView(floatingView);
|
||||
@@ -275,4 +292,6 @@ public class MainService extends BaseService {
|
||||
public void onRebind(Intent intent) {
|
||||
super.onRebind(intent);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
212
app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java
Normal file
212
app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java
Normal file
@@ -0,0 +1,212 @@
|
||||
package com.ttstd.dialer.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.util.LruCache;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
public class AvatarCacheUtil {
|
||||
// 柔和背景色
|
||||
private static final int[] COLORS = {
|
||||
0xFFE57373, 0xFFBA68C8, 0xFF4FC3F7, 0xFF4DD0E1,
|
||||
0xFF81C784, 0xFFFFF176, 0xFFFFB74D, 0xFF9575CD
|
||||
};
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
// 内存缓存 LruCache
|
||||
private static LruCache<String, Bitmap> mMemoryCache;
|
||||
// 缓存文件夹名
|
||||
private static final String CACHE_DIR_NAME = "avatar_cache";
|
||||
|
||||
static {
|
||||
// 初始化内存缓存:最大占用1/8应用可用内存
|
||||
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
|
||||
int cacheSize = maxMemory / 8;
|
||||
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
|
||||
@Override
|
||||
protected int sizeOf(String key, Bitmap bitmap) {
|
||||
return bitmap.getByteCount() / 1024;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// dp转px
|
||||
private static int dp2px(Context context, float dp) {
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * density + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外统一获取头像(优先内存→本地→重新生成)
|
||||
*/
|
||||
public static Bitmap getAvatar(Context context, String name, int size, boolean isCircle) {
|
||||
if (name == null) name = "";
|
||||
String cacheKey = getCacheKey(name, size, isCircle);
|
||||
|
||||
// 1.查内存缓存
|
||||
Bitmap memoryBitmap = getMemoryCache(cacheKey);
|
||||
if (memoryBitmap != null) {
|
||||
return memoryBitmap;
|
||||
}
|
||||
|
||||
// 2.查本地磁盘缓存
|
||||
Bitmap diskBitmap = getDiskCache(context, cacheKey);
|
||||
if (diskBitmap != null) {
|
||||
// 存入内存
|
||||
putMemoryCache(cacheKey, diskBitmap);
|
||||
return diskBitmap;
|
||||
}
|
||||
|
||||
// 3.都没有,重新生成
|
||||
Bitmap newBitmap = generateAvatar(name, size, isCircle);
|
||||
// 存入双层缓存
|
||||
putMemoryCache(cacheKey, newBitmap);
|
||||
putDiskCache(context, cacheKey, newBitmap);
|
||||
return newBitmap;
|
||||
}
|
||||
|
||||
public static Bitmap getAvatar(Context context, String name) {
|
||||
if (name == null) name = "";
|
||||
String cacheKey = getCacheKey(name, dp2px(context, 50), true);
|
||||
|
||||
// 1.查内存缓存
|
||||
Bitmap memoryBitmap = getMemoryCache(cacheKey);
|
||||
if (memoryBitmap != null) {
|
||||
return memoryBitmap;
|
||||
}
|
||||
|
||||
// 2.查本地磁盘缓存
|
||||
Bitmap diskBitmap = getDiskCache(context, cacheKey);
|
||||
if (diskBitmap != null) {
|
||||
// 存入内存
|
||||
putMemoryCache(cacheKey, diskBitmap);
|
||||
return diskBitmap;
|
||||
}
|
||||
|
||||
// 3.都没有,重新生成
|
||||
Bitmap newBitmap = generateAvatar(name, dp2px(context, 50), true);
|
||||
// 存入双层缓存
|
||||
putMemoryCache(cacheKey, newBitmap);
|
||||
putDiskCache(context, cacheKey, newBitmap);
|
||||
return newBitmap;
|
||||
}
|
||||
|
||||
// ========== 内存缓存操作 ==========
|
||||
private static void putMemoryCache(String key, Bitmap bitmap) {
|
||||
if (getMemoryCache(key) == null) {
|
||||
mMemoryCache.put(key, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap getMemoryCache(String key) {
|
||||
return mMemoryCache.get(key);
|
||||
}
|
||||
|
||||
// ========== 本地磁盘缓存操作 ==========
|
||||
private static File getCacheDir(Context context) {
|
||||
File cacheDir = new File(context.getExternalCacheDir(), CACHE_DIR_NAME);
|
||||
if (!cacheDir.exists()) {
|
||||
cacheDir.mkdirs();
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
private static void putDiskCache(Context context, String key, Bitmap bitmap) {
|
||||
File file = new File(getCacheDir(context), key + ".png");
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap getDiskCache(Context context, String key) {
|
||||
File file = new File(getCacheDir(context), key + ".png");
|
||||
if (!file.exists()) return null;
|
||||
return BitmapFactory.decodeFile(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
// ========== 生成唯一缓存Key ==========
|
||||
private static String getCacheKey(String name, int size, boolean isCircle) {
|
||||
// 名字+尺寸+形状 组合唯一key,避免不同尺寸头像冲突
|
||||
return name.trim() + "_" + size + "_" + (isCircle ? "circle" : "square");
|
||||
}
|
||||
|
||||
// ========== 核心绘制头像方法 ==========
|
||||
private static Bitmap generateAvatar(String name, int size, boolean isCircle) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
bgPaint.setColor(getRandomColor());
|
||||
if (isCircle) {
|
||||
float r = size / 2f;
|
||||
canvas.drawCircle(r, r, r, bgPaint);
|
||||
} else {
|
||||
canvas.drawRect(0, 0, size, size, bgPaint);
|
||||
}
|
||||
|
||||
String text = getFirstChar(name);
|
||||
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
textPaint.setColor(Color.WHITE);
|
||||
textPaint.setTextSize(size * 0.4f);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
|
||||
Rect rect = new Rect();
|
||||
textPaint.getTextBounds(text, 0, text.length(), rect);
|
||||
float centerY = size / 2f + (rect.bottom - rect.top) / 2f - rect.bottom;
|
||||
canvas.drawText(text, size / 2f, centerY, textPaint);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static String getFirstChar(String name) {
|
||||
if (name == null || name.trim().isEmpty()) return "A";
|
||||
return String.valueOf(name.trim().charAt(0)).toUpperCase();
|
||||
}
|
||||
|
||||
private static int getRandomColor() {
|
||||
return COLORS[RANDOM.nextInt(COLORS.length)];
|
||||
}
|
||||
|
||||
// ========== 清除缓存方法 ==========
|
||||
|
||||
/**
|
||||
* 清除内存缓存
|
||||
*/
|
||||
public static void clearMemoryCache() {
|
||||
mMemoryCache.evictAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除本地所有头像缓存
|
||||
*/
|
||||
public static void clearDiskCache(Context context) {
|
||||
File dir = getCacheDir(context);
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
368
app/src/main/java/com/ttstd/dialer/utils/GlideUtils.java
Normal file
368
app/src/main/java/com/ttstd/dialer/utils/GlideUtils.java
Normal file
@@ -0,0 +1,368 @@
|
||||
package com.ttstd.dialer.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.ttstd.dialer.glide.GlideApp;
|
||||
|
||||
/**
|
||||
* Glide 图片加载工具类
|
||||
* 包含 Activity/Fragment 生命周期检查和常用加载方法
|
||||
*/
|
||||
public class GlideUtils {
|
||||
|
||||
private static final String TAG = "GlideUtils";
|
||||
|
||||
/**
|
||||
* 检查 Activity 是否有效(未销毁且未 finishing)
|
||||
*
|
||||
* @param activity Activity
|
||||
* @return true: 有效, false: 已销毁或正在销毁
|
||||
*/
|
||||
public static boolean isActivityValid(@Nullable Activity activity) {
|
||||
if (activity == null) {
|
||||
Logger.w(TAG, "Activity is null");
|
||||
return false;
|
||||
}
|
||||
if (activity.isFinishing()) {
|
||||
Logger.w(TAG, "Activity is finishing: " + activity.getClass().getSimpleName());
|
||||
return false;
|
||||
}
|
||||
if (activity.isDestroyed()) {
|
||||
Logger.w(TAG, "Activity is destroyed: " + activity.getClass().getSimpleName());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 FragmentActivity 是否有效
|
||||
*
|
||||
* @param activity FragmentActivity
|
||||
* @return true: 有效, false: 已销毁或正在销毁
|
||||
*/
|
||||
public static boolean isFragmentActivityValid(@Nullable FragmentActivity activity) {
|
||||
if (activity == null) {
|
||||
Logger.w(TAG, "FragmentActivity is null");
|
||||
return false;
|
||||
}
|
||||
return isActivityValid(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Fragment 是否有效
|
||||
*
|
||||
* @param fragment Fragment
|
||||
* @return true: 有效, false: 未附加或 Activity 已销毁
|
||||
*/
|
||||
public static boolean isFragmentValid(@Nullable Fragment fragment) {
|
||||
if (fragment == null) {
|
||||
Logger.w(TAG, "Fragment is null");
|
||||
return false;
|
||||
}
|
||||
if (!fragment.isAdded()) {
|
||||
Logger.w(TAG, "Fragment is not added");
|
||||
return false;
|
||||
}
|
||||
Activity activity = fragment.getActivity();
|
||||
return isActivityValid(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取 Glide RequestManager
|
||||
* 自动检查 Context 类型和生命周期状态
|
||||
*
|
||||
* @param context Context
|
||||
* @return RequestManager,如果 Context 无效则返回 null
|
||||
*/
|
||||
@Nullable
|
||||
public static RequestBuilder<Drawable> getSafeRequestManager(@Nullable Context context) {
|
||||
if (context == null) {
|
||||
Logger.w(TAG, "Context is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context instanceof FragmentActivity) {
|
||||
FragmentActivity activity = (FragmentActivity) context;
|
||||
if (!isFragmentActivityValid(activity)) {
|
||||
return null;
|
||||
}
|
||||
return GlideApp.with(activity).asDrawable();
|
||||
} else if (context instanceof Activity) {
|
||||
Activity activity = (Activity) context;
|
||||
if (!isActivityValid(activity)) {
|
||||
return null;
|
||||
}
|
||||
return GlideApp.with(activity).asDrawable();
|
||||
} else {
|
||||
// Application Context,无需检查生命周期
|
||||
return GlideApp.with(context).asDrawable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地加载图片到 ImageView
|
||||
* 自动检查 Activity 生命周期
|
||||
*
|
||||
* @param context Context
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
*/
|
||||
public static void loadImageSafe(@Nullable Context context, @Nullable String url, @NonNull ImageView imageView) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地加载图片到 ImageView(带占位图和错误图)
|
||||
*
|
||||
* @param context Context
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
* @param errorId 错误图资源ID
|
||||
*/
|
||||
public static void loadImageSafe(@Nullable Context context, @Nullable String url,
|
||||
@NonNull ImageView imageView,
|
||||
@DrawableRes int errorId) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.error(errorId)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
public static void loadImageSafe(@Nullable Context context, @Nullable String url,
|
||||
@NonNull ImageView imageView,
|
||||
Drawable drawable) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.error(drawable)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
public static void loadImageSafe(@Nullable Context context, @Nullable String url,
|
||||
@NonNull ImageView imageView,
|
||||
Bitmap bitmap) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.error(bitmap)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 安全地加载图片到 ImageView(带占位图和错误图)
|
||||
*
|
||||
* @param context Context
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
* @param placeholderId 占位图资源ID
|
||||
* @param errorId 错误图资源ID
|
||||
*/
|
||||
public static void loadImageSafe(@Nullable Context context, @Nullable String url,
|
||||
@NonNull ImageView imageView,
|
||||
@DrawableRes int placeholderId,
|
||||
@DrawableRes int errorId) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.placeholder(placeholderId)
|
||||
.error(errorId)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地加载 Bitmap 图片
|
||||
*
|
||||
* @param context Context
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
*/
|
||||
public static void loadBitmapSafe(@Nullable Context context, @Nullable String url, @NonNull ImageView imageView) {
|
||||
if (context == null || url == null) {
|
||||
Logger.w(TAG, "Context or URL is null");
|
||||
return;
|
||||
}
|
||||
|
||||
RequestBuilder<Bitmap> requestManager = null;
|
||||
|
||||
if (context instanceof FragmentActivity) {
|
||||
FragmentActivity activity = (FragmentActivity) context;
|
||||
if (!isFragmentActivityValid(activity)) {
|
||||
return;
|
||||
}
|
||||
requestManager = GlideApp.with(activity).asBitmap();
|
||||
} else if (context instanceof Activity) {
|
||||
Activity activity = (Activity) context;
|
||||
if (!isActivityValid(activity)) {
|
||||
return;
|
||||
}
|
||||
requestManager = GlideApp.with(activity).asBitmap();
|
||||
}
|
||||
|
||||
if (requestManager != null) {
|
||||
requestManager
|
||||
.load(url)
|
||||
.into(imageView);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地加载 Drawable 图片(带回调)
|
||||
*
|
||||
* @param context Context
|
||||
* @param url 图片URL
|
||||
* @param listener 加载回调监听器
|
||||
*/
|
||||
public static void loadWithListener(@Nullable Context context, @Nullable String url,
|
||||
@NonNull RequestListener<Drawable> listener) {
|
||||
RequestBuilder<Drawable> requestManager = getSafeRequestManager(context);
|
||||
if (requestManager == null) {
|
||||
Logger.w(TAG, "Skip loading image due to invalid context");
|
||||
return;
|
||||
}
|
||||
|
||||
requestManager
|
||||
.load(url)
|
||||
.listener(listener)
|
||||
.submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Fragment 安全地加载图片
|
||||
*
|
||||
* @param fragment Fragment
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
*/
|
||||
public static void loadImageFromFragment(@Nullable Fragment fragment, @Nullable String url,
|
||||
@NonNull ImageView imageView) {
|
||||
if (!isFragmentValid(fragment)) {
|
||||
Logger.w(TAG, "Skip loading from invalid fragment");
|
||||
return;
|
||||
}
|
||||
|
||||
GlideApp.with(fragment)
|
||||
.load(url)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Fragment 安全地加载图片(带占位图和错误图)
|
||||
*
|
||||
* @param fragment Fragment
|
||||
* @param url 图片URL
|
||||
* @param imageView 目标ImageView
|
||||
* @param placeholderId 占位图资源ID
|
||||
* @param errorId 错误图资源ID
|
||||
*/
|
||||
public static void loadImageFromFragment(@Nullable Fragment fragment, @Nullable String url,
|
||||
@NonNull ImageView imageView,
|
||||
@DrawableRes int placeholderId,
|
||||
@DrawableRes int errorId) {
|
||||
if (!isFragmentValid(fragment)) {
|
||||
Logger.w(TAG, "Skip loading from invalid fragment");
|
||||
return;
|
||||
}
|
||||
|
||||
GlideApp.with(fragment)
|
||||
.load(url)
|
||||
.placeholder(placeholderId)
|
||||
.error(errorId)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除 ImageView 的图片加载请求
|
||||
* 通常在 RecyclerView 复用时使用
|
||||
*
|
||||
* @param imageView ImageView
|
||||
*/
|
||||
public static void clearImage(@NonNull ImageView imageView) {
|
||||
GlideApp.with(imageView.getContext()).clear(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停所有图片加载请求
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
public static void pauseRequests(@Nullable Context context) {
|
||||
if (context != null) {
|
||||
GlideApp.with(context).pauseRequests();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复所有图片加载请求
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
public static void resumeRequests(@Nullable Context context) {
|
||||
if (context != null) {
|
||||
GlideApp.with(context).resumeRequests();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除内存缓存
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
public static void clearMemoryCache(@Nullable Context context) {
|
||||
if (context != null) {
|
||||
GlideApp.get(context).clearMemory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除磁盘缓存(需在后台线程执行)
|
||||
*
|
||||
* @param context Context
|
||||
*/
|
||||
public static void clearDiskCache(@Nullable Context context) {
|
||||
if (context != null) {
|
||||
GlideApp.get(context).clearDiskCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
app/src/main/java/com/ttstd/dialer/utils/PhoneUtils.java
Normal file
20
app/src/main/java/com/ttstd/dialer/utils/PhoneUtils.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.ttstd.dialer.utils;
|
||||
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber;
|
||||
|
||||
public class PhoneUtils {
|
||||
public static boolean isValidPhone(String phone, String regionCode) {
|
||||
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
|
||||
try {
|
||||
Phonenumber.PhoneNumber number = util.parse(phone, regionCode);
|
||||
return util.isValidNumber(number); // ✅ 座机 & 手机都返回 true
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isValidPhone(String phone) {
|
||||
return isValidPhone(phone, "CN");
|
||||
}
|
||||
}
|
||||
20
app/src/main/java/com/ttstd/dialer/view/BindingAdapters.java
Normal file
20
app/src/main/java/com/ttstd/dialer/view/BindingAdapters.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.ttstd.dialer.view;
|
||||
|
||||
import androidx.databinding.BindingAdapter;
|
||||
|
||||
import com.suke.widget.SwitchButton;
|
||||
|
||||
public class BindingAdapters {
|
||||
|
||||
// @BindingAdapter({"imageUrl", "urlError"})
|
||||
// public static void loadImage(ImageView imageView, String url, @DrawableRes int errorId) {
|
||||
// GlideUtils.loadImageSafe(imageView.getContext(), url, imageView, errorId);
|
||||
// }
|
||||
|
||||
|
||||
@BindingAdapter(value = {"sb_checked"}, requireAll = false)
|
||||
public static void setSwitchButtonChecked(SwitchButton switchButton, boolean checked) {
|
||||
switchButton.setChecked(checked);
|
||||
}
|
||||
}
|
||||
|
||||
98
app/src/main/java/com/ttstd/dialer/view/ClearEditText.java
Normal file
98
app/src/main/java/com/ttstd/dialer/view/ClearEditText.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.ttstd.dialer.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.appcompat.widget.AppCompatEditText;
|
||||
|
||||
import com.ttstd.dialer.R;
|
||||
|
||||
public class ClearEditText extends AppCompatEditText {
|
||||
|
||||
private Drawable clearDrawable;
|
||||
|
||||
public ClearEditText(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ClearEditText(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public ClearEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// 换成你自己的清除图标
|
||||
clearDrawable = AppCompatResources.getDrawable(getContext(), R.drawable.ic_clear);
|
||||
|
||||
if (clearDrawable != null) {
|
||||
clearDrawable.setBounds(0, 0,
|
||||
clearDrawable.getIntrinsicWidth(),
|
||||
clearDrawable.getIntrinsicHeight());
|
||||
}
|
||||
|
||||
updateClearButton();
|
||||
|
||||
addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
updateClearButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateClearButton() {
|
||||
Drawable endDrawable = length() > 0 ? clearDrawable : null;
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, endDrawable, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (clearDrawable != null
|
||||
&& event.getAction() == MotionEvent.ACTION_UP
|
||||
&& getCompoundDrawablesRelative()[2] != null) {
|
||||
|
||||
int touchX = (int) event.getX();
|
||||
int width = getWidth();
|
||||
int paddingEnd = getPaddingEnd();
|
||||
int drawableWidth = clearDrawable.getBounds().width();
|
||||
|
||||
if (touchX >= width - paddingEnd - drawableWidth) {
|
||||
setText("");
|
||||
event.setAction(MotionEvent.ACTION_CANCEL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||
if (focused) {
|
||||
updateClearButton();
|
||||
} else {
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
app/src/main/java/com/ttstd/dialer/view/TransparentCardView.java
Normal file
104
app/src/main/java/com/ttstd/dialer/view/TransparentCardView.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package com.ttstd.dialer.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.cardview.widget.CardView;
|
||||
|
||||
import com.ttstd.dialer.R;
|
||||
|
||||
public class TransparentCardView extends CardView {
|
||||
|
||||
private FrameLayout mContent;
|
||||
private GradientDrawable mBackgroundDrawable;
|
||||
|
||||
private float mCornerRadius = 0f;
|
||||
private float mShadowElevation = 0f;
|
||||
private int mBackgroundColor = Color.WHITE;
|
||||
|
||||
public TransparentCardView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public TransparentCardView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public TransparentCardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
initAttrs(context, attrs);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
private void initAttrs(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TransparentCardView);
|
||||
try {
|
||||
mCornerRadius = a.getDimension(
|
||||
R.styleable.TransparentCardView_tcv_cornerRadius, dpToPx(12));
|
||||
mShadowElevation = a.getDimension(
|
||||
R.styleable.TransparentCardView_tcv_elevation, dpToPx(8));
|
||||
mBackgroundColor = a.getColor(
|
||||
R.styleable.TransparentCardView_tcv_backgroundColor, Color.WHITE);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
// 1️⃣ CardView 本身必须是透明的
|
||||
setCardBackgroundColor(Color.TRANSPARENT);
|
||||
setRadius(mCornerRadius);
|
||||
setCardElevation(mShadowElevation);
|
||||
setMaxCardElevation(mShadowElevation + dpToPx(4));
|
||||
setUseCompatPadding(true);
|
||||
setPreventCornerOverlap(false);
|
||||
|
||||
// 2️⃣ 创建内部容器(真正承载半透明背景)
|
||||
mContent = new FrameLayout(context);
|
||||
LayoutParams params = new LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT
|
||||
);
|
||||
mContent.setLayoutParams(params);
|
||||
|
||||
// 3️⃣ 创建圆角半透明背景
|
||||
mBackgroundDrawable = new GradientDrawable();
|
||||
mBackgroundDrawable.setShape(GradientDrawable.RECTANGLE);
|
||||
mBackgroundDrawable.setCornerRadius(mCornerRadius);
|
||||
mBackgroundDrawable.setColor(mBackgroundColor);
|
||||
|
||||
mContent.setBackground(mBackgroundDrawable);
|
||||
|
||||
// 4️⃣ 添加到 CardView
|
||||
addView(mContent);
|
||||
}
|
||||
|
||||
/* ================== API ================== */
|
||||
|
||||
public void setTransparentBackgroundColor(int color) {
|
||||
mBackgroundColor = color;
|
||||
mBackgroundDrawable.setColor(color);
|
||||
}
|
||||
|
||||
public void setCornerRadiusDp(float dp) {
|
||||
float radius = dpToPx(dp);
|
||||
setRadius(radius);
|
||||
mBackgroundDrawable.setCornerRadius(radius);
|
||||
}
|
||||
|
||||
public FrameLayout getContentContainer() {
|
||||
return mContent;
|
||||
}
|
||||
|
||||
/* ================== Util ================== */
|
||||
|
||||
private float dpToPx(float dp) {
|
||||
return dp * getResources().getDisplayMetrics().density;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class WallpaperScrollHelper {
|
||||
|
||||
public void onResume() {
|
||||
setupWallpaperOffsetSteps();
|
||||
syncWallpaperOffset(0f);
|
||||
// syncWallpaperOffset(0f);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
|
||||
9
app/src/main/res/drawable-anydpi/qweather_100.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_100.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.655,2.357a0.5,0.5 0,0 0,0.854 -0.353v-1.5a0.5,0.5 0,0 0,-1 0v1.5a0.5,0.5 0,0 0,0.146 0.353ZM3.575,4.218c0.06,0.026 0.126,0.039 0.191,0.039l0.001,-0.001a0.5,0.5 0,0 0,0.355 -0.855l-1.064,-1.06a0.5,0.5 0,0 0,-0.707 0.708l1.062,1.06a0.498,0.498 0,0 0,0.162 0.11ZM0.503,8.496h1.5a0.5,0.5 0,1 0,0 -1h-1.5a0.5,0.5 0,0 0,0 1ZM2.417,13.717a0.501,0.501 0,0 0,0.631 -0.063l1.063,-1.06a0.5,0.5 0,0 0,-0.708 -0.707l-1.062,1.06a0.5,0.5 0,0 0,0.076 0.77ZM7.642,15.857a0.5,0.5 0,0 0,0.854 -0.354v-1.5a0.5,0.5 0,0 0,-1 0v1.5a0.5,0.5 0,0 0,0.146 0.354ZM13.109,13.773a0.5,0.5 0,0 0,0.544 -0.816l-1.06,-1.06a0.498,0.498 0,0 0,-0.832 0.152,0.5 0.5,0 0,0 0.126,0.555l1.06,1.06a0.496,0.496 0,0 0,0.162 0.109ZM14.002,8.51h1.5a0.5,0.5 0,1 0,0 -1h-1.5a0.5,0.5 0,0 0,0 1ZM11.971,4.183a0.5,0.5 0,0 0,0.633 -0.063l1.06,-1.06a0.5,0.5 0,1 0,-0.708 -0.708l-1.06,1.06a0.5,0.5 0,0 0,0.075 0.77ZM5.505,4.258a4.5,4.5 0,1 1,5 7.484,4.5 4.5,0 0,1 -5,-7.484ZM9.95,5.09a3.5,3.5 0,1 0,-3.89 5.82,3.5 3.5,0 0,0 3.89,-5.82Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1001.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1001.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M9.21,1.491c-3.757,-0.066 -6.613,2.537 -6.88,5.705 -0.292,3.494 2.107,4.947 2.428,5.232C2.853,12.4 0.585,10.28 0.204,8.296a0.104,0.104 0,0 0,-0.1 -0.085,0.103 0.103,0 0,0 -0.103,0.114c0.403,3.526 3.405,6.2 6.79,6.186 3.604,-0.016 6.518,-2.147 6.89,-5.646 0.35,-3.295 -2.108,-5.008 -2.424,-5.292 2.023,0.02 4.162,2.15 4.54,4.133 0.008,0.048 0.05,0.084 0.098,0.085a0.102,0.102 0,0 0,0.1 -0.071,0.103 0.103,0 0,0 0.004,-0.043c-0.406,-3.521 -3.405,-6.126 -6.788,-6.185ZM8,9.503A1.502,1.502 0,1 1,8 6.5a1.502,1.502 0,0 1,0 3.004Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
15
app/src/main/res/drawable-anydpi/qweather_1002.xml
Normal file
15
app/src/main/res/drawable-anydpi/qweather_1002.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M2.653,4.48c-0.105,-0.315 -0.105,-0.573 0.014,-0.791 0.53,-0.967 2.19,-2.004 4.637,-2.443 2.743,-0.492 4.582,0.057 5.1,0.746a0.71,0.71 0,0 1,0.033 0.837c0.897,-0.528 1.158,-1.081 1.014,-1.58C13.166,0.246 10.41,-0.369 7.09,0.244c-3.417,0.632 -5.456,2.22 -5.362,3.229 0.031,0.337 0.38,0.804 0.925,1.006Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M11.568,3.056c-0.178,-0.621 -1.676,-1.49 -3.99,-1.047 -2.362,0.452 -3.348,1.804 -3.29,2.43 0.02,0.208 0.237,0.498 0.575,0.624 -0.066,-0.196 -0.065,-0.356 0.01,-0.492 0.327,-0.6 1.358,-1.244 2.877,-1.516 1.704,-0.306 2.845,0.035 3.166,0.463a0.44,0.44 0,0 1,0.022 0.52c0.556,-0.329 0.718,-0.672 0.63,-0.982Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M15.583,1.905c0.062,0.674 -0.27,1.59 -1.036,2.482 0.365,0.215 0.778,0.548 0.828,0.978 0.11,0.964 -0.43,2.058 -1.606,2.953 0.008,0.007 0.016,0.012 0.024,0.017a0.15,0.15 0,0 1,0.03 0.023,1.278 1.278,0 0,1 0.34,1.041c-0.058,0.378 -0.301,0.568 -0.598,0.8 -0.3,0.232 -0.654,0.508 -0.926,1.062 -0.097,0.198 -0.38,0.559 -0.564,0.729 -0.378,0.35 -0.722,0.4 -1.007,0.44 -0.18,0.026 -0.336,0.049 -0.462,0.141 -0.294,0.216 -0.43,0.424 -0.553,0.612 -0.101,0.154 -0.193,0.294 -0.356,0.415a0.915,0.915 0,0 1,-0.432 0.167c-0.165,0.03 -0.326,0.06 -0.519,0.252 -0.073,0.073 -0.128,0.19 -0.188,0.317 -0.078,0.167 -0.165,0.351 -0.31,0.476 -0.103,0.089 -0.21,0.146 -0.306,0.197 -0.117,0.062 -0.216,0.115 -0.27,0.207 -0.093,0.16 -0.123,0.34 -0.147,0.487 -0.028,0.167 -0.048,0.292 -0.149,0.299 -0.106,0.007 -0.964,-1.02 -1.167,-1.975 -0.045,-0.21 -0.102,-0.478 -0.018,-0.791 0.022,-0.085 0.049,-0.15 0.085,-0.238 0.031,-0.078 0.07,-0.175 0.12,-0.319l0.016,-0.044a2.85,2.85 0,0 0,0.134 -0.446c0.034,-0.234 -0.267,-0.455 -0.457,-0.595a1.666,1.666 0,0 1,-0.12 -0.092c-0.149,-0.138 -1.019,-0.973 -0.964,-1.71 0,-0.189 0.048,-0.376 0.139,-0.542 -0.958,-0.5 -1.593,-1.174 -1.774,-1.808a1.946,1.946 0,0 1,-0.05 -0.459C1.513,6.41 0.583,5.356 0.424,4.445c-0.073,-0.427 0.173,-0.94 0.554,-1.38 0,0.001 -0.035,0.686 0.285,1.026 0.956,1.018 3.98,1.787 7.223,1.262 3.613,-0.585 5.97,-2.628 5.763,-3.967 -0.06,-0.39 -0.198,-0.651 -0.538,-0.972 0,0 1.784,0.537 1.873,1.491ZM9.633,11.252c1.13,-0.1 2.536,-0.664 3.386,-1.793 0.17,-0.241 0.273,-0.524 0.298,-0.818 -0.83,0.52 -1.902,0.951 -3.247,1.199 -1.852,0.341 -3.422,0.098 -4.581,-0.408 0.03,0.104 0.077,0.201 0.142,0.287 0.54,0.625 1.978,1.714 4.002,1.533ZM4.122,7.37c1.124,0.775 3.08,1.268 5.706,0.85 2.927,-0.463 4.836,-2.11 4.671,-3.22a1.227,1.227 0,0 0,-0.15 -0.395c-1.082,1.143 -2.899,2.206 -5.571,2.61 -2.004,0.302 -3.616,0.223 -4.876,-0.072 0.06,0.088 0.134,0.165 0.22,0.227Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1003.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1003.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0ZM8.943,11.704a0.494,0.494 0,0 0,-0.157 -0.641c-0.205,-0.13 -0.467,-0.053 -0.586,0.172l-2.143,4.061a0.494,0.494 0,0 0,0.157 0.641c0.205,0.13 0.467,0.053 0.586,-0.172l2.143,-4.061ZM2.8,11.556c0.191,0.115 0.257,0.37 0.146,0.57l-1.2,2.165a0.391,0.391 0,0 1,-0.546 0.153,0.427 0.427,0 0,1 -0.146,-0.57l1.2,-2.165a0.39,0.39 0,0 1,0.546 -0.153ZM5.8,11.556c0.191,0.115 0.257,0.37 0.146,0.57l-1.2,2.165a0.391,0.391 0,0 1,-0.546 0.153,0.427 0.427,0 0,1 -0.146,-0.57l1.2,-2.165a0.39,0.39 0,0 1,0.546 -0.153ZM14.8,11.556c0.191,0.115 0.257,0.37 0.146,0.57l-1.2,2.165a0.391,0.391 0,0 1,-0.546 0.153,0.427 0.427,0 0,1 -0.146,-0.57l1.2,-2.165a0.39,0.39 0,0 1,0.546 -0.153ZM11.946,12.125a0.427,0.427 0,0 0,-0.146 -0.57,0.391 0.391,0 0,0 -0.546,0.154l-1.2,2.166a0.428,0.428 0,0 0,0.146 0.57,0.391 0.391,0 0,0 0.546,-0.154l1.2,-2.166Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1004.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1004.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0ZM1.501,10a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,1 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.47,0.272a0.35,0.35 0,1 0,0.35 -0.606l-0.47,-0.272 0.47,-0.272a0.35,0.35 0,1 0,-0.35 -0.606l-0.47,0.272v-0.544a0.35,0.35 0,0 0,-0.35 -0.35ZM14.151,10.35a0.35,0.35 0,1 1,0.7 0v0.544l0.47,-0.272a0.35,0.35 0,1 1,0.35 0.606l-0.47,0.272 0.47,0.272a0.35,0.35 0,1 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,1 1,-0.35 -0.606l0.47,-0.272 -0.47,-0.272a0.35,0.35 0,1 1,0.35 -0.606l0.47,0.272v-0.544ZM7.651,13.35a0.35,0.35 0,1 1,0.7 0v0.544l0.47,-0.272a0.35,0.35 0,1 1,0.35 0.606l-0.47,0.272 0.47,0.272a0.35,0.35 0,1 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,1 1,-0.35 -0.606l0.47,-0.272 -0.47,-0.272a0.35,0.35 0,1 1,0.35 -0.606l0.47,0.272v-0.544ZM4.151,12.35a0.35,0.35 0,1 1,0.7 0v0.544l0.47,-0.272a0.35,0.35 0,1 1,0.35 0.606l-0.47,0.272 0.47,0.272a0.35,0.35 0,1 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,1 1,-0.35 -0.606l0.47,-0.272 -0.47,-0.272a0.35,0.35 0,1 1,0.35 -0.606l0.47,0.272v-0.544ZM11.501,12a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,1 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.47,0.272a0.35,0.35 0,1 0,0.35 -0.606l-0.47,-0.272 0.47,-0.272a0.35,0.35 0,1 0,-0.35 -0.606l-0.47,0.272v-0.544a0.35,0.35 0,0 0,-0.35 -0.35Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1005.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1005.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M8.5,0.5a0.5,0.5 0,1 0,-1 0v1.293l-0.646,-0.647a0.5,0.5 0,1 0,-0.708 0.708L7.5,3.207V5c0,0.014 0,0.028 0.002,0.041A2.997,2.997 0,0 0,5.687 6.09a0.512,0.512 0,0 0,-0.035 -0.022l-1.553,-0.896 -0.495,-1.85a0.5,0.5 0,1 0,-0.966 0.26l0.237,0.882 -1.12,-0.646a0.5,0.5 0,0 0,-0.5 0.866l1.12,0.646 -0.884,0.237a0.5,0.5 0,0 0,0.26 0.966l1.848,-0.495 1.553,0.896a0.503,0.503 0,0 0,0.036 0.019,2.994 2.994,0 0,0 0,2.096 0.508,0.508 0,0 0,-0.036 0.019l-1.553,0.896 -1.849,-0.495a0.5,0.5 0,0 0,-0.259 0.966l0.884,0.237 -1.12,0.646a0.5,0.5 0,1 0,0.5 0.866l1.12,-0.646 -0.237,0.883a0.5,0.5 0,1 0,0.966 0.258l0.495,-1.849 1.553,-0.896a0.507,0.507 0,0 0,0.035 -0.022,3 3,0 0,0 1.815,1.048 0.51,0.51 0,0 0,-0.002 0.04v1.793l-1.354,1.353a0.5,0.5 0,0 0,0.708 0.708l0.646,-0.647V15.5a0.5,0.5 0,0 0,1 0v-1.293l0.646,0.647a0.5,0.5 0,0 0,0.708 -0.708L8.5,12.793V10.99c0,-0.01 0,-0.02 -0.002,-0.031H8.5V5.04h-0.002l0.002,-0.03V3.207l1.354,-1.353a0.5,0.5 0,1 0,-0.707 -0.708l-0.647,0.647V0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M16,5.064 L13.897,4l-1.946,0.985 -1.722,-0.435 -0.229,0.928L12.061,6l1.836,-0.93 1.68,0.85 0.423,-0.856ZM16,8.064L13.897,7l-1.946,0.985 -1.722,-0.435 -0.229,0.928L12.061,9l1.836,-0.93 1.68,0.85 0.423,-0.856ZM13.897,10 L16,11.065l-0.423,0.856 -1.68,-0.85 -1.836,0.929L10,11.478l0.23,-0.928 1.721,0.435L13.897,10Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1006.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1006.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M15.497,3.077S7.525,0.722 4.845,0.023a0.794,0.794 0,0 0,-0.956 0.568L0.024,15a0.81,0.81 0,0 0,0.544 0.968,0.811 0.811,0 0,0 1,-0.554l1.671,-6.23 12.373,-4.817a0.696,0.696 0,0 0,-0.115 -1.291Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M11.756,7.71a0.296,0.296 0,0 0,-0.512 0L7.04,15a0.292,0.292 0,0 0,0.256 0.438h8.41a0.292,0.292 0,0 0,0.256 -0.437L11.756,7.71ZM10.8,10.12c-0.036,-0.317 0.287,-0.59 0.7,-0.59 0.412,0 0.736,0.273 0.7,0.59l-0.316,2.785h-0.768L10.8,10.12ZM12.067,14.03a0.563,0.563 0,1 1,-1.125 0,0.563 0.563,0 0,1 1.125,0Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1007.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1007.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M15.859,8.141 L14.34,9.66a0.2,0.2 0,0 1,-0.34 -0.143V9H1a1,1 0,1 1,0 -2h13v-0.517a0.2,0.2 0,0 1,0.341 -0.142L15.86,7.86a0.2,0.2 0,0 1,0 0.282Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M10.462,2.99c0.388,0.39 1.052,0.476 1.516,0.156 0.44,-0.303 0.536,-0.862 0.177,-1.238a7.232,7.232 0,0 0,-1.52 -1.241C9.91,0.222 9.06,0 8.082,0 6.82,0 5.788,0.354 4.984,1.063c-0.788,0.694 -1.182,1.548 -1.182,2.562 0,0.472 0.102,0.944 0.307,1.417 0.205,0.472 0.528,0.916 0.97,1.333 0.191,0.174 0.447,0.383 0.768,0.625h3.366a24.36,24.36 0,0 0,-0.162 -0.104c-1.356,-0.89 -2.223,-1.528 -2.6,-1.917 -0.38,-0.389 -0.568,-0.84 -0.568,-1.354 0,-0.528 0.197,-0.958 0.59,-1.292 0.41,-0.333 0.907,-0.5 1.49,-0.5 0.6,0 1.12,0.132 1.561,0.396 0.276,0.156 0.588,0.41 0.938,0.761ZM11.725,9c0.12,0.126 0.229,0.251 0.33,0.375 0.63,0.778 0.945,1.597 0.945,2.458 0,1.125 -0.497,2.104 -1.49,2.938C10.533,15.59 9.39,16 8.082,16c-2.038,0 -3.686,-0.887 -4.946,-2.662 -0.284,-0.4 -0.105,-0.918 0.36,-1.154a1.175,1.175 0,0 1,1.43 0.328c0.886,1.159 1.859,1.738 2.92,1.738 0.819,0 1.52,-0.23 2.104,-0.688 0.583,-0.458 0.875,-0.993 0.875,-1.604 0,-0.61 -0.245,-1.187 -0.733,-1.729 -0.317,-0.36 -0.783,-0.77 -1.398,-1.229h3.031Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
15
app/src/main/res/drawable-anydpi/qweather_1008.xml
Normal file
15
app/src/main/res/drawable-anydpi/qweather_1008.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M11.5,7a0.5,0.5 0,0 0,-0.5 0.5v2.063a2,2 0,1 0,1 0V7.5a0.5,0.5 0,0 0,-0.5 -0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="m10.2,8.399 l-0.532,0.356a3.3,3.3 0,1 0,3.665 0l-0.533,-0.356L12.8,2.5a1.3,1.3 0,1 0,-2.6 0v5.899ZM9,2.5a2.5,2.5 0,0 1,5 0v5.258a4.5,4.5 0,1 1,-5 0L9,2.5ZM3.535,2.467a0.467,0.467 0,0 1,0.933 0v0.725l0.628,-0.363a0.467,0.467 0,1 1,0.467 0.808L4.935,4l0.628,0.363a0.467,0.467 0,0 1,-0.467 0.808l-0.628,-0.363v0.725a0.467,0.467 0,1 1,-0.933 0v-0.725l-0.628,0.363a0.467,0.467 0,0 1,-0.467 -0.808L3.068,4l-0.628,-0.363a0.467,0.467 0,1 1,0.467 -0.808l0.628,0.363v-0.725Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M7.324,1.872 L4.175,0.048a0.347,0.347 0,0 0,-0.35 0L0.675,1.872a0.352,0.352 0,0 0,-0.175 0.304v3.648c0,0.126 0.067,0.242 0.175,0.305l3.15,1.824a0.344,0.344 0,0 0,0.35 0l3.149,-1.824a0.351,0.351 0,0 0,0.176 -0.305L7.5,2.176a0.353,0.353 0,0 0,-0.176 -0.304ZM6.798,5.622L4,7.241l-2.798,-1.62L1.202,2.38L4,0.758 6.798,2.38v3.242Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1009.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1009.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M3,2a0.6,0.6 0,0 0,-0.6 0.6v1.8L0.6,4.4a0.6,0.6 0,1 0,0 1.2h1.8v1.8a0.6,0.6 0,0 0,1.2 0L3.6,5.6h1.8a0.6,0.6 0,1 0,0 -1.2L3.6,4.4L3.6,2.6A0.6,0.6 0,0 0,3 2ZM11.5,3a0.5,0.5 0,0 0,-0.5 0.5v6.063a2,2 0,1 0,1 0L12,3.5a0.5,0.5 0,0 0,-0.5 -0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="m10.2,8.399 l-0.532,0.356a3.3,3.3 0,1 0,3.665 0l-0.533,-0.356V2.5a1.3,1.3 0,1 0,-2.6 0v5.899ZM9,2.5a2.5,2.5 0,0 1,5 0v5.258a4.5,4.5 0,1 1,-5 0V2.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_100_fill.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_100_fill.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M8.005,3.5a4.5,4.5 0,1 0,0 9,4.5 4.5,0 0,0 0,-9ZM8.009,2.503a0.5,0.5 0,0 1,-0.5 -0.5v-1.5a0.5,0.5 0,0 1,1 0v1.5a0.5,0.5 0,0 1,-0.5 0.5ZM3.766,4.255a0.498,0.498 0,0 1,-0.353 -0.147l-1.062,-1.06a0.5,0.5 0,0 1,0.707 -0.707L4.122,3.4a0.5,0.5 0,0 1,-0.355 0.854v0.001ZM2.004,8.493h-1.5a0.5,0.5 0,1 1,0 -1h1.5a0.5,0.5 0,1 1,0 1ZM2.695,13.796a0.5,0.5 0,0 1,-0.354 -0.854l1.062,-1.06a0.5,0.5 0,0 1,0.708 0.707l-1.063,1.06a0.497,0.497 0,0 1,-0.353 0.147ZM7.996,15.997a0.5,0.5 0,0 1,-0.5 -0.5v-1.5a0.5,0.5 0,0 1,1 0v1.5a0.5,0.5 0,0 1,-0.5 0.5ZM13.3,13.806a0.496,0.496 0,0 1,-0.353 -0.147l-1.06,-1.06a0.5,0.5 0,1 1,0.706 -0.707l1.06,1.06a0.5,0.5 0,0 1,-0.353 0.854ZM15.503,8.507h-1.5a0.5,0.5 0,0 1,0 -1h1.5a0.5,0.5 0,1 1,0 1ZM12.25,4.265a0.5,0.5 0,0 1,-0.354 -0.854l1.06,-1.06a0.5,0.5 0,1 1,0.708 0.707l-1.06,1.06a0.498,0.498 0,0 1,-0.354 0.147Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_101.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_101.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M8.406,15.985a4.766,4.766 0,0 0,3.446 -1.449,0.323 0.323,0 0,1 0.341,-0.074c0.31,0.112 0.645,0.173 0.995,0.173 1.553,0 2.812,-1.209 2.812,-2.7s-1.26,-2.7 -2.813,-2.7c-0.157,0 -0.312,0.013 -0.463,0.037a0.32,0.32 0,0 1,-0.32 -0.137c-0.824,-1.29 -2.306,-2.15 -3.998,-2.15 -1.682,0 -3.157,0.85 -3.984,2.128a0.318,0.318 0,0 1,-0.3 0.138,2.962 2.962,0 0,0 -0.31,-0.016C2.26,9.235 1,10.444 1,11.935s1.26,2.7 2.813,2.7c0.302,0 0.594,-0.046 0.867,-0.13a0.322,0.322 0,0 1,0.324 0.076,4.768 4.768,0 0,0 3.402,1.404ZM12.067,13.379c-0.161,-0.116 -0.41,-0.088 -0.52,0.074a3.788,3.788 0,0 1,-3.14 1.632,3.792 3.792,0 0,1 -3.091,-1.56c-0.106,-0.147 -0.326,-0.178 -0.482,-0.08 -0.294,0.183 -0.645,0.29 -1.021,0.29 -1.036,0 -1.876,-0.806 -1.876,-1.8s0.84,-1.8 1.875,-1.8c0.241,0 0.471,0.044 0.683,0.123 0.173,0.065 0.383,-0.008 0.455,-0.172 0.569,-1.293 1.902,-2.2 3.456,-2.2 1.575,0 2.924,0.931 3.48,2.253 0.075,0.18 0.314,0.254 0.496,0.17 0.244,-0.111 0.517,-0.174 0.806,-0.174 1.035,0 1.874,0.806 1.874,1.8s-0.839,1.8 -1.874,1.8c-0.42,0 -0.808,-0.132 -1.12,-0.356ZM4.995,1.762a0.516,0.516 0,1 0,1.007 -0.224L5.746,0.388A0.516,0.516 0,0 0,4.74 0.612l0.255,1.15ZM1.273,3.52l0.994,0.633a0.516,0.516 0,0 0,0.555 -0.87l-0.995,-0.633a0.516,0.516 0,0 0,-0.554 0.87ZM0.878,8.028l1.15,-0.256a0.516,0.516 0,0 0,-0.223 -1.008l-1.15,0.256a0.516,0.516 0,1 0,0.223 1.008ZM11.116,5.748a0.535,0.535 0,0 0,0.112 -0.012l1.15,-0.256a0.516,0.516 0,1 0,-0.224 -1.008l-1.15,0.256a0.516,0.516 0,0 0,0.112 1.02ZM8.772,2.713a0.516,0.516 0,0 0,0.712 -0.158l0.633,-0.994a0.516,0.516 0,0 0,-0.87 -0.554l-0.633,0.994a0.516,0.516 0,0 0,0.158 0.712ZM3.07,7.017c0.07,0.303 0.182,0.596 0.33,0.87a3.13,3.13 0,0 0,0.909 -0.486,2.453 2.453,0 0,1 -0.233,-0.608 2.504,2.504 0,0 1,4.888 -1.088c0.003,0.013 0.002,0.026 0.005,0.038a5.42,5.42 0,0 1,1.063 0.25,3.497 3.497,0 0,0 -0.061,-0.512A3.535,3.535 0,1 0,3.07 7.017Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1010.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1010.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M8.01,2.503a0.5,0.5 0,0 1,-0.501 -0.5v-1.5a0.5,0.5 0,0 1,1 0v1.5a0.5,0.5 0,0 1,-0.5 0.5ZM3.766,4.255a0.498,0.498 0,0 1,-0.353 -0.147l-1.062,-1.06a0.5,0.5 0,0 1,0.707 -0.707L4.122,3.4a0.5,0.5 0,0 1,-0.355 0.854v0.001ZM2.004,8.493h-1.5a0.5,0.5 0,1 1,0 -1h1.5a0.5,0.5 0,1 1,0 1ZM2.695,13.796a0.5,0.5 0,0 1,-0.354 -0.854l1.062,-1.06a0.5,0.5 0,0 1,0.708 0.707l-1.063,1.06a0.498,0.498 0,0 1,-0.353 0.147ZM7.996,15.997a0.5,0.5 0,0 1,-0.5 -0.5v-1.5a0.5,0.5 0,0 1,1 0v1.5a0.5,0.5 0,0 1,-0.5 0.5ZM7.127,12.414a4.5,4.5 0,0 0,1.373 0.059L8.5,3.527a4.503,4.503 0,0 0,-4.652 2.75,4.5 4.5,0 0,0 3.28,6.137ZM16.003,8.007A0.506,0.506 0,0 0,16 7.952v0.04a0.5,0.5 0,0 0,-0.2 -0.392,2.952 2.952,0 0,0 -0.846,-0.463A2.96,2.96 0,0 0,14 7c-0.629,0 -1.037,0.364 -1.304,0.601l-0.028,0.025C12.37,7.891 12.222,8 12,8c-0.273,0 -0.468,-0.029 -0.638,-0.085A1.967,1.967 0,0 1,10.8 7.6a0.5,0.5 0,0 0,-0.6 0.8c0.276,0.207 0.544,0.363 0.846,0.463 0.301,0.1 0.61,0.137 0.954,0.137 0.629,0 1.038,-0.364 1.304,-0.601l0.028,-0.025C13.63,8.109 13.778,8 14,8c0.273,0 0.468,0.029 0.638,0.085 0.17,0.057 0.344,0.151 0.562,0.315a0.5,0.5 0,0 0,0.8 -0.392v0.054a0.506,0.506 0,0 0,0.003 -0.055ZM12,6c0.629,0 1.038,-0.364 1.304,-0.601l0.028,-0.025C13.63,5.109 13.778,5 14,5c0.273,0 0.468,0.029 0.638,0.085 0.17,0.057 0.344,0.151 0.562,0.315a0.5,0.5 0,0 0,0.6 -0.8,2.952 2.952,0 0,0 -0.846,-0.463A2.96,2.96 0,0 0,14 4c-0.629,0 -1.037,0.364 -1.304,0.601l-0.028,0.025C12.37,4.891 12.222,5 12,5c-0.273,0 -0.468,-0.029 -0.638,-0.085A1.967,1.967 0,0 1,10.8 4.6a0.5,0.5 0,0 0,-0.6 0.8c0.276,0.207 0.544,0.363 0.846,0.463 0.301,0.1 0.61,0.137 0.954,0.137ZM12,12c0.629,0 1.038,-0.364 1.304,-0.601l0.028,-0.025c0.298,-0.264 0.446,-0.374 0.668,-0.374 0.273,0 0.468,0.029 0.638,0.085 0.17,0.057 0.344,0.151 0.562,0.315a0.5,0.5 0,0 0,0.6 -0.8,2.951 2.951,0 0,0 -0.846,-0.463c-0.301,-0.1 -0.61,-0.137 -0.954,-0.137 -0.629,0 -1.037,0.364 -1.304,0.601l-0.028,0.025c-0.298,0.264 -0.446,0.374 -0.668,0.374 -0.273,0 -0.468,-0.029 -0.638,-0.085a1.968,1.968 0,0 1,-0.562 -0.315,0.5 0.5,0 0,0 -0.6,0.8c0.276,0.207 0.544,0.363 0.846,0.463 0.301,0.1 0.61,0.137 0.954,0.137Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1011.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1011.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M4.9,1.5c-0.9,0.3 -1.2,1.1 -1.1,1.6 -0.7,-0.8 -0.7,-1.7 -0.6,-3.1 -2.1,0.8 -1.6,3.2 -1.7,4C1,3.5 0.9,2.5 0.9,2.5 0.3,2.8 0,3.6 0,4.3 0,5.9 1.3,7 2.8,7c1.5,0 2.7,-1.2 2.7,-2.7 0,-1.1 -0.6,-1.4 -0.6,-2.8ZM2,9h6a1,1 0,1 0,-0.943 -1.333,0.5 0.5,0 1,1 -0.943,-0.334A2,2 0,1 1,8 10H2a0.5,0.5 0,0 1,0 -1Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M11.079,8.375A2.5,2.5 0,0 1,16 9c0,1.397 -1.24,2.5 -2.5,2.5H0.5a0.5,0.5 0,0 1,0 -1h13c0.74,0 1.5,-0.688 1.5,-1.5a1.5,1.5 0,0 0,-2.953 -0.375,0.5 0.5,0 1,1 -0.968,-0.25ZM2.5,12.5A0.5,0.5 0,0 1,3 12h8a2,2 0,1 1,-1.886 2.667,0.5 0.5,0 1,1 0.943,-0.334A1,1 0,1 0,11 13H3a0.5,0.5 0,0 1,-0.5 -0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1012.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1012.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M5,10a0.5,0.5 0,0 1,0.5 0.5L5.5,14a2,2 0,1 1,-2.665 -1.887,0.5 0.5,0 0,1 0.332,0.944A1,1 0,1 0,4.5 14v-3.5A0.5,0.5 0,0 1,5 10ZM8,11c0.276,0 0.5,0.18 0.5,0.4v3.2c0,0.22 -0.224,0.4 -0.5,0.4s-0.5,-0.18 -0.5,-0.4v-3.2c0,-0.22 0.224,-0.4 0.5,-0.4ZM10.5,10.5a0.5,0.5 0,0 1,1 0L11.5,14a1,1 0,1 0,1.332 -0.944,0.5 0.5,0 1,1 0.332,-0.943A2,2 0,1 1,10.5 14v-3.5ZM7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1013.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1013.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="m14.589,4 l-1.472,0.835 -1.235,2.139 -2.44,1.017L8.336,9.77l-3.588,0.905L1,15.998h15L14.589,4ZM10.501,0a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,0 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,0 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.47,0.272a0.35,0.35 0,0 0,0.35 -0.606l-0.47,-0.272 0.47,-0.272a0.35,0.35 0,1 0,-0.35 -0.606l-0.47,0.272L10.851,0.35a0.35,0.35 0,0 0,-0.35 -0.35ZM6.151,3.35a0.35,0.35 0,1 1,0.7 0v0.544l0.471,-0.272a0.35,0.35 0,0 1,0.35 0.606L7.2,4.5l0.471,0.272a0.35,0.35 0,0 1,-0.35 0.606l-0.471,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,0 1,-0.35 -0.606L5.8,4.5l-0.47,-0.272a0.35,0.35 0,1 1,0.35 -0.606l0.47,0.272L6.15,3.35Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M10.151,4.35a0.35,0.35 0,1 1,0.7 0v0.544l0.47,-0.272a0.35,0.35 0,0 1,0.35 0.606l-0.47,0.272 0.47,0.272a0.35,0.35 0,1 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,0 1,-0.35 -0.606L9.8,5.5l-0.47,-0.272a0.35,0.35 0,0 1,0.35 -0.606l0.47,0.272L10.15,4.35ZM5.151,7.35a0.35,0.35 0,1 1,0.7 0v0.544l0.471,-0.272a0.35,0.35 0,0 1,0.35 0.606L6.2,8.5l0.471,0.272a0.35,0.35 0,0 1,-0.35 0.606l-0.471,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,0 1,-0.35 -0.606L4.8,8.5l-0.47,-0.272a0.35,0.35 0,0 1,0.35 -0.606l0.47,0.272L5.15,7.35ZM2.501,9a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,0 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.471,0.272a0.35,0.35 0,1 0,0.35 -0.606L3.2,10.5l0.47,-0.272a0.35,0.35 0,1 0,-0.349 -0.606l-0.471,0.272L2.85,9.35A0.35,0.35 0,0 0,2.5 9Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1014.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1014.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.058,0h5.403c0.264,0 0.422,0.311 0.279,0.548l-2.975,3.85a0.173,0.173 0,0 0,0.05 0.232,0.147 0.147,0 0,0 0.08,0.024h3.13c0.416,0 0.63,0.53 0.345,0.855L4.12,16l2.203,-8.082a0.177,0.177 0,0 0,-0.025 -0.146,0.159 0.159,0 0,0 -0.055,-0.048 0.148,0.148 0,0 0,-0.07 -0.018H2.976a0.451,0.451 0,0 1,-0.236 -0.067,0.49 0.49,0 0,1 -0.173,-0.183 0.532,0.532 0,0 1,-0.006 -0.503L6.56,0.311C6.66,0.119 6.85,0 7.057,0Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1015.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1015.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="m1,9 l1,1.5L1,13l-1,-2.5L1,9ZM16,10.5L15,9l-1,1.5 1,2.5 1,-2.5ZM4.5,11l1,1.5 -1,2.5 -1,-2.5 1,-1.5ZM12.5,12.5 L11.5,11 10.5,12.5 11.5,15 12.5,12.5ZM9,13.5L8,12l-1,1.5L8,16l1,-2.5ZM7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1016.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1016.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M0,10.75a0.75,0.75 0,0 1,1.5 0v3.75h13v-3.75a0.75,0.75 0,0 1,1.5 0v4.5a0.75,0.75 0,0 1,-0.75 0.75H0.75a0.75,0.75 0,0 1,-0.75 -0.75v-4.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M8.406,0.406a0.406,0.406 0,1 0,-0.812 0v1.05L7.069,0.932a0.406,0.406 0,1 0,-0.575 0.575l1.1,1.1v1.457l0.001,0.033a2.44,2.44 0,0 0,-1.474 0.851,0.415 0.415,0 0,0 -0.029,-0.018l-1.261,-0.728L4.428,2.7a0.406,0.406 0,1 0,-0.785 0.21l0.193,0.718 -0.91,-0.526a0.406,0.406 0,0 0,-0.406 0.704l0.91,0.525 -0.718,0.192a0.406,0.406 0,0 0,0.21 0.785l1.502,-0.402 1.262,0.728 0.03,0.015a2.432,2.432 0,0 0,0 1.704,0.415 0.415,0 0,0 -0.03,0.015l-1.262,0.728 -1.502,-0.402a0.406,0.406 0,1 0,-0.21 0.785l0.717,0.192 -0.91,0.525a0.406,0.406 0,0 0,0.407 0.704l0.91,-0.526 -0.193,0.718a0.406,0.406 0,1 0,0.785 0.21L4.831,8.8l1.261,-0.728a0.416,0.416 0,0 0,0.029 -0.018,2.44 2.44,0 0,0 1.474,0.851 0.411,0.411 0,0 0,-0.001 0.034v1.456l-1.1,1.1a0.406,0.406 0,1 0,0.575 0.575l0.525,-0.526v1.05a0.406,0.406 0,0 0,0.812 0v-1.05l0.526,0.526a0.406,0.406 0,1 0,0.574 -0.575l-1.1,-1.1V8.937l-0.001,-0.033a2.435,2.435 0,0 0,1.474 -0.852l0.029,0.019 1.261,0.728 0.403,1.502a0.406,0.406 0,1 0,0.785 -0.21l-0.192,-0.718 0.91,0.526a0.406,0.406 0,1 0,0.405 -0.704l-0.91,-0.525 0.718,-0.192a0.406,0.406 0,0 0,-0.21 -0.785l-1.502,0.402 -1.262,-0.728a0.422,0.422 0,0 0,-0.03 -0.016,2.433 2.433,0 0,0 0,-1.702l0.03,-0.016 1.262,-0.728 1.502,0.402a0.406,0.406 0,0 0,0.21 -0.785l-0.717,-0.192 0.91,-0.525a0.406,0.406 0,0 0,-0.407 -0.704l-0.91,0.526 0.193,-0.718a0.406,0.406 0,1 0,-0.785 -0.21L11.17,4.2l-1.262,0.728a0.414,0.414 0,0 0,-0.029 0.019,2.435 2.435,0 0,0 -1.474,-0.852l0.001,-0.034V2.607l1.1,-1.1a0.406,0.406 0,0 0,-0.574 -0.575l-0.526,0.526V0.407Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1017.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1017.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M12.227,8.13a0.263,0.263 0,0 0,-0.454 0l-3.738,6.482a0.26,0.26 0,0 0,0.227 0.388h7.476a0.26,0.26 0,0 0,0.227 -0.388L12.227,8.13ZM11.377,10.274c-0.032,-0.282 0.256,-0.524 0.623,-0.524s0.655,0.242 0.623,0.524l-0.282,2.476h-0.682l-0.282,-2.476ZM12.504,13.75a0.5,0.5 0,1 1,-1 0,0.5 0.5,0 0,1 1,0ZM0.75,2a0.75,0.75 0,0 0,0 1.5h14.5a0.75,0.75 0,0 0,0 -1.5L0.75,2ZM7.75,5.5a0.75,0.75 0,0 0,0 1.5h7.5a0.75,0.75 0,0 0,0 -1.5h-7.5ZM0,9.75A0.75,0.75 0,0 1,0.75 9h7.5a0.75,0.75 0,0 1,0 1.5L0.75,10.5A0.75,0.75 0,0 1,0 9.75ZM0.75,5.5a0.75,0.75 0,0 0,0 1.5h4.5a0.75,0.75 0,1 0,0 -1.5L0.75,5.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1018.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1018.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.86,12.447a2.807,2.807 0,1 0,0 -5.614,2.807 2.807,0 0,0 0,5.614ZM7.86,5.676c0.973,0 1.636,0.475 1.833,0.628 0.013,-0.169 0.026,-0.382 0.027,-0.628 0.015,-2.353 -0.956,-5.15 -1.856,-5.15 -0.678,0 -1.849,2.306 -1.849,5.15 0,0.211 0.016,0.412 0.027,0.617a3.018,3.018 0,0 1,1.818 -0.617ZM4.528,11.776a3.022,3.022 0,0 1,-0.372 -1.901,8.77 8.77,0 0,0 -0.558,0.29C1.553,11.328 -0.384,13.567 0.066,14.347c0.339,0.587 2.921,0.449 5.384,-0.973 0.183,-0.106 0.349,-0.22 0.52,-0.332a3.016,3.016 0,0 1,-1.442 -1.266ZM12.399,10.014a9.015,9.015 0,0 0,-0.547 -0.285,3.021 3.021,0 0,1 -0.375,1.883 3.013,3.013 0,0 1,-1.46 1.273c0.175,0.114 0.344,0.23 0.53,0.338 2.463,1.422 5.046,1.559 5.388,0.967 0.45,-0.779 -1.492,-3.015 -3.536,-4.176Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1019.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1019.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M12.543,4.487c-1.581,0 -3.876,1.712 -4.57,2.888C7.282,6.2 4.987,4.487 3.406,4.487a3.486,3.486 0,0 0,0 6.97c1.58,0 3.876,-1.75 4.569,-2.906 0.693,1.156 2.988,2.906 4.569,2.906a3.486,3.486 0,0 0,0 -6.97h-0.001Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_101_fill.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_101_fill.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M4.745,1.777a0.516,0.516 0,1 0,1.007 -0.224L5.496,0.403A0.516,0.516 0,0 0,4.49 0.627l0.255,1.15ZM1.023,3.535l0.994,0.633a0.516,0.516 0,0 0,0.554 -0.87l-0.994,-0.633a0.516,0.516 0,0 0,-0.554 0.87ZM0.628,8.043l1.15,-0.256a0.516,0.516 0,0 0,-0.223 -1.008l-1.15,0.256a0.516,0.516 0,1 0,0.223 1.008ZM10.866,5.763a0.535,0.535 0,0 0,0.112 -0.012l1.15,-0.256a0.516,0.516 0,1 0,-0.224 -1.008l-1.15,0.256a0.516,0.516 0,0 0,0.112 1.02ZM8.522,2.728a0.516,0.516 0,0 0,0.712 -0.158l0.633,-0.994a0.516,0.516 0,0 0,-0.87 -0.554l-0.633,0.994a0.516,0.516 0,0 0,0.158 0.712ZM2.819,7.032c0.071,0.303 0.182,0.596 0.331,0.87a3.13,3.13 0,0 0,0.908 -0.486,2.453 2.453,0 0,1 -0.232,-0.608A2.504,2.504 0,0 1,8.714 5.72l0.004,0.038a5.42,5.42 0,0 1,1.064 0.25,3.51 3.51,0 0,0 -0.061,-0.512 3.535,3.535 0,0 0,-6.902 1.536ZM11.994,14.396A4.758,4.758 0,0 1,8.406 16a4.76,4.76 0,0 1,-3.537 -1.547,2.908 2.908,0 0,1 -1.056,0.197C2.258,14.65 1,13.441 1,11.95s1.26,-2.7 2.813,-2.7c0.173,0 0.342,0.015 0.507,0.044C5.124,7.924 6.652,7 8.406,7c1.769,0 3.308,0.94 4.107,2.328a2.93,2.93 0,0 1,0.675 -0.078c1.553,0 2.812,1.209 2.812,2.7s-1.26,2.7 -2.813,2.7a2.9,2.9 0,0 1,-1.193 -0.254Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_102.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_102.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M13.268,15.162a0.224,0.224 0,0 0,-0.233 0.042A2.99,2.99 0,0 1,11 16a2.99,2.99 0,0 1,-2.035 -0.796,0.224 0.224,0 0,0 -0.233,-0.042 2,2 0,1 1,-0.383 -3.832,0.224 0.224,0 0,0 0.22,-0.087A2.996,2.996 0,0 1,11 10c1,0 1.887,0.49 2.432,1.243 0.05,0.069 0.136,0.102 0.22,0.087a2,2 0,1 1,-0.383 3.832ZM11,15.25c0.752,0 1.418,-0.37 1.827,-0.936 0.086,-0.12 0.273,-0.134 0.388,-0.041a1.25,1.25 0,1 0,0.209 -2.082c-0.132,0.068 -0.312,0.017 -0.373,-0.118a2.25,2.25 0,0 0,-4.102 0c-0.06,0.135 -0.241,0.186 -0.372,0.118a1.25,1.25 0,1 0,0.209 2.082c0.114,-0.093 0.301,-0.079 0.387,0.04A2.247,2.247 0,0 0,11 15.25ZM7.655,2.357a0.5,0.5 0,0 0,0.854 -0.353v-1.5a0.5,0.5 0,1 0,-1 0v1.5a0.5,0.5 0,0 0,0.146 0.353ZM3.575,4.218c0.06,0.026 0.126,0.039 0.191,0.039l0.001,-0.001a0.5,0.5 0,0 0,0.355 -0.855l-1.064,-1.06a0.5,0.5 0,0 0,-0.707 0.708l1.062,1.06a0.498,0.498 0,0 0,0.162 0.11ZM0.503,8.496h1.5a0.5,0.5 0,1 0,0 -1h-1.5a0.5,0.5 0,0 0,0 1ZM2.417,13.717a0.501,0.501 0,0 0,0.631 -0.063l1.063,-1.06a0.5,0.5 0,0 0,-0.708 -0.707l-1.062,1.06a0.5,0.5 0,0 0,0.076 0.77ZM12.393,9a4.5,4.5 0,1 0,-7.033 2.64l0.718,-0.718A3.501,3.501 0,0 1,4.505 8a3.504,3.504 0,0 1,3.5 -3.5A3.5,3.5 0,0 1,11.359 9h1.034ZM14.002,8.51h1.5a0.5,0.5 0,1 0,0 -1h-1.5a0.5,0.5 0,1 0,0 1ZM11.971,4.183a0.5,0.5 0,0 0,0.633 -0.063l1.06,-1.06a0.5,0.5 0,1 0,-0.708 -0.708l-1.06,1.06a0.5,0.5 0,0 0,0.075 0.77Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1020.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1020.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M2,3h6a1,1 0,1 0,-0.943 -1.333,0.5 0.5,0 1,1 -0.943,-0.334A2,2 0,1 1,8 4H2a0.5,0.5 0,0 1,0 -1Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M11.079,2.375A2.5,2.5 0,0 1,16 3c0,1.397 -1.24,2.5 -2.5,2.5L0.5,5.5a0.5,0.5 0,0 1,0 -1h13c0.74,0 1.5,-0.688 1.5,-1.5a1.5,1.5 0,0 0,-2.953 -0.375,0.5 0.5,0 1,1 -0.968,-0.25ZM2.5,6.5A0.5,0.5 0,0 1,3 6h8a2,2 0,1 1,-1.886 2.667,0.5 0.5,0 1,1 0.943,-0.334A1,1 0,1 0,11 7L3,7a0.5,0.5 0,0 1,-0.5 -0.5ZM5.46,12.626c-0.054,0 -0.089,-0.05 -0.065,-0.093l0.792,-1.438C6.21,11.05 6.176,11 6.122,11L4.544,11a0.147,0.147 0,0 0,-0.076 0.02,0.158 0.158,0 0,0 -0.058,0.057l-1.397,2.637c-0.042,0.079 0.022,0.17 0.118,0.17h1.42c0.05,0 0.084,0.043 0.069,0.086l-0.739,1.943c-0.027,0.07 0.072,0.118 0.124,0.063l2.978,-3.243c0.04,-0.042 0.006,-0.107 -0.055,-0.107L5.46,12.626ZM10.158,15.512a1.666,1.666 0,0 1,-0.488 -1.179c0,-0.833 0.926,-2.325 1.667,-3.333 0.74,1.008 1.666,2.5 1.666,3.333a1.666,1.666 0,0 1,-2.845 1.179Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1021.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1021.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M16,4 L6.5,9l3.5,3 -6,4h9l2.5,-5L11,9l5,-3L16,4ZM14.55,5.878 L14.45,5.705 14.95,5.414 15.05,5.586 14.55,5.878ZM12.55,7.045 L12.45,6.872 13.45,6.289 13.55,6.461 12.55,7.045ZM10.55,8.211 L10.45,8.039 11.45,7.455 11.55,7.628 10.55,8.211ZM9.55,8.795 L9.174,9.015 9.439,9.235 9.311,9.389 8.826,8.986 9.45,8.622 9.55,8.795ZM10.939,10.485 L10.811,10.639 10.061,10.014 10.189,9.861 10.939,10.486ZM12.135,11.483 L11.769,11.996 11.606,11.879 11.865,11.517 11.561,11.264 11.689,11.111 12.135,11.483ZM10.519,13.746 L10.356,13.629 10.981,12.754 11.144,12.871 10.519,13.746ZM9.581,15.058 L9.419,14.942 9.731,14.504 9.894,14.621 9.581,15.058ZM3.535,2.467a0.467,0.467 0,0 1,0.933 0v0.725l0.628,-0.363a0.467,0.467 0,1 1,0.467 0.808L4.935,4l0.628,0.363a0.467,0.467 0,0 1,-0.467 0.808l-0.628,-0.363v0.725a0.467,0.467 0,1 1,-0.933 0v-0.725l-0.628,0.363a0.467,0.467 0,0 1,-0.467 -0.808L3.068,4l-0.628,-0.363a0.467,0.467 0,1 1,0.467 -0.808l0.628,0.363v-0.725Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M7.324,1.872 L4.175,0.048a0.347,0.347 0,0 0,-0.35 0L0.675,1.872a0.352,0.352 0,0 0,-0.175 0.304v3.648c0,0.126 0.067,0.242 0.175,0.305l3.15,1.824a0.344,0.344 0,0 0,0.35 0l3.149,-1.824a0.351,0.351 0,0 0,0.176 -0.305L7.5,2.176a0.353,0.353 0,0 0,-0.176 -0.304ZM6.798,5.622L4,7.241l-2.798,-1.62L1.202,2.38L4,0.758 6.798,2.38v3.242Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1022.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1022.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M2.121,0.352C1.873,0.01 1.337,-0.103 0.924,0.104 0.51,0.31 0.377,0.756 0.624,1.099l3.09,4.281a0.21,0.21 0,0 1,-0.017 0.27l-2.63,2.915C0.641,9.038 0.541,9.66 0.805,10.21L2.628,14H1a1,1 0,1 0,0 2h14a1,1 0,1 0,0 -2h-0.492l-2.082,-4.33a0.209,0.209 0,0 1,0.037 -0.234l2.63,-2.915c0.496,-0.551 0.543,-1.297 0.117,-1.888L12.12,0.353c-0.248,-0.344 -0.784,-0.456 -1.197,-0.25 -0.413,0.207 -0.547,0.653 -0.3,0.996l3.089,4.281a0.21,0.21 0,0 1,-0.017 0.27l-2.629,2.915c-0.426,0.473 -0.526,1.096 -0.262,1.645L12.63,14H9.51L7.425,9.67a0.209,0.209 0,0 1,0.037 -0.234l2.63,-2.915c0.496,-0.551 0.543,-1.297 0.117,-1.888L7.12,0.353c-0.248,-0.344 -0.784,-0.456 -1.197,-0.25 -0.413,0.207 -0.547,0.653 -0.3,0.996L8.714,5.38a0.21,0.21 0,0 1,-0.017 0.27l-2.63,2.915c-0.426,0.473 -0.526,1.096 -0.262,1.645L7.628,14h-3.12L2.426,9.67a0.209,0.209 0,0 1,0.037 -0.234l2.63,-2.915c0.497,-0.551 0.543,-1.297 0.117,-1.888L2.12,0.353Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1023.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1023.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M12.685,1.923S7.703,0.45 6.028,0.014A0.496,0.496 0,0 0,5.43 0.37L3.015,9.376a0.506,0.506 0,0 0,0.34 0.605,0.507 0.507,0 0,0 0.625,-0.347l1.044,-3.893 7.734,-3.01a0.434,0.434 0,0 0,-0.073 -0.808ZM0.777,11.644a0.5,0.5 0,1 0,-0.554 0.832l1.017,0.678a1.5,1.5 0,0 0,1.503 0.094l1.033,-0.517a0.5,0.5 0,0 1,0.448 0l1.105,0.553a1.5,1.5 0,0 0,1.342 0l1.105,-0.553a0.5,0.5 0,0 1,0.448 0l1.105,0.553a1.5,1.5 0,0 0,1.342 0l1.105,-0.553a0.5,0.5 0,0 1,0.448 0l1.033,0.517a1.5,1.5 0,0 0,1.503 -0.094l1.017,-0.678a0.5,0.5 0,1 0,-0.554 -0.832l-1.017,0.678a0.5,0.5 0,0 1,-0.501 0.031l-1.034,-0.517a1.5,1.5 0,0 0,-1.342 0l-1.105,0.553a0.5,0.5 0,0 1,-0.448 0l-1.105,-0.553a1.5,1.5 0,0 0,-1.342 0l-1.105,0.553a0.5,0.5 0,0 1,-0.448 0l-1.105,-0.553a1.5,1.5 0,0 0,-1.342 0l-1.034,0.517a0.5,0.5 0,0 1,-0.5 -0.03l-1.018,-0.679ZM0.777,14.144a0.5,0.5 0,1 0,-0.554 0.832l1.017,0.678a1.5,1.5 0,0 0,1.503 0.094l1.033,-0.517a0.5,0.5 0,0 1,0.448 0l1.105,0.553a1.5,1.5 0,0 0,1.342 0l1.105,-0.553a0.5,0.5 0,0 1,0.448 0l1.105,0.553a1.5,1.5 0,0 0,1.342 0l1.105,-0.553a0.5,0.5 0,0 1,0.448 0l1.033,0.517a1.5,1.5 0,0 0,1.503 -0.094l1.017,-0.678a0.5,0.5 0,1 0,-0.554 -0.832l-1.017,0.678a0.5,0.5 0,0 1,-0.501 0.031l-1.034,-0.517a1.5,1.5 0,0 0,-1.342 0l-1.105,0.553a0.5,0.5 0,0 1,-0.448 0l-1.105,-0.553a1.5,1.5 0,0 0,-1.342 0l-1.105,0.553a0.5,0.5 0,0 1,-0.448 0l-1.105,-0.553a1.5,1.5 0,0 0,-1.342 0l-1.034,0.517a0.5,0.5 0,0 1,-0.5 -0.03l-1.018,-0.679Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1024.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1024.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M11.306,1.326a0.281,0.281 0,0 0,0.48 -0.199L11.786,0.283a0.281,0.281 0,1 0,-0.562 0v0.844c0,0.075 0.03,0.146 0.082,0.2ZM9.011,2.373a0.281,0.281 0,0 0,0.307 -0.46l-0.598,-0.596a0.281,0.281 0,0 0,-0.398 0.398l0.598,0.597a0.28,0.28 0,0 0,0.091 0.06ZM7.283,4.78h0.844a0.281,0.281 0,0 0,0 -0.564h-0.844a0.281,0.281 0,0 0,0 0.563ZM8.36,7.716a0.281,0.281 0,0 0,0.355 -0.036l0.597,-0.596a0.281,0.281 0,0 0,-0.398 -0.398l-0.597,0.597a0.281,0.281 0,0 0,0.042 0.433ZM11.299,8.92a0.281,0.281 0,0 0,0.48 -0.2v-0.844a0.281,0.281 0,1 0,-0.563 0v0.844c0,0.075 0.03,0.147 0.083,0.2ZM14.374,7.747a0.28,0.28 0,0 0,0.367 -0.152,0.281 0.281,0 0,0 -0.061,-0.307l-0.597,-0.596a0.281,0.281 0,1 0,-0.397 0.398l0.597,0.596a0.28,0.28 0,0 0,0.09 0.061ZM14.876,4.787h0.844a0.282,0.282 0,0 0,0 -0.563h-0.844a0.281,0.281 0,1 0,0 0.563ZM13.734,2.353a0.282,0.282 0,0 0,0.356 -0.036l0.596,-0.596a0.281,0.281 0,0 0,-0.398 -0.398l-0.597,0.596a0.281,0.281 0,0 0,0.043 0.434ZM10.097,2.395a2.532,2.532 0,1 1,2.812 4.21,2.532 2.532,0 0,1 -2.813,-4.21ZM12.597,2.863a1.969,1.969 0,1 0,-2.188 3.274,1.969 1.969,0 0,0 2.188,-3.274ZM5,6.5a1.5,1.5 0,1 1,-3 0,1.5 1.5,0 0,1 3,0ZM4.061,8.751L2.904,8.52a1,1 0,0 0,-1.187 0.848l-0.708,5.31A1,1 0,0 0,2 15.81h1.055a1,1 0,0 0,0.555 -0.168l2.651,-1.767a0.2,0.2 0,0 1,0.2 -0.013l3.791,1.896a0.5,0.5 0,0 0,0.224 0.052h0.23a0.5,0.5 0,0 0,0.278 -0.916l-4.205,-2.803a0.8,0.8 0,0 0,-0.855 -0.02l-1.695,1.017a0.2,0.2 0,0 1,-0.3 -0.205l0.365,-2.19a0.2,0.2 0,0 1,0.339 -0.108l0.932,0.932a1,1 0,0 0,0.707 0.293h2.086a0.5,0.5 0,0 0,0 -1L6.441,10.81a0.2,0.2 0,0 1,-0.142 -0.058L4.572,9.024a1,1 0,0 0,-0.51 -0.273ZM4.694,1.619a0.218,0.218 0,0 0,-0.29 -0.096,0.213 0.213,0 0,0 -0.098,0.287l0.21,0.415c0.092,0.182 0.056,0.4 -0.09,0.544l-0.16,0.159a0.892,0.892 0,0 0,-0.17 1.038l0.21,0.415a0.218,0.218 0,0 0,0.29 0.096,0.213 0.213,0 0,0 0.098,-0.287l-0.21,-0.415a0.467,0.467 0,0 1,0.09 -0.544l0.16,-0.159a0.892,0.892 0,0 0,0.17 -1.038l-0.21,-0.415ZM2.403,1.523a0.218,0.218 0,0 1,0.29 0.096l0.21,0.415a0.892,0.892 0,0 1,-0.17 1.038l-0.16,0.159a0.467,0.467 0,0 0,-0.09 0.544l0.21,0.415a0.213,0.213 0,0 1,-0.096 0.287,0.218 0.218,0 0,1 -0.29,-0.096l-0.21,-0.415a0.892,0.892 0,0 1,0.17 -1.038l0.16,-0.159a0.467,0.467 0,0 0,0.09 -0.544l-0.21,-0.415a0.213,0.213 0,0 1,0.096 -0.287ZM3.403,1.523a0.218,0.218 0,0 1,0.29 0.096l0.21,0.415a0.892,0.892 0,0 1,-0.17 1.038l-0.16,0.159a0.467,0.467 0,0 0,-0.09 0.544l0.21,0.415a0.213,0.213 0,0 1,-0.096 0.287,0.218 0.218,0 0,1 -0.29,-0.096l-0.21,-0.415a0.892,0.892 0,0 1,0.17 -1.038l0.16,-0.159a0.467,0.467 0,0 0,0.09 -0.544l-0.21,-0.415a0.213,0.213 0,0 1,0.096 -0.287Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1025.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1025.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M15.4,3c-0.9,0.3 -1.2,1.1 -1.1,1.6 -0.7,-0.8 -0.7,-1.7 -0.6,-3.1 -2.1,0.8 -1.6,3.2 -1.7,4 -0.5,-0.5 -0.6,-1.5 -0.6,-1.5 -0.6,0.3 -0.9,1.1 -0.9,1.8 0,1.6 1.3,2.7 2.8,2.7 1.5,0 2.7,-1.2 2.7,-2.7 0,-1.1 -0.6,-1.4 -0.6,-2.8Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M12.3,9.3c-1.6,-0.4 -2.8,-1.8 -2.8,-3.6 0,-0.6 0.2,-1.3 0.6,-1.9L7.26,0.203a0.2,0.2 0,0 0,-0.316 0.003l-3.7,4.873a0.2,0.2 0,0 0,0.159 0.321H4.8L2.056,8.876a0.2,0.2 0,0 0,0.157 0.324H4.2L0.298,13.567a0.2,0.2 0,0 0,0.149 0.333H6v1.9c0,0.11 0.09,0.2 0.2,0.2H8a0.2,0.2 0,0 0,0.2 -0.2v-1.9h5.547a0.2,0.2 0,0 0,0.147 -0.335L10,9.3h2.3Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1026.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1026.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M15.454,5.05c-0.818,0.27 -1.09,0.99 -1,1.44 -0.636,-0.72 -0.636,-1.53 -0.545,-2.79 -1.909,0.72 -1.455,2.88 -1.545,3.6 -0.455,-0.45 -0.546,-1.35 -0.546,-1.35 -0.545,0.27 -0.818,0.99 -0.818,1.62C11,9.01 12.182,10 13.546,10A2.432,2.432 0,0 0,16 7.57c0,-0.99 -0.546,-1.26 -0.546,-2.52Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M14.7,10.8v-0.2c-0.4,0.2 -0.8,0.2 -1.3,0.2 -0.9,0 -1.7,-0.3 -2.3,-0.8 -0.3,0.4 -0.6,0.9 -0.8,1.4 -0.4,1.1 -0.7,2 -0.8,2.8 -0.1,-1.6 -0.3,-4.2 -1.1,-6.6C7,3.1 2.2,0 2.2,0s2.6,6.5 2.9,9.8c0.3,2.2 -0.1,4.3 -0.3,5.4 -0.1,-0.8 -0.3,-2 -0.9,-3.3C2.8,9.3 0,7.6 0,7.6s1.4,3.2 1.7,5.1c0.2,1.8 -0.4,3.3 -0.4,3.3h13.5c0.1,0 -1,-1.5 -0.1,-5.2Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1027.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1027.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.07,4.933a0.933,0.933 0,0 1,1.866 0v1.45l1.256,-0.725a0.933,0.933 0,1 1,0.933 1.617L9.87,8l1.256,0.725a0.933,0.933 0,1 1,-0.933 1.617l-1.256,-0.725v1.45a0.933,0.933 0,0 1,-1.867 0v-1.45l-1.256,0.725a0.933,0.933 0,1 1,-0.933 -1.617L6.136,8 4.88,7.275a0.933,0.933 0,0 1,0.933 -1.617l1.256,0.725v-1.45Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M14.649,3.743 L8.35,0.095a0.693,0.693 0,0 0,-0.701 0L1.351,3.743a0.705,0.705 0,0 0,-0.351 0.61v7.295c0,0.251 0.134,0.483 0.351,0.61l6.298,3.647a0.688,0.688 0,0 0,0.701 0l6.298,-3.648a0.702,0.702 0,0 0,0.352 -0.609L15,4.352a0.705,0.705 0,0 0,-0.351 -0.609ZM13.597,11.243L8,14.483l-5.597,-3.242L2.403,4.76L8,1.516l5.597,3.242v6.484Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1028.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1028.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M15.25,4.13a2.08,2.08 0,0 0,0.486 -1.328,2.102 2.102,0 0,0 -3.284,-1.734A7.305,7.305 0,0 0,8.652 0,7.35 7.35,0 0,0 1.3,7.35c0,0.879 0.162,1.717 0.445,2.498A3.14,3.14 0,0 0,0 12.654a3.15,3.15 0,0 0,3.15 3.15,3.135 3.135,0 0,0 2.748,-1.64 7.327,7.327 0,0 0,5.564 -0.021A7.35,7.35 0,0 0,16 7.35a7.3,7.3 0,0 0,-0.75 -3.222ZM3.15,14.333a1.682,1.682 0,0 1,-1.68 -1.68c0,-0.927 0.754,-1.68 1.68,-1.68a1.681,1.681 0,0 1,0 3.36ZM8.65,13.232c-0.812,0 -1.615,-0.17 -2.357,-0.497 0,-0.027 0.008,-0.054 0.008,-0.081a3.15,3.15 0,0 0,-3.117 -3.147,5.838 5.838,0 0,1 -0.415,-2.155 5.888,5.888 0,0 1,5.881 -5.88,5.84 5.84,0 0,1 2.958,0.806 2.08,2.08 0,0 0,-0.074 0.524c0,1.16 0.94,2.1 2.1,2.1 0.116,0 0.228,-0.015 0.34,-0.033a5.83,5.83 0,0 1,0.557 2.483,5.889 5.889,0 0,1 -5.88,5.88Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M8.584,4.829a2.688,2.688 0,1 0,0 5.376,2.688 2.688,0 0,0 0,-5.376Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
15
app/src/main/res/drawable-anydpi/qweather_1029.xml
Normal file
15
app/src/main/res/drawable-anydpi/qweather_1029.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M10.649,0.631a2,2 0,0 0,-3.275 0.533,1.5 1.5,0 0,0 -2.098,0.84 1,1 0,0 0,-1.028 0.665,1 1,0 1,0 0.388,1.162 0.995,0.995 0,0 0,1.22 -0.084,1.493 1.493,0 0,0 1.388,0.148 1.5,1.5 0,0 0,2.362 0.793,2.5 2.5,0 0,0 4.149,-0.719A1.002,1.002 0,0 0,15 3a1,1 0,0 0,-0.674 -0.946,1 1,0 0,0 -1.36,-1.042 2.497,2.497 0,0 0,-2.318 -0.381ZM2.234,6.096a0.75,0.75 0,1 0,0 -1.5,0.75 0.75,0 0,0 0,1.5ZM3,2a0.5,0.5 0,1 0,0 -1,0.5 0.5,0 0,0 0,1Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M5,1.5a0.5,0.5 0,1 0,0 -1,0.5 0.5,0 0,0 0,1ZM4.5,5.5a0.5,0.5 0,1 0,0 -1,0.5 0.5,0 0,0 0,1ZM1.5,6.5h3v1h-3v-1ZM16,16L0,16v-1h1.034l0.5,-7h2.932l0.5,7L16,15v1ZM3.963,15l-0.143,-2L2.18,13l-0.143,2h1.926ZM3.749,12 L3.682,11.067L2.318,11.067L2.251,12L3.75,12ZM3.611,10.067L3.534,9L2.466,9l-0.077,1.067h1.222Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M10.773,7.63a0.263,0.263 0,0 1,0.454 0l3.738,6.482a0.26,0.26 0,0 1,-0.227 0.388L7.262,14.5a0.26,0.26 0,0 1,-0.227 -0.388l3.738,-6.481ZM11,9.25c-0.367,0 -0.655,0.242 -0.623,0.524l0.282,2.476h0.682l0.282,-2.476c0.032,-0.282 -0.256,-0.524 -0.623,-0.524ZM11.004,13.75a0.5,0.5 0,1 0,0 -1,0.5 0.5,0 0,0 0,1Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_102_fill.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_102_fill.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M13.268,15.162a0.224,0.224 0,0 0,-0.233 0.042A2.99,2.99 0,0 1,11 16a2.99,2.99 0,0 1,-2.035 -0.796,0.224 0.224,0 0,0 -0.233,-0.042 2,2 0,1 1,-0.383 -3.832,0.224 0.224,0 0,0 0.22,-0.087A2.996,2.996 0,0 1,11 10c1,0 1.887,0.49 2.432,1.243 0.05,0.069 0.136,0.102 0.22,0.087a2,2 0,1 1,-0.383 3.832ZM11,15.25c0.752,0 1.418,-0.37 1.827,-0.936 0.086,-0.12 0.273,-0.134 0.388,-0.041a1.25,1.25 0,1 0,0.209 -2.082c-0.132,0.068 -0.312,0.017 -0.373,-0.118a2.25,2.25 0,0 0,-4.102 0c-0.06,0.135 -0.241,0.186 -0.372,0.118a1.25,1.25 0,1 0,0.209 2.082c0.114,-0.093 0.301,-0.079 0.387,0.04A2.247,2.247 0,0 0,11 15.25ZM3.4,11.877 L3.402,11.875a0.5,0.5 0,1 1,0.707 0.707l-1.065,1.064a0.5,0.5 0,1 1,-0.707 -0.707l0.003,-0.003h0.001l1.057,-1.059L3.4,11.877ZM8.357,2.354A0.5,0.5 0,0 1,7.503 2L7.503,0.5a0.5,0.5 0,0 1,1 0L8.503,2a0.5,0.5 0,0 1,-0.146 0.354ZM3.76,4.245a0.5,0.5 0,0 1,-0.352 -0.14L2.347,3.044a0.5,0.5 0,0 1,0.708 -0.706l1.06,1.06a0.5,0.5 0,0 1,-0.355 0.847ZM2.354,7.636A0.5,0.5 0,0 1,2 8.49L0.5,8.49a0.5,0.5 0,0 1,0 -1L2,7.49a0.5,0.5 0,0 1,0.354 0.146ZM13.64,8.357a0.5,0.5 0,0 1,0.353 -0.854h1.5a0.5,0.5 0,0 1,0 1h-1.5a0.5,0.5 0,0 1,-0.354 -0.146ZM12.433,4.223a0.498,0.498 0,0 1,-0.47 -0.046,0.5 0.5,0 0,1 -0.075,-0.77l1.061,-1.06a0.5,0.5 0,0 1,0.706 0.707l-1.06,1.061a0.498,0.498 0,0 1,-0.162 0.108Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M9.975,9.166a3.846,3.846 0,0 0,-1.961 1.244v0.001a2.923,2.923 0,0 0,-2.381 1.397,4.5 4.5,0 1,1 6.868,-3.812 4.453,4.453 0,0 1,-0.207 1.282,3.846 3.846,0 0,0 -2.32,-0.112Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_103.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_103.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M13.583,11.078c-0.199,0.005 -0.396,0.03 -0.59,0.075A4.249,4.249 0,0 0,10.128 10a4.279,4.279 0,0 0,-1.642 0.34,4.05 4.05,0 0,0 -1.354,0.935 2.953,2.953 0,0 0,-0.579 -0.056,3.096 3.096,0 0,0 -1.364,0.297c-0.423,0.2 -0.787,0.494 -1.063,0.856a1.707,1.707 0,0 0,-0.44 -0.094,1.769 1.769,0 0,0 -0.75,0.163 1.66,1.66 0,0 0,-0.595 0.462,1.53 1.53,0 0,0 -0.312,0.662 1.49,1.49 0,0 0,0.037 0.723c0.072,0.235 0.201,0.451 0.378,0.631 0.176,0.18 0.394,0.32 0.638,0.406a1.778,1.778 0,0 0,1.493 -0.14c0.558,0.443 1.268,0.68 1.998,0.665 0.527,0 1.046,-0.126 1.508,-0.365a4.267,4.267 0,0 0,2.222 0.511,4.23 4.23,0 0,0 2.162,-0.699c0.345,0.184 0.733,0.28 1.13,0.282a2.49,2.49 0,0 0,1.69 -0.652c0.451,-0.418 0.708,-0.986 0.716,-1.58a2.297,2.297 0,0 0,-0.735 -1.579,2.597 2.597,0 0,0 -1.682,-0.69ZM13.583,14.669a1.437,1.437 0,0 1,-0.66 -0.169,1.051 1.051,0 0,0 -1.058,0.066 3.036,3.036 0,0 1,-1.738 0.525,3.148 3.148,0 0,1 -1.548,-0.384 1.049,1.049 0,0 0,-0.509 -0.132,0.986 0.986,0 0,0 -0.48,0.122c-0.306,0.156 -0.65,0.24 -0.998,0.244a2.142,2.142 0,0 1,-1.338 -0.44,1.038 1.038,0 0,0 -0.65,-0.226c-0.19,0 -0.599,0.235 -0.888,0.235a0.694,0.694 0,0 1,-0.427 -0.21,0.616 0.616,0 0,1 -0.17,-0.423c0,-0.156 0.06,-0.306 0.17,-0.423a0.694,0.694 0,0 1,0.427 -0.21c0.05,0 0.4,0.056 0.489,0.056a0.884,0.884 0,0 0,0.451 -0.096,0.816 0.816,0 0,0 0.328,-0.307c0.188,-0.232 0.431,-0.42 0.71,-0.549 0.28,-0.129 0.587,-0.194 0.898,-0.192 0.13,0 0.49,0.066 0.61,0.066a1.05,1.05 0,0 0,0.39 -0.095,0.993 0.993,0 0,0 0.318,-0.233 3.13,3.13 0,0 1,1.017 -0.683c0.384,-0.161 0.8,-0.248 1.22,-0.255 0.403,0.005 0.801,0.085 1.171,0.235 0.37,0.15 0.706,0.366 0.987,0.637a1,1 0,0 0,0.329 0.21c0.123,0.048 0.256,0.072 0.39,0.072 0.1,0 0.46,-0.075 0.56,-0.075 0.362,0.027 0.704,0.173 0.963,0.413 0.26,0.24 0.42,0.559 0.454,0.9a1.293,1.293 0,0 1,-0.419 0.934,1.467 1.467,0 0,1 -0.999,0.387ZM8.354,2.374A0.5,0.5 0,0 1,7.5 2L7.5,0.5a0.5,0.5 0,1 1,1 0.02v1.5a0.5,0.5 0,0 1,-0.146 0.354ZM3.58,4.232a0.48,0.48 0,0 1,-0.16 -0.112L2.36,3.06a0.495,0.495 0,0 1,0.7 -0.7l1.06,1.06a0.48,0.48 0,0 1,0 0.7,0.48 0.48,0 0,1 -0.54,0.112ZM2.364,7.646A0.5,0.5 0,0 1,2 8.5L0.51,8.5a0.5,0.5 0,0 1,0 -1h1.5a0.5,0.5 0,0 1,0.354 0.146ZM13.606,8.354A0.5,0.5 0,0 1,14 7.5h1.5a0.5,0.5 0,1 1,-0.04 1h-1.5a0.5,0.5 0,0 1,-0.354 -0.146ZM12.44,4.242a0.47,0.47 0,0 1,-0.19 0.038,0.47 0.47,0 0,1 -0.35,-0.15 0.48,0.48 0,0 1,0 -0.7l1.06,-1.06a0.495,0.495 0,0 1,0.7 0.7L12.6,4.13a0.471,0.471 0,0 1,-0.16 0.112ZM5.86,10.42a3.57,3.57 0,0 0,-1 0.41,4.33 4.33,0 0,1 -1.12,-2.95 4.38,4.38 0,1 1,8.44 1.64,4.179 4.179,0 0,0 -0.92,-0.32 3.41,3.41 0,1 0,-5.4 1.22Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
18
app/src/main/res/drawable-anydpi/qweather_1030.xml
Normal file
18
app/src/main/res/drawable-anydpi/qweather_1030.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M11.5,7a0.5,0.5 0,0 0,-0.5 0.5v2.063a2,2 0,1 0,1 0V7.5a0.5,0.5 0,0 0,-0.5 -0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="m10.2,8.399 l-0.532,0.356a3.3,3.3 0,1 0,3.665 0l-0.533,-0.356L12.8,2.5a1.3,1.3 0,1 0,-2.6 0v5.899ZM9,2.5a2.5,2.5 0,0 1,5 0v5.258a4.5,4.5 0,1 1,-5 0L9,2.5ZM2.651,1.85a0.35,0.35 0,1 1,0.7 0v0.544l0.471,-0.272a0.35,0.35 0,0 1,0.35 0.606L3.7,3l0.47,0.272a0.35,0.35 0,0 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,0 1,-0.35 -0.606L2.3,3l-0.47,-0.272a0.35,0.35 0,0 1,0.35 -0.606l0.47,0.272L2.65,1.85Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M5.493,1.404 L3.131,0.036a0.26,0.26 0,0 0,-0.263 0L0.507,1.404a0.264,0.264 0,0 0,-0.132 0.228v2.736c0,0.094 0.05,0.181 0.132,0.228l2.361,1.368a0.258,0.258 0,0 0,0.263 0l2.362,-1.368a0.264,0.264 0,0 0,0.132 -0.228L5.625,1.632a0.264,0.264 0,0 0,-0.132 -0.228ZM5.1,4.216 L3,5.432 0.901,4.216L0.901,1.785L3,0.569l2.099,1.215v2.432ZM5.493,8.404L3.131,7.036a0.26,0.26 0,0 0,-0.263 0L0.507,8.404a0.264,0.264 0,0 0,-0.132 0.228v2.736c0,0.094 0.05,0.181 0.132,0.228l2.361,1.368a0.258,0.258 0,0 0,0.263 0l2.362,-1.368a0.264,0.264 0,0 0,0.132 -0.228L5.625,8.632a0.264,0.264 0,0 0,-0.132 -0.228ZM5.1,11.216 L3,12.432 0.901,11.216L0.901,8.785L3,7.569l2.099,1.215v2.432Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M2.293,11.207A1,1 0,0 1,2 10.5c0,-0.5 0.555,-1.395 1,-2 0.445,0.605 1,1.5 1,2a1,1 0,0 1,-1.707 0.707Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1031.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1031.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="m1.959,8.648 l3.43,-2.169a0.288,0.288 0,0 0,-0.067 -0.517l-1.853,-0.579a5.17,5.17 0,0 1,0.808 -1.08,5.254 5.254,0 0,1 1.668,-1.126 5.298,5.298 0,0 1,4.084 0,5.22 5.22,0 0,1 1.668,1.125c0.48,0.478 0.861,1.045 1.125,1.668a0.701,0.701 0,0 0,1.292 -0.546,6.612 6.612,0 0,0 -1.425,-2.113 6.635,6.635 0,0 0,-2.114 -1.425,6.7 6.7,0 0,0 -5.177,0 6.618,6.618 0,0 0,-2.114 1.425c-0.485,0.484 -0.86,1.047 -1.172,1.647l-1.74,-0.543a0.287,0.287 0,0 0,-0.35 0.382l1.517,3.717a0.289,0.289 0,0 0,0.42 0.134ZM15.979,11.05L14.46,7.334a0.286,0.286 0,0 0,-0.419 -0.134l-3.43,2.168a0.287,0.287 0,0 0,0.067 0.517l1.91,0.598a5.238,5.238 0,0 1,-0.892 1.24,5.22 5.22,0 0,1 -3.71,1.535 5.285,5.285 0,0 1,-2.042 -0.41,5.242 5.242,0 0,1 -1.668,-1.124 5.24,5.24 0,0 1,-1.125 -1.67,0.701 0.701,0 0,0 -1.292,0.547 6.608,6.608 0,0 0,1.425 2.113,6.629 6.629,0 0,0 4.701,1.948 6.615,6.615 0,0 0,4.702 -1.948,6.63 6.63,0 0,0 1.258,-1.807l1.681,0.526a0.287,0.287 0,0 0,0.352 -0.383Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1032.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1032.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.81,8c0,0.473 -0.077,0.872 -0.232,1.198a1.686,1.686 0,0 1,-0.638 0.74c-0.272,0.166 -0.585,0.25 -0.94,0.25s-0.668,-0.084 -0.94,-0.25a1.708,1.708 0,0 1,-0.641 -0.74c-0.153,-0.326 -0.23,-0.726 -0.23,-1.198s0.077,-0.871 0.23,-1.195c0.155,-0.327 0.368,-0.573 0.64,-0.74A1.75,1.75 0,0 1,6 5.813c0.355,0 0.668,0.084 0.94,0.252 0.273,0.167 0.485,0.413 0.638,0.74 0.155,0.324 0.233,0.723 0.233,1.195Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M13.99,13.245a3,3 0,0 1,-4.49 2.354A2.987,2.987 0,0 1,8 16a2.987,2.987 0,0 1,-1.5 -0.401,3 3,0 0,1 -4.49,-2.354A2.993,2.993 0,0 1,1 11c0,-0.535 0.14,-1.037 0.385,-1.471a2.998,2.998 0,0 1,-0.304 -4.835A3,3 0,0 1,3.755 1.01,2.993 2.993,0 0,1 6,0c0.768,0 1.47,0.289 2,0.764A2.989,2.989 0,0 1,10 0c0.893,0 1.695,0.39 2.245,1.01a3,3 0,0 1,2.674 3.684,2.998 2.998,0 0,1 -0.304,4.834c0.245,0.435 0.385,0.937 0.385,1.472 0,0.893 -0.39,1.695 -1.01,2.245ZM9,8c0,-0.671 -0.132,-1.245 -0.395,-1.722A2.722,2.722 0,0 0,7.533 5.18,3.073 3.073,0 0,0 6,4.8a3.09,3.09 0,0 0,-1.537 0.38c-0.45,0.254 -0.807,0.62 -1.07,1.098C3.13,6.755 3,7.328 3,8c0,0.67 0.13,1.243 0.392,1.722 0.264,0.476 0.62,0.842 1.071,1.098 0.453,0.253 0.965,0.38 1.537,0.38s1.083,-0.127 1.533,-0.38c0.453,-0.254 0.81,-0.619 1.072,-1.095C8.868,9.246 9,8.67 9,8ZM10.71,10.654c0.226,0.097 0.482,0.146 0.77,0.146 0.296,0 0.558,-0.05 0.787,-0.148 0.229,-0.1 0.408,-0.235 0.538,-0.407A0.941,0.941 0,0 0,13 9.654a0.836,0.836 0,0 0,-0.228 -0.605c-0.149,-0.16 -0.364,-0.258 -0.647,-0.296a0.018,0.018 0,0 1,-0.016 -0.018c0,-0.009 0.006,-0.016 0.015,-0.018a0.939,0.939 0,0 0,0.523 -0.274,0.753 0.753,0 0,0 0.206,-0.546 0.94,0.94 0,0 0,-0.17 -0.555,1.17 1.17,0 0,0 -0.476,-0.396 1.644,1.644 0,0 0,-0.715 -0.146c-0.27,0 -0.512,0.049 -0.727,0.146 -0.213,0.097 -0.383,0.23 -0.51,0.402a0.98,0.98 0,0 0,-0.173 0.39c-0.022,0.11 0.071,0.203 0.184,0.203h0.402c0.108,0 0.191,-0.09 0.239,-0.186a0.541,0.541 0,0 1,0.271 -0.242,0.774 0.774,0 0,1 0.603,0.002 0.47,0.47 0,0 1,0.268 0.431,0.46 0.46,0 0,1 -0.08,0.27 0.537,0.537 0,0 1,-0.228 0.18,0.81 0.81,0 0,1 -0.334,0.064h-0.167a0.2,0.2 0,0 0,-0.201 0.2v0.204c0,0.11 0.09,0.2 0.2,0.2h0.168a0.98,0.98 0,0 1,0.386 0.069,0.557 0.557,0 0,1 0.25,0.19c0.06,0.08 0.09,0.172 0.09,0.275a0.461,0.461 0,0 1,-0.084 0.272,0.553 0.553,0 0,1 -0.23,0.185 0.81,0.81 0,0 1,-0.337 0.066,0.877 0.877,0 0,1 -0.33,-0.059 0.582,0.582 0,0 1,-0.235 -0.165,0.436 0.436,0 0,1 -0.045,-0.07c-0.05,-0.093 -0.133,-0.181 -0.24,-0.181h-0.445c-0.113,0 -0.206,0.092 -0.184,0.202a0.99,0.99 0,0 0,0.178 0.399c0.13,0.172 0.306,0.308 0.53,0.407Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1033.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1033.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0ZM1.501,10a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,1 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.471,0.272a0.35,0.35 0,1 0,0.35 -0.606L2.2,11.5l0.47,-0.272a0.35,0.35 0,1 0,-0.349 -0.606l-0.471,0.272v-0.544A0.35,0.35 0,0 0,1.5 10ZM5.501,12a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,1 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.471,0.272a0.35,0.35 0,1 0,0.35 -0.606L6.2,13.5l0.471,-0.272a0.35,0.35 0,1 0,-0.35 -0.606l-0.471,0.272v-0.544A0.35,0.35 0,0 0,5.5 12ZM10.151,12.35a0.35,0.35 0,1 1,0.7 0v0.544l0.47,-0.272a0.35,0.35 0,1 1,0.35 0.606l-0.47,0.272 0.47,0.272a0.35,0.35 0,1 1,-0.35 0.606l-0.47,-0.272v0.544a0.35,0.35 0,1 1,-0.7 0v-0.544l-0.47,0.272a0.35,0.35 0,1 1,-0.35 -0.606l0.47,-0.272 -0.47,-0.272a0.35,0.35 0,1 1,0.35 -0.606l0.47,0.272v-0.544ZM14.501,10a0.35,0.35 0,0 0,-0.35 0.35v0.544l-0.47,-0.272a0.35,0.35 0,1 0,-0.35 0.606l0.47,0.272 -0.47,0.272a0.35,0.35 0,1 0,0.35 0.606l0.47,-0.272v0.544a0.35,0.35 0,1 0,0.7 0v-0.544l0.47,0.272a0.35,0.35 0,1 0,0.35 -0.606l-0.47,-0.272 0.47,-0.272a0.35,0.35 0,1 0,-0.35 -0.606l-0.47,0.272v-0.544a0.35,0.35 0,0 0,-0.35 -0.35Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1034.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1034.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M2.302,1.7a0.7,0.7 0,0 1,1.4 0v1.088l0.942,-0.544a0.7,0.7 0,1 1,0.7 1.212L4.402,4l0.942,0.544a0.7,0.7 0,1 1,-0.7 1.212l-0.942,-0.544V6.3a0.7,0.7 0,1 1,-1.4 0V5.212l-0.942,0.544a0.7,0.7 0,0 1,-0.7 -1.212L1.602,4 0.66,3.456a0.7,0.7 0,0 1,0.7 -1.212l0.942,0.544V1.7ZM11.5,7a0.5,0.5 0,0 0,-0.5 0.5v2.063a2,2 0,1 0,1 0V7.5a0.5,0.5 0,0 0,-0.5 -0.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="m10.2,8.399 l-0.532,0.356a3.3,3.3 0,1 0,3.665 0l-0.533,-0.356V2.5a1.3,1.3 0,1 0,-2.6 0v5.899ZM9,2.5a2.5,2.5 0,0 1,5 0v5.258a4.5,4.5 0,1 1,-5 0V2.5Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1035.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1035.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M8.293,15.707A1,1 0,0 1,8 15c0,-0.5 0.555,-1.395 1,-2 0.445,0.605 1,1.5 1,2a1,1 0,0 1,-1.707 0.707ZM2.293,9.707A1,1 0,0 1,2 9c0,-0.5 0.555,-1.395 1,-2 0.445,0.605 1,1.5 1,2a1,1 0,0 1,-1.707 0.707ZM12.293,15.707A1,1 0,0 1,12 15c0,-0.5 0.555,-1.395 1,-2 0.445,0.605 1,1.5 1,2a1,1 0,0 1,-1.707 0.707ZM7.268,5.162a0.224,0.224 0,0 0,-0.233 0.042A2.99,2.99 0,0 1,5 6a2.99,2.99 0,0 1,-2.035 -0.796,0.224 0.224,0 0,0 -0.233,-0.042 2,2 0,1 1,-0.383 -3.832,0.224 0.224,0 0,0 0.22,-0.087A2.996,2.996 0,0 1,5 0c1,0 1.887,0.49 2.432,1.243 0.05,0.069 0.136,0.102 0.22,0.087a2,2 0,1 1,-0.383 3.832ZM5,5.25c0.752,0 1.418,-0.37 1.827,-0.936 0.086,-0.12 0.273,-0.134 0.388,-0.041a1.25,1.25 0,1 0,0.209 -2.082c-0.132,0.068 -0.312,0.017 -0.373,-0.118a2.25,2.25 0,0 0,-4.102 0c-0.06,0.135 -0.241,0.186 -0.372,0.118a1.25,1.25 0,1 0,0.209 2.082c0.114,-0.093 0.301,-0.079 0.387,0.04A2.247,2.247 0,0 0,5 5.25ZM13.137,11.105A2.99,2.99 0,0 1,11 12a2.99,2.99 0,0 1,-2.138 -0.895,2 2,0 1,1 -0.375,-3.745A2.997,2.997 0,0 1,11 6c1.052,0 1.977,0.541 2.512,1.36A2.004,2.004 0,0 1,16 9.3a2,2 0,0 1,-2.863 1.805ZM10.287,7.881 L10.563,9.64h0.863l0.286,-1.822a0.677,0.677 0,0 0,-0.327 -0.682l-0.056,-0.034a0.607,0.607 0,0 0,-0.645 -0.018c-0.26,0.157 -0.442,0.508 -0.397,0.797ZM11.48,10.52a0.48,0.48 0,1 0,-0.96 0,0.48 0.48,0 0,0 0.96,0Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable-anydpi/qweather_1036.xml
Normal file
12
app/src/main/res/drawable-anydpi/qweather_1036.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M3,10.76c-0.683,-0.13 -1.336,-0.353 -2.139,-0.705 -0.298,-0.132 -0.657,-0.018 -0.801,0.253 -0.144,0.27 -0.02,0.597 0.279,0.728 1.034,0.454 1.872,0.72 2.794,0.854a5.438,5.438 0,0 0,1.331 2.548C5.402,15.438 6.674,16 8,16s2.598,-0.562 3.536,-1.562c0.937,-1 1.464,-2.357 1.464,-3.771C13,8.24 10.703,4.073 8.615,0.91A78.36,78.36 0,0 0,8 0a61.87,61.87 0,0 0,-0.615 0.911,49.363 49.363,0 0,0 -2.39,3.999c-1.648,0.01 -2.627,-0.194 -4.134,-0.856 -0.298,-0.13 -0.657,-0.017 -0.801,0.254 -0.144,0.27 -0.02,0.597 0.279,0.728 1.496,0.657 2.581,0.92 4.105,0.959a22.42,22.42 0,0 0,-0.805 1.858c-0.939,-0.1 -1.73,-0.339 -2.778,-0.799 -0.298,-0.13 -0.657,-0.017 -0.801,0.254 -0.144,0.27 -0.02,0.597 0.279,0.728 1.092,0.48 1.964,0.749 2.948,0.875C3.104,9.557 3,10.15 3,10.667v0.092ZM4.005,10.884A4.554,4.554 0,0 1,4 10.667c0,-0.43 0.101,-0.992 0.312,-1.676 0.252,0.009 0.516,0.01 0.796,0.008 1.249,-0.015 1.993,-0.128 3.18,-0.482 0.314,-0.094 0.486,-0.402 0.382,-0.688 -0.103,-0.286 -0.442,-0.441 -0.757,-0.347 -1.07,0.319 -1.694,0.413 -2.82,0.427h-0.394a24.089,24.089 0,0 1,0.88 -1.922c0.982,-0.037 1.678,-0.163 2.708,-0.47 0.315,-0.094 0.487,-0.402 0.383,-0.688 -0.103,-0.286 -0.442,-0.441 -0.757,-0.347 -0.677,0.201 -1.175,0.313 -1.734,0.372A49.378,49.378 0,0 1,8 1.835c0.86,1.32 1.736,2.791 2.453,4.213 0.471,0.936 0.864,1.834 1.138,2.643 0.277,0.82 0.409,1.486 0.409,1.976a4.415,4.415 0,0 1,-1.172 3.017c-0.75,0.8 -1.767,1.25 -2.828,1.25 -1.06,0 -2.078,-0.45 -2.828,-1.25a4.324,4.324 0,0 1,-0.976 -1.698c0.287,0.013 0.59,0.016 0.912,0.013 1.249,-0.015 1.993,-0.128 3.18,-0.482 0.314,-0.094 0.486,-0.402 0.382,-0.688 -0.103,-0.286 -0.442,-0.441 -0.757,-0.348 -1.07,0.32 -1.694,0.414 -2.82,0.428 -0.396,0.004 -0.754,-0.003 -1.088,-0.025Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
<path
|
||||
android:pathData="M11.052,4.996c1.675,-0.025 2.681,0.09 4.375,0.488a0.47,0.47 0,0 0,0.562 -0.376,0.497 0.497,0 0,0 -0.357,-0.592c-1.84,-0.433 -2.934,-0.549 -4.818,-0.509a8.9,8.9 0,0 0,-0.295 0.012c0.183,0.325 0.361,0.651 0.533,0.977ZM12.421,8.015c0.975,0.051 1.823,0.191 3.006,0.47a0.47,0.47 0,0 0,0.562 -0.377,0.497 0.497,0 0,0 -0.357,-0.592c-1.412,-0.332 -2.385,-0.478 -3.612,-0.51 0.148,0.344 0.282,0.682 0.402,1.01ZM15.427,11.485c-0.95,-0.224 -1.684,-0.358 -2.44,-0.429a4.745,4.745 0,0 0,-0.029 -0.999c0.838,0.072 1.637,0.215 2.674,0.458 0.253,0.06 0.413,0.325 0.357,0.593a0.47,0.47 0,0 1,-0.562 0.377Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1037.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1037.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="m9,4.866 l-3.027,5.462 0.696,1.729 -1.761,3.927L0.212,16a0.184,0.184 0,0 1,-0.103 -0.031,0.232 0.232,0 0,1 -0.077,-0.088 0.29,0.29 0,0 1,-0.01 -0.246L6.69,0.149a0.247,0.247 0,0 1,0.077 -0.107A0.188,0.188 0,0 1,6.88 0c0.04,0 0.08,0.012 0.113,0.037a0.243,0.243 0,0 1,0.08 0.105L9,4.866ZM13.5,11l2.482,4.676c0.057,0.15 -0.03,0.324 -0.163,0.324L10,15.969 13.5,11ZM11.905,7.56 L12.365,3 8.205,10.05 9.81,9.838L8,15.068l5.653,-7.362 -1.748,-0.145Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-anydpi/qweather_1038.xml
Normal file
9
app/src/main/res/drawable-anydpi/qweather_1038.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M7.9,10a4.99,4.99 0,0 0,3.827 -1.783,3 3,0 1,0 0.553,-5.63A4.999,4.999 0,0 0,7.9 0a4.998,4.998 0,0 0,-4.359 2.549,3 3,0 1,0 0.586,5.732A4.988,4.988 0,0 0,7.9 10ZM7.109,3.602c-0.057,-0.362 0.17,-0.8 0.496,-0.997 0.256,-0.153 0.551,-0.133 0.806,0.023l0.07,0.042a0.846,0.846 0,0 1,0.409 0.853L8.532,5.8L7.454,5.8L7.11,3.602ZM8.599,6.9a0.6,0.6 0,1 1,-1.2 0,0.6 0.6,0 0,1 1.2,0ZM1,12.5a1,1 0,1 0,2 0c0,-0.5 -0.555,-1.395 -1,-2 -0.445,0.605 -1,1.5 -1,2ZM5,15a1,1 0,1 0,2 0c0,-0.5 -0.555,-1.395 -1,-2 -0.445,0.605 -1,1.5 -1,2ZM9.293,15.707A1,1 0,0 1,9 15c0,-0.5 0.555,-1.395 1,-2 0.445,0.605 1,1.5 1,2a1,1 0,0 1,-1.707 0.707ZM13,12.5a1,1 0,0 0,2 0c0,-0.5 -0.555,-1.395 -1,-2 -0.445,0.605 -1,1.5 -1,2Z"
|
||||
android:fillColor="?attr/colorControlNormal" />
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user