V1.0.0 (1)
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
||||
57
app/build.gradle.kts
Normal file
@ -0,0 +1,57 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.key.vibekeyboard"
|
||||
compileSdk = 34
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.key.vibekeyboard"
|
||||
minSdk = 23
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(libs.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation(libs.activity)
|
||||
implementation(libs.constraintlayout)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
// Room 运行时库
|
||||
implementation ("androidx.room:room-runtime:2.6.1")
|
||||
// Room 编译器,用于生成代码
|
||||
annotationProcessor ("androidx.room:room-compiler:2.6.1")
|
||||
// Glide 依赖
|
||||
implementation ("com.github.bumptech.glide:glide:4.16.0")
|
||||
//Zip
|
||||
implementation("com.github.omicronapps:7-Zip-JBinding-4Android:Release-16.02-2.02")
|
||||
|
||||
|
||||
}
|
||||
21
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@ -0,0 +1,26 @@
|
||||
package com.key.vibekeyboard;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.lock.keyboarddemo", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
60
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name=".AppApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.KeyboardDemo"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".Activity.MainActivity"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".Activity.PermissionActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.DownloadActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.SearchActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.CategoryActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.SplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".Keyboard.KeyboardService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_INPUT_METHOD">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.view.im"
|
||||
android:resource="@xml/im" />
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
5555
app/src/main/assets/keyboard.json
Normal file
BIN
app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 430 KiB |
@ -0,0 +1,126 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.key.vibekeyboard.Adapter.CategoryViewPager2Adapter;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.ActivityCategoryBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CategoryActivity extends AppCompatActivity {
|
||||
|
||||
private final List<Category> categories = Mytool.parseJsonToList("keyboard.json");
|
||||
private ActivityCategoryBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
binding = ActivityCategoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void initData() {
|
||||
|
||||
CategoryViewPager2Adapter adapter = new CategoryViewPager2Adapter(this, categories);
|
||||
binding.categoryViewPager.setAdapter(adapter);
|
||||
|
||||
|
||||
new TabLayoutMediator(binding.categoryTab, binding.categoryViewPager, (tab, position) -> {
|
||||
|
||||
// 设置自定义视图
|
||||
View customView = LayoutInflater.from(this).inflate(R.layout.category_tab_custom, null);
|
||||
tab.setCustomView(customView);
|
||||
|
||||
// 设置标题文字
|
||||
TextView textView = customView.findViewById(R.id.category_tab_custom_title);
|
||||
Category category = categories.get(position);
|
||||
String dir = category.getClassName();
|
||||
textView.setText(dir.substring(dir.lastIndexOf("_") + 1));
|
||||
|
||||
}).attach();
|
||||
|
||||
// 添加 TabLayout 选中状态监听器
|
||||
binding.categoryTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
// 当 Tab 选中时,将文字设置为红色
|
||||
View customView = tab.getCustomView();
|
||||
if (customView != null) {
|
||||
TextView textView = customView.findViewById(R.id.category_tab_custom_title);
|
||||
textView.setTextColor(ContextCompat.getColor(getApplicationContext(), android.R.color.holo_red_dark));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
// 当 Tab 取消选中时,恢复默认颜色
|
||||
View customView = tab.getCustomView();
|
||||
if (customView != null) {
|
||||
TextView textView = customView.findViewById(R.id.category_tab_custom_title);
|
||||
textView.setTextColor(ContextCompat.getColor(getApplicationContext(), android.R.color.black));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
// 可选择性处理重复选中的情况
|
||||
}
|
||||
});
|
||||
|
||||
// 设置第一个 Tab 默认选中并改变颜色
|
||||
TabLayout.Tab firstTab = binding.categoryTab.getTabAt(0);
|
||||
if (firstTab != null) {
|
||||
firstTab.select(); // 手动选中第一个 Tab
|
||||
View customView = firstTab.getCustomView();
|
||||
if (customView != null) {
|
||||
TextView textView = customView.findViewById(R.id.category_tab_custom_title);
|
||||
textView.setTextColor(ContextCompat.getColor(getApplicationContext(), android.R.color.holo_red_dark)); // 选中时设置为红色
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
|
||||
binding.categoryBack.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
binding.categorySearch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(CategoryActivity.this, SearchActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,212 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Adapter.DownlaodRecyclerViewAdapter;
|
||||
import com.key.vibekeyboard.Dialog.PermissionRequestDialog;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.MyDatabase;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.ItemDecoration;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.Utils.StaticValue;
|
||||
import com.key.vibekeyboard.databinding.ActivityDownloadBinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DownloadActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityDownloadBinding binding;
|
||||
private String preview;
|
||||
private String url;
|
||||
private String unzipPath;
|
||||
private WallpaperInfo otherdata;
|
||||
private Boolean islike = false;
|
||||
private Boolean tempIsLike = false; // 用来暂存状态
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityDownloadBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (otherdata != null && tempIsLike != null && tempIsLike != islike) {
|
||||
otherdata.setIslike(tempIsLike);
|
||||
Mytool.runIO(() -> {
|
||||
MyDatabase.getInstance().wallpaperInfoDao().update(otherdata);
|
||||
});
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
|
||||
|
||||
private void initData() {
|
||||
Intent intent = getIntent();
|
||||
WallpaperInfo wallpaperInfo = intent.getParcelableExtra("wallpaperInfo");
|
||||
ArrayList<WallpaperInfo> list = intent.getParcelableArrayListExtra("list");
|
||||
|
||||
if (wallpaperInfo == null) {
|
||||
Toast.makeText(this, "Wallpapers info is missing!", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
preview = wallpaperInfo.getPreview();
|
||||
String name = wallpaperInfo.getTitle();
|
||||
url = wallpaperInfo.getZipUrl();
|
||||
|
||||
Log.d("DownloadActivity", "wallpaperInfo: " + wallpaperInfo);
|
||||
|
||||
DownlaodRecyclerViewAdapter adapter = new DownlaodRecyclerViewAdapter(this, wallpaperInfo, list);
|
||||
binding.downloadRecycler.setAdapter(adapter);
|
||||
binding.downloadRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
||||
binding.downloadRecycler.addItemDecoration(new ItemDecoration(16, 19, 10));
|
||||
|
||||
Mytool.runIO(() -> {
|
||||
List<WallpaperInfo> existingData = MyDatabase.getInstance().wallpaperInfoDao().checklikelist(preview);
|
||||
|
||||
if (!existingData.isEmpty()) {
|
||||
otherdata = existingData.get(0);
|
||||
islike = otherdata.getIslike();
|
||||
tempIsLike = islike; // Store the initial islike value
|
||||
|
||||
String path = StaticValue.PATH;
|
||||
|
||||
if (path.equals(otherdata.getPath())) {
|
||||
runOnUiThread(() -> {
|
||||
// Update UI if needed
|
||||
});
|
||||
}
|
||||
|
||||
runOnUiThread(() -> {
|
||||
// Update the favorite icon based on the islike value
|
||||
if (islike) {
|
||||
binding.downloadFavorite.setImageResource(android.R.drawable.btn_star_big_on);
|
||||
} else {
|
||||
binding.downloadFavorite.setImageResource(android.R.drawable.btn_star_big_off);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (wallpaperInfo.getPreview() != null) {
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(this)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(binding.downloadImage);
|
||||
} else {
|
||||
binding.downloadImage.setImageResource(R.drawable.ic_launcher_foreground);
|
||||
}
|
||||
|
||||
unzipPath = getCacheDir() + "/" + name;
|
||||
}
|
||||
|
||||
|
||||
private void initEvent() {
|
||||
|
||||
binding.downloadBack.setOnClickListener(v -> finish());
|
||||
|
||||
binding.downloadDownload.setOnClickListener(v -> downLoad());
|
||||
|
||||
binding.downloadFavorite.setOnClickListener(v -> checkLike());
|
||||
|
||||
binding.downloadAll.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
Intent intent = new Intent(DownloadActivity.this, CategoryActivity.class);
|
||||
startActivity(intent);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void downLoad() {
|
||||
ProgressBar progressBar = findViewById(R.id.progressBar);
|
||||
View view = findViewById(R.id.view);
|
||||
|
||||
// 显示进度条
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
view.setVisibility(View.VISIBLE);
|
||||
|
||||
if (!Mytool.isStep1() || !Mytool.isStep2()) {
|
||||
PermissionRequestDialog dialog = new PermissionRequestDialog();
|
||||
dialog.show(getSupportFragmentManager(), "PermissionRequestDialog");
|
||||
// 操作结束后隐藏进度条
|
||||
progressBar.setVisibility(View.GONE);
|
||||
view.setVisibility(View.GONE);
|
||||
} else {
|
||||
Mytool.donwnZip(this, url, (successful, resource) -> {
|
||||
if (successful) {
|
||||
Mytool.unZip(this, unzipPath, resource, (successful1, resDirPath) -> {
|
||||
if (successful1) {
|
||||
StaticValue.PATH = resDirPath;
|
||||
if (otherdata != null) {
|
||||
otherdata.setPath(resDirPath);
|
||||
otherdata.setDownloaded(true);
|
||||
|
||||
Mytool.runIO(() -> MyDatabase.getInstance().wallpaperInfoDao().update(otherdata));
|
||||
}
|
||||
} else {
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(DownloadActivity.this, "Decompression failure", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
// 解压完成,隐藏进度条
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
view.setVisibility(View.GONE);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 下载失败,隐藏进度条
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
view.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLike() {
|
||||
if (!tempIsLike) {
|
||||
binding.downloadFavorite.setImageResource(android.R.drawable.btn_star_big_on);
|
||||
tempIsLike = true;
|
||||
} else {
|
||||
binding.downloadFavorite.setImageResource(android.R.drawable.btn_star_big_off);
|
||||
tempIsLike = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.key.vibekeyboard.Adapter.MainViewpager2Adapter;
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
import com.key.vibekeyboard.Dialog.PermissionRequestDialog;
|
||||
import com.key.vibekeyboard.Dialog.RecommendedDialog;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.ActivityMainBinding;
|
||||
import com.key.vibekeyboard.databinding.MainTabCustomBinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
private List<WallpaperInfo> list = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// 使用 ViewBinding 绑定布局
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 创建并设置 ViewPager 适配器
|
||||
MainViewpager2Adapter adapter = new MainViewpager2Adapter(this);
|
||||
binding.mainViewpager.setAdapter(adapter);
|
||||
|
||||
// 解析 Json 文件并随机选取一个分类
|
||||
List<Category> categories = AppApplication.getCategories();
|
||||
Random random = new Random();
|
||||
int randomIndex = random.nextInt(categories.size()); // 随机选取分类索引
|
||||
list = categories.get(randomIndex).getList(); // 获取随机选中的分类中的壁纸列表
|
||||
|
||||
// 判断是否完成步骤1和步骤2,显示相应的对话框
|
||||
if (Mytool.isStep1() && Mytool.isStep2()) {
|
||||
showRecommendedDialog(); // 如果两个步骤都完成,显示推荐对话框
|
||||
} else {
|
||||
showPermissionDialog(); // 否则显示权限请求对话框
|
||||
}
|
||||
|
||||
binding.mainViewpager.setUserInputEnabled(false);//禁止页面左右滑动
|
||||
|
||||
// 初始化 TabLayout(标签栏)
|
||||
tabLayout();
|
||||
}
|
||||
|
||||
// 显示权限请求对话框
|
||||
public void showPermissionDialog() {
|
||||
PermissionRequestDialog dialog = new PermissionRequestDialog();
|
||||
dialog.show(getSupportFragmentManager(), "PermissionRequestDialog");
|
||||
}
|
||||
|
||||
// 显示推荐壁纸对话框
|
||||
public void showRecommendedDialog() {
|
||||
RecommendedDialog dialog = new RecommendedDialog();
|
||||
if (list != null) {
|
||||
dialog.setList(list); // 设置壁纸列表
|
||||
}
|
||||
dialog.show(getSupportFragmentManager(), "RecommendedDialog");
|
||||
}
|
||||
|
||||
// 初始化 TabLayout,设置标签和关联的 ViewPager
|
||||
public void tabLayout() {
|
||||
// 使用 TabLayoutMediator 连接 TabLayout 和 ViewPager2
|
||||
new TabLayoutMediator(binding.mainTablayout, binding.mainViewpager, (tab, position) -> {
|
||||
// 创建自定义 Tab 视图
|
||||
MainTabCustomBinding tabBinding = MainTabCustomBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(tabBinding.getRoot());
|
||||
|
||||
// 设置默认的图标,未选中状态的图标
|
||||
if (position == 0) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_camera); // 第一个 Tab 图标
|
||||
} else if (position == 1) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_agenda); // 第二个 Tab 图标
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_preferences); // 第三个 Tab 图标
|
||||
}
|
||||
}).attach(); // 绑定 TabLayout 和 ViewPager
|
||||
|
||||
// 设置 Tab 选中时和未选中时的图标变化
|
||||
binding.mainTablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
// 选中时更改图标
|
||||
MainTabCustomBinding tabBinding = MainTabCustomBinding.bind(Objects.requireNonNull(tab.getCustomView()));
|
||||
int position = tab.getPosition();
|
||||
if (position == 0) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_camera); // 选中状态的图标
|
||||
} else if (position == 1) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_compass); // 第二个 Tab 选中图标
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_rotate); // 第三个 Tab 选中图标
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
// 未选中时恢复默认图标
|
||||
MainTabCustomBinding tabBinding = MainTabCustomBinding.bind(Objects.requireNonNull(tab.getCustomView()));
|
||||
int position = tab.getPosition();
|
||||
if (position == 0) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_gallery); // 未选中状态的图标
|
||||
} else if (position == 1) {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_agenda); // 第二个 Tab 未选中图标
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(android.R.drawable.ic_menu_preferences); // 第三个 Tab 未选中图标
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
// 可以留空,或者添加重复选择时的逻辑
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null; // 释放 ViewBinding 的引用
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.key.vibekeyboard.R;
|
||||
|
||||
public class PermissionActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_permission);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.key.vibekeyboard.Adapter.SearchRecyclerViewAdapter;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.ItemDecoration;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.ActivitySearchBinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchActivity extends AppCompatActivity {
|
||||
|
||||
private ActivitySearchBinding binding;
|
||||
private List<Category> categories = Mytool.parseJsonToList("keyboard.json");
|
||||
private List<WallpaperInfo> filteredList = new ArrayList<>();
|
||||
private SearchRecyclerViewAdapter adapter; // 适配器类
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySearchBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 设置 RecyclerView
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
adapter = new SearchRecyclerViewAdapter(filteredList, this);
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(12, 10, 9);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
// 监听输入框内容变化
|
||||
binding.searchEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
filter(charSequence.toString()); // 调用过滤方法
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 过滤逻辑,根据输入内容过滤数据
|
||||
private void filter(String text) {
|
||||
filteredList.clear(); // 清空之前的结果
|
||||
|
||||
for (Category category : categories) {
|
||||
for (WallpaperInfo wallpaper : category.getList()) {
|
||||
if (wallpaper.getTitle().toLowerCase().contains(text.toLowerCase())) {
|
||||
filteredList.add(wallpaper); // 添加匹配的结果
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter.notifyDataSetChanged(); // 通知适配器更新数据
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null; // 释放 ViewBinding 的引用
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.key.vibekeyboard.Activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.key.vibekeyboard.databinding.ActivitySplashBinding;
|
||||
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
|
||||
private ActivitySplashBinding binding;
|
||||
private static final long TOTAL_TIME = 110;
|
||||
private CountDownTimer countDownTimer;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// 初始化 ViewBinding
|
||||
binding = ActivitySplashBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 获取进度条引用
|
||||
ProgressBar progressBar = binding.progressBar;
|
||||
|
||||
// 初始化倒计时
|
||||
countDownTimer = new CountDownTimer(TOTAL_TIME, 100) { // 每100ms更新一次
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
// 更新进度条
|
||||
int percentage = (int) ((TOTAL_TIME - millisUntilFinished) * 100 / TOTAL_TIME);
|
||||
progressBar.setProgress(percentage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
// 确保进度条更新至满值
|
||||
progressBar.setProgress(100);
|
||||
|
||||
// 跳转到主界面
|
||||
startMain();
|
||||
}
|
||||
};
|
||||
|
||||
// 开始倒计时
|
||||
countDownTimer.start();
|
||||
}
|
||||
|
||||
// 跳转到主界面的方法
|
||||
private void startMain() {
|
||||
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish(); // 结束当前 Activity
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
// 取消倒计时,防止内存泄漏
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel();
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CategoryRecyclerViewAdapter extends RecyclerView.Adapter<CategoryRecyclerViewAdapter.CategoryRecyclerViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<WallpaperInfo> list;
|
||||
|
||||
public CategoryRecyclerViewAdapter(Context context, List<WallpaperInfo> list) {
|
||||
|
||||
this.context = context;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public CategoryRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_recycler_item, parent, false);
|
||||
return new CategoryRecyclerViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull CategoryRecyclerViewHolder holder, int position) {
|
||||
|
||||
WallpaperInfo wallpaperInfo = list.get(position);
|
||||
Log.d("WallpaperInfo", "WallpaperInfo: " + wallpaperInfo);
|
||||
|
||||
if (wallpaperInfo != null) {
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(context, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo); // wallpaperInfo 已经实现了 Parcelable
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
Log.e("WallpaperInfo", "WallpaperInfo is null at position: " + position);
|
||||
}
|
||||
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(context)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public static class CategoryRecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
public CategoryRecyclerViewHolder(View view) {
|
||||
super(view);
|
||||
imageView = view.findViewById(R.id.home_recycler_image);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import com.key.vibekeyboard.Fragment.CategoryFragment;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CategoryViewPager2Adapter extends FragmentStateAdapter {
|
||||
|
||||
private final List<Category> categories;
|
||||
|
||||
public CategoryViewPager2Adapter(@NonNull FragmentActivity fragmentActivity, List<Category> categories) {
|
||||
super(fragmentActivity);
|
||||
this.categories = categories;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
|
||||
Category category = categories.get(position);
|
||||
return CategoryFragment.newInstance(category.getClassName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return categories.size();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DownlaodRecyclerViewAdapter extends RecyclerView.Adapter<DownlaodRecyclerViewAdapter.DownlaodRecyclerViewHolder> {
|
||||
|
||||
private DownloadActivity downloadActivity;
|
||||
private WallpaperInfo wallpaperInfo;
|
||||
private List<WallpaperInfo> list;
|
||||
|
||||
public DownlaodRecyclerViewAdapter(DownloadActivity downloadActivity, WallpaperInfo wallpaperInfo, List<WallpaperInfo> list) {
|
||||
this.downloadActivity = downloadActivity;
|
||||
this.wallpaperInfo = wallpaperInfo;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DownlaodRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_recycler_item, parent, false);
|
||||
return new DownlaodRecyclerViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull DownlaodRecyclerViewHolder holder, int position) {
|
||||
|
||||
WallpaperInfo wallpaperInfo1 = list.get(position);
|
||||
|
||||
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(downloadActivity, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo1); // wallpaperInfo 已经实现了 Parcelable
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
downloadActivity.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(downloadActivity)
|
||||
.load(list.get(position).getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public static class DownlaodRecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
|
||||
public DownlaodRecyclerViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.home_recycler_image);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoriteRecyclerViewAdapter extends RecyclerView.Adapter<FavoriteRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
|
||||
private Context context;
|
||||
private List<WallpaperInfo> list;
|
||||
|
||||
public FavoriteRecyclerViewAdapter(Context context, List<WallpaperInfo> list) {
|
||||
|
||||
this.context = context;
|
||||
this.list = new ArrayList<>(list);
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_recycler_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
|
||||
WallpaperInfo wallpaperInfo = list.get(position);
|
||||
|
||||
if (wallpaperInfo != null) {
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(context, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo); // wallpaperInfo 已经实现了 Parcelable
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
if (wallpaperInfo != null) {
|
||||
Glide.with(context)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return (list != null) ? list.size() : 0;
|
||||
}
|
||||
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
imageView = itemView.findViewById(R.id.home_recycler_image);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 DiffUtil 更新列表
|
||||
public void updateList(List<WallpaperInfo> newList) {
|
||||
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
|
||||
@Override
|
||||
public int getOldListSize() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewListSize() {
|
||||
return newList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
// 通过唯一标识符比较两个项目是否相同
|
||||
return list.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
// 比较内容是否相同
|
||||
return list.get(oldItemPosition).equals(newList.get(newItemPosition));
|
||||
}
|
||||
});
|
||||
|
||||
list.clear();
|
||||
list.addAll(newList);
|
||||
diffResult.dispatchUpdatesTo(this); // 通知 RecyclerView 进行局部更新
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeRecyclerViewAdapter extends RecyclerView.Adapter<HomeRecyclerViewAdapter.HomeRecyclerViewHolder> {
|
||||
|
||||
private List<Category> categories;
|
||||
private Context context;
|
||||
|
||||
public HomeRecyclerViewAdapter(Context context,List<Category> categories) {
|
||||
this.context = context;
|
||||
this.categories = categories;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HomeRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_recycler_item, parent, false);
|
||||
return new HomeRecyclerViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull HomeRecyclerViewHolder holder, int position) {
|
||||
|
||||
Category category = categories.get(position);
|
||||
List<WallpaperInfo> list = category.getList();
|
||||
WallpaperInfo categoryWallpaperInfo = category.getList().get(position);
|
||||
WallpaperInfo wallpaperInfo = category.getList().get(0);
|
||||
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(context, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo); // wallpaperInfo 已经实现了 Parcelable
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(context)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return categories.size();
|
||||
}
|
||||
|
||||
public static class HomeRecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
private ImageView imageView;
|
||||
|
||||
public HomeRecyclerViewHolder(View view) {
|
||||
super(view);
|
||||
imageView = view.findViewById(R.id.home_recycler_image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeViewPager2Adapter extends RecyclerView.Adapter<HomeViewPager2Adapter.HomeViewPager2ViewHolder> {
|
||||
|
||||
private List<Category> categories;
|
||||
private Context context;
|
||||
|
||||
public HomeViewPager2Adapter(Context context, List<Category> categories) {
|
||||
this.context = context;
|
||||
this.categories = categories;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HomeViewPager2ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_viewpager2_item, parent, false);
|
||||
return new HomeViewPager2ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull HomeViewPager2ViewHolder holder, int position) {
|
||||
|
||||
int actualPosition = position % categories.size(); // 确保最后一张的视图是第一张
|
||||
Category category = categories.get(actualPosition);
|
||||
List<WallpaperInfo> list = category.getList();
|
||||
WallpaperInfo categoryWallpaperInfo = category.getList().get(position);
|
||||
WallpaperInfo wallpaperInfo = category.getList().get(0); // 假设只使用列表的第一个壁纸
|
||||
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(context, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo);
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(context)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return categories.size()+1;
|
||||
}
|
||||
|
||||
public static class HomeViewPager2ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ImageView imageView;
|
||||
|
||||
public HomeViewPager2ViewHolder(View view) {
|
||||
super(view);
|
||||
imageView = view.findViewById(R.id.home_viewpager_image);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import com.key.vibekeyboard.Fragment.FavoriteFragment;
|
||||
import com.key.vibekeyboard.Fragment.HomeFragment;
|
||||
import com.key.vibekeyboard.Fragment.SettingFragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MainViewpager2Adapter extends FragmentStateAdapter {
|
||||
|
||||
private final List<Fragment> fragmentList;
|
||||
|
||||
public MainViewpager2Adapter(@NonNull FragmentActivity fragmentActivity) {
|
||||
super(fragmentActivity);
|
||||
|
||||
fragmentList = new ArrayList<>();
|
||||
fragmentList.add(new HomeFragment());
|
||||
fragmentList.add(new FavoriteFragment());
|
||||
fragmentList.add(new SettingFragment());
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
return fragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return fragmentList.size();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package com.key.vibekeyboard.Adapter;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.Activity.SearchActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchRecyclerViewAdapter extends RecyclerView.Adapter<SearchRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
private List<WallpaperInfo> wallpaperList;
|
||||
private SearchActivity context;
|
||||
|
||||
public SearchRecyclerViewAdapter(List<WallpaperInfo> wallpaperList, SearchActivity context) {
|
||||
this.wallpaperList = wallpaperList;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_recycler_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
WallpaperInfo wallpaperInfo = wallpaperList.get(position);
|
||||
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(context, DownloadActivity.class);
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo); // wallpaperInfo 已经实现了 Parcelable
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(wallpaperList)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
// 应用圆角变换
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_background)
|
||||
.error(R.drawable.ic_launcher_background)
|
||||
.transform(new CenterCrop())
|
||||
.transform(new RoundedCorners(16)); // 设置圆角度数
|
||||
|
||||
Glide.with(context)
|
||||
.load(wallpaperInfo.getPreview())
|
||||
.apply(options)
|
||||
.into(holder.imageView);
|
||||
// 根据需要加载其他字段,如图片等
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return wallpaperList.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.home_recycler_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
app/src/main/java/com/key/vibekeyboard/AppApplication.java
Normal file
@ -0,0 +1,68 @@
|
||||
package com.key.vibekeyboard;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.MyDatabase;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class AppApplication extends Application {
|
||||
|
||||
public static AppApplication instance;
|
||||
public static List<Category> categories;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
instance = this;
|
||||
categories = Mytool.parseJsonToList("keyboard.json");
|
||||
|
||||
Mytool.runIO(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
MyDatabase.getInstance().wallpaperInfoDao().insertAll(getAlldataList());
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static AppApplication getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return instance.getApplicationContext();
|
||||
}
|
||||
|
||||
public static List<Category> getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static List<WallpaperInfo> getAlldataList() {
|
||||
List<WallpaperInfo> otherdata = new ArrayList<>();
|
||||
List<Category> mydataList = getCategories();
|
||||
Set<String> set = new HashSet<>();
|
||||
for (Category mydata : mydataList) {
|
||||
List<WallpaperInfo> otherdataList = mydata.getList();
|
||||
for (WallpaperInfo otherdata1 : otherdataList) {
|
||||
String title = otherdata1.getTitle();
|
||||
if (!set.contains(title)) {
|
||||
otherdata.add(otherdata1);
|
||||
set.add(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return otherdata;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
package com.key.vibekeyboard.Dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.DialogPermissionBinding;
|
||||
|
||||
public class PermissionRequestDialog extends DialogFragment {
|
||||
|
||||
private DialogPermissionBinding binding;
|
||||
private InputMethodManager methodManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
binding = DialogPermissionBinding.inflate(inflater, container, false);
|
||||
init();
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Dialog dialog = getDialog();
|
||||
setCancelable(true); // 设置为false对话框不可点击外面取消
|
||||
if (dialog != null && dialog.getWindow() != null) {
|
||||
Window window = dialog.getWindow();
|
||||
// 设置宽度为屏幕的 90%,高度自适应内容
|
||||
window.setLayout((int) (getResources().getDisplayMetrics().widthPixels * 0.9), WindowManager.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
// 每次对话框显示时调用 update()
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
methodManager = (InputMethodManager) AppApplication.instance.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
binding.firstIconTextLayout.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
binding.secondIconTextLayout.setOnClickListener(v -> {
|
||||
methodManager.showInputMethodPicker();
|
||||
});
|
||||
|
||||
binding.imageView.setOnClickListener(v -> {
|
||||
dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (Mytool.isStep1()) {
|
||||
binding.firstIconTextLayout.setSelected(Mytool.isStep1());
|
||||
binding.firstIconTextLayout.setClickable(false);
|
||||
}
|
||||
if (Mytool.isStep2()) {
|
||||
binding.secondIconTextLayout.setSelected(Mytool.isStep2());
|
||||
binding.secondIconTextLayout.setClickable(false);
|
||||
}
|
||||
|
||||
if (Mytool.isStep1() && Mytool.isStep2()) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
package com.key.vibekeyboard.Dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.key.vibekeyboard.Activity.DownloadActivity;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.databinding.DialogRecommendedBinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class RecommendedDialog extends DialogFragment {
|
||||
|
||||
private DialogRecommendedBinding binding; // 绑定布局文件
|
||||
private List<WallpaperInfo> list = new ArrayList<>(); // 存储壁纸信息的列表
|
||||
private WallpaperInfo wallpaperInfo; // 当前选择的壁纸信息
|
||||
|
||||
// 设置壁纸列表
|
||||
public void setList(List<WallpaperInfo> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// 将布局文件与视图绑定
|
||||
binding = DialogRecommendedBinding.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// 初始化对话框设置
|
||||
Dialog dialog = getDialog();
|
||||
setCancelable(true); // 设置为 true 对话框可点击外面取消
|
||||
if (dialog != null && dialog.getWindow() != null) {
|
||||
Window window = dialog.getWindow();
|
||||
window.setLayout((int) (getResources().getDisplayMetrics().widthPixels * 0.9), WindowManager.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
// 随机选择一个壁纸
|
||||
Random random = new Random();
|
||||
int randomIndex = random.nextInt(list.size());
|
||||
wallpaperInfo = list.get(randomIndex); // 获取随机的壁纸信息
|
||||
|
||||
// 加载图像
|
||||
loadImage();
|
||||
|
||||
// 点击图片后进入下载界面
|
||||
binding.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(requireContext(), DownloadActivity.class);
|
||||
// 将选中的壁纸信息传递给下一个 Activity
|
||||
intent.putExtra("wallpaperInfo", wallpaperInfo); // wallpaperInfo 已经实现了 Parcelable
|
||||
// 将壁纸列表传递给下一个 Activity
|
||||
intent.putParcelableArrayListExtra("list", new ArrayList<>(list)); // list 中的 WallpaperInfo 对象实现了 Parcelable
|
||||
dismiss(); // 关闭当前对话框
|
||||
requireContext().startActivity(intent); // 启动下载界面
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 加载图像的方法
|
||||
private void loadImage() {
|
||||
// 判断壁纸的预览图 URL 是否有效
|
||||
if (wallpaperInfo.getPreview() != null && !wallpaperInfo.getPreview().isEmpty()) {
|
||||
// 设置图像的加载选项
|
||||
RequestOptions options = new RequestOptions()
|
||||
.placeholder(R.drawable.ic_launcher_foreground) // 图片加载中的占位图
|
||||
.error(R.drawable.ic_launcher_foreground) // 图片加载失败时的备用图
|
||||
.transform(new CenterCrop()) // 中心裁剪,保证图片填满控件
|
||||
.transform(new RoundedCorners(16)); // 设置圆角,16px
|
||||
|
||||
// 使用 Glide 加载图像
|
||||
Glide.with(requireContext())
|
||||
.asDrawable() // 指定加载为 Drawable
|
||||
.load(wallpaperInfo.getPreview()) // 设置要加载的图片 URL
|
||||
.apply(options) // 应用上面定义的加载选项
|
||||
.into(binding.imageView); // 设置到 ImageView 上显示
|
||||
} else {
|
||||
// 如果预览图 URL 为空,显示默认图像
|
||||
binding.imageView.setImageResource(R.drawable.ic_launcher_background); // 默认图像
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.key.vibekeyboard.Fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.key.vibekeyboard.Adapter.CategoryRecyclerViewAdapter;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.ItemDecoration;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.FragmentCategoryBinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CategoryFragment extends Fragment {
|
||||
|
||||
private static final String ARG_CATEGORY = "category";
|
||||
private FragmentCategoryBinding binding;
|
||||
private String category; // 用于存储从外部传入的类别名称。
|
||||
private final List<Category> categories = Mytool.parseJsonToList("keyboard.json");
|
||||
|
||||
public CategoryFragment() {
|
||||
|
||||
}
|
||||
|
||||
// 工厂方法,用于创建 Fragment 的实例,并通过 Bundle 传递类别参数。
|
||||
public static CategoryFragment newInstance(String category) {
|
||||
CategoryFragment fragment = new CategoryFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_CATEGORY, category); // 将类别参数存储到 Bundle 中。
|
||||
fragment.setArguments(args); // 将 Bundle 设置为 Fragment 的参数。
|
||||
return fragment;
|
||||
}
|
||||
// 当 Fragment 创建时调用,用于初始化一些变量。
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// 如果 Fragment 有传入的参数,则获取并存储类别名称。
|
||||
if (getArguments() != null) {
|
||||
category = getArguments().getString(ARG_CATEGORY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentCategoryBinding.inflate(inflater, container, false);
|
||||
|
||||
List<WallpaperInfo> list = getListByClassName(category);
|
||||
|
||||
CategoryRecyclerViewAdapter adapter = new CategoryRecyclerViewAdapter(requireContext(),list);
|
||||
binding.categoryRecycler.setAdapter(adapter);
|
||||
binding.categoryRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(12, 10, 9);
|
||||
binding.categoryRecycler.addItemDecoration(itemDecoration);
|
||||
return binding.getRoot();
|
||||
|
||||
}
|
||||
|
||||
public List<WallpaperInfo> getListByClassName(String className) {
|
||||
for (Category category : categories) {
|
||||
if (category.getClassName().equals(className)) {
|
||||
return category.getList();
|
||||
}
|
||||
}
|
||||
// 如果没有找到,返回一个空列表
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null; // 释放 ViewBinding 的引用
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.key.vibekeyboard.Fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.key.vibekeyboard.Adapter.FavoriteRecyclerViewAdapter;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.Utils.ItemDecoration;
|
||||
import com.key.vibekeyboard.ViewModel.FavoriteViewModel;
|
||||
import com.key.vibekeyboard.databinding.FragmentFavoriteBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FavoriteFragment extends Fragment {
|
||||
|
||||
private FragmentFavoriteBinding binding;
|
||||
private FavoriteRecyclerViewAdapter adapter;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
binding = FragmentFavoriteBinding.inflate(inflater, container, false);
|
||||
|
||||
// 初始化 RecyclerView 和 LayoutManager
|
||||
binding.favoriteRecyclerview.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
binding.favoriteRecyclerview.addItemDecoration(new ItemDecoration(16, 19, 10));
|
||||
|
||||
// 获取 ViewModel 实例
|
||||
FavoriteViewModel favoriteViewModel = new ViewModelProvider(this).get(FavoriteViewModel.class);
|
||||
|
||||
// 监听 LiveData 的变化并更新 RecyclerView
|
||||
favoriteViewModel.getFavoriteList().observe(getViewLifecycleOwner(), new Observer<List<WallpaperInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<WallpaperInfo> wallpaperInfoList) {
|
||||
// 更新 RecyclerView 的 Adapter
|
||||
if (adapter == null) {
|
||||
adapter = new FavoriteRecyclerViewAdapter(requireContext(), wallpaperInfoList);
|
||||
binding.favoriteRecyclerview.setAdapter(adapter);
|
||||
} else {
|
||||
// 更新现有 Adapter 数据
|
||||
adapter.updateList(wallpaperInfoList);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,127 @@
|
||||
package com.key.vibekeyboard.Fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.key.vibekeyboard.Activity.CategoryActivity;
|
||||
import com.key.vibekeyboard.Activity.SearchActivity;
|
||||
import com.key.vibekeyboard.Adapter.HomeRecyclerViewAdapter;
|
||||
import com.key.vibekeyboard.Adapter.HomeViewPager2Adapter;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Utils.ItemDecoration;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.databinding.FragmentHomeBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
|
||||
private FragmentHomeBinding binding;
|
||||
private HomeViewPager2Adapter homeViewPager2Adapter;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
binding = FragmentHomeBinding.inflate(inflater, container, false);
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
|
||||
return binding.getRoot();
|
||||
|
||||
}
|
||||
|
||||
public void initData() {
|
||||
// 解析Json
|
||||
List<Category> categories = Mytool.parseJsonToList("keyboard.json");
|
||||
Log.d("dsd", "size" + categories.size());
|
||||
|
||||
// 设置ViewPager2
|
||||
homeViewPager2Adapter = new HomeViewPager2Adapter(requireContext(), categories);
|
||||
binding.homeViewPager.setAdapter(homeViewPager2Adapter);
|
||||
|
||||
// 设置RecyclerView
|
||||
binding.homeRecycler.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
HomeRecyclerViewAdapter homeRecyclerViewAdapter = new HomeRecyclerViewAdapter(requireContext(), categories);
|
||||
binding.homeRecycler.setAdapter(homeRecyclerViewAdapter);
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
binding.homeRecycler.addItemDecoration(itemDecoration);
|
||||
|
||||
}
|
||||
|
||||
public void initEvent() {
|
||||
|
||||
binding.homeAll.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(getContext(), CategoryActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
binding.homeViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (position == homeViewPager2Adapter.getItemCount() - 1) {
|
||||
// 如果用户手动滑到了最后的虚拟页面,切换回第一张
|
||||
binding.homeViewPager.postDelayed(() -> binding.homeViewPager.setCurrentItem(0, false), 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
binding.homeSearch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(getContext(), SearchActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// 设置自动轮播功能
|
||||
autoSlideImages();
|
||||
}
|
||||
|
||||
// 自动轮播图片
|
||||
private void autoSlideImages() {
|
||||
final int delay = 3000; // 延迟 3 秒
|
||||
binding.homeViewPager.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int currentItem = binding.homeViewPager.getCurrentItem();
|
||||
int nextItem = currentItem + 1;
|
||||
|
||||
if (nextItem >= homeViewPager2Adapter.getItemCount()) {
|
||||
// 如果到达了最后的虚拟页面,瞬间跳回第一张,禁用动画
|
||||
binding.homeViewPager.setCurrentItem(0, false);
|
||||
} else {
|
||||
// 正常切换到下一张,有动画效果
|
||||
binding.homeViewPager.setCurrentItem(nextItem, true);
|
||||
}
|
||||
|
||||
// 继续下一次轮播
|
||||
binding.homeViewPager.postDelayed(this, delay);
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.key.vibekeyboard.Fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Utils.SettingUtil;
|
||||
import com.key.vibekeyboard.databinding.FragmentSettingBinding;
|
||||
|
||||
public class SettingFragment extends Fragment {
|
||||
|
||||
private FragmentSettingBinding binding;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
binding = FragmentSettingBinding.inflate(inflater, container, false);
|
||||
|
||||
binding.version.setText(SettingUtil.getCurrentVersion(requireContext()));
|
||||
|
||||
binding.share.setOnClickListener(v -> {
|
||||
SettingUtil.shareApp(requireContext());
|
||||
});
|
||||
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,179 @@
|
||||
package com.key.vibekeyboard.Keyboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Xml;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
import com.key.vibekeyboard.Utils.StaticValue;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CustomViewConfig {
|
||||
private String Bg_action_normal = "btn_keyboard_key_functional_normal.9.png";
|
||||
private String jpg_BG = "keyboard_background.jpg";
|
||||
private String color_normal_key = "key_text_color_normal";
|
||||
private String color_action_key = "key_text_color_functional";
|
||||
private String Bg_pressed = "btn_keyboard_key_normal_pressed.9.png";
|
||||
private String Bg_normal = "btn_keyboard_key_normal_normal.9.png";
|
||||
private String path_drawxh = "/drawable-xhdpi-v4/";
|
||||
private String path_drawxxh = "/drawable-xxhdpi-v4/";
|
||||
private String path_color = "/colors.xml";
|
||||
private String icon_del = "sym_keyboard_delete_normal.png";
|
||||
private String icon_shift = "sym_keyboard_shift.png";
|
||||
private String Bg_action_pressed = "btn_keyboard_key_functional_pressed.9.png";
|
||||
private String icon_shift_lock = "sym_keyboard_shift_locked.png";
|
||||
|
||||
private String Bg_space_normal = "btn_keyboard_spacekey_normal_normal.9.png";
|
||||
private String Bg_space_pressed = "btn_keyboard_spacekey_normal_pressed.9.png";
|
||||
|
||||
private Drawable BgActionDraw;
|
||||
private Drawable BgSpaceDraw;
|
||||
private Drawable BgNormalDraw;
|
||||
|
||||
private Drawable iconShift = ContextCompat.getDrawable(AppApplication.instance, android.R.drawable.stat_sys_upload);
|
||||
private Drawable iconDel = ContextCompat.getDrawable(AppApplication.instance, android.R.drawable.ic_input_delete);
|
||||
private Drawable BG = ContextCompat.getDrawable(AppApplication.instance, R.color.black);
|
||||
|
||||
private int keyNoramlcolor = AppApplication.instance.getResources().getColor(R.color.white, null);
|
||||
|
||||
private int keyActioncolor = AppApplication.instance.getResources().getColor(R.color.white, null);
|
||||
|
||||
private Drawable iconShiftLock = ContextCompat.getDrawable(AppApplication.instance, android.R.drawable.stat_sys_upload);
|
||||
|
||||
|
||||
public Drawable getBG() {
|
||||
return BG;
|
||||
}
|
||||
|
||||
public Drawable getBgActionDraw() {
|
||||
return BgActionDraw;
|
||||
}
|
||||
|
||||
public Drawable getBgNormalDraw() {
|
||||
return BgNormalDraw;
|
||||
}
|
||||
|
||||
public Drawable getBgSpaceDraw() {
|
||||
return BgSpaceDraw;
|
||||
}
|
||||
|
||||
public Drawable getIconDel() {
|
||||
return iconDel;
|
||||
}
|
||||
|
||||
public Drawable getIconShift() {
|
||||
return iconShift;
|
||||
}
|
||||
|
||||
public Drawable getIconShiftLock() {
|
||||
return iconShiftLock;
|
||||
}
|
||||
|
||||
public int getKeyNoramlcolor() {
|
||||
return keyNoramlcolor;
|
||||
}
|
||||
|
||||
|
||||
public int getKeyActioncolor() {
|
||||
return keyActioncolor;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
// iconShift = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.drawable.ico_shift_lit);
|
||||
// iconDel = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.drawable.icon_del);
|
||||
// BG = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.color.white);
|
||||
// keyNoramlcolor = CoolKeyboardSkin.app.getResources().getColor(R.color.white, null);
|
||||
// iconShiftLock = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.drawable.ico_shift_lit);
|
||||
// Drawable drawable1 = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.drawable.de_keybg_press);
|
||||
// Drawable drawable = ContextCompat.getDrawable(CoolKeyboardSkin.app, R.drawable.de_keybg);
|
||||
// StateListDrawable status = Mytool.getStatus(drawable, drawable1);
|
||||
// BgActionDraw = status;
|
||||
// BgNormalDraw = status;
|
||||
// BgSpaceDraw = status;
|
||||
}
|
||||
|
||||
private Drawable getKeyBackGround(Context context, String resDirPath, String drawName) {
|
||||
String filePath = resDirPath + path_drawxh + drawName;
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), BitmapFactory.decodeFile(filePath));
|
||||
return bitmapDrawable;
|
||||
}
|
||||
|
||||
private Drawable getBackGround(Context context, String resDirPath) {
|
||||
String filePath = resDirPath + path_drawxxh + jpg_BG;
|
||||
if (!new File(filePath).exists()) {
|
||||
return null;
|
||||
}
|
||||
BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), BitmapFactory.decodeFile(filePath));
|
||||
return bitmapDrawable;
|
||||
}
|
||||
|
||||
private void updateKeyColor(String resDirPath) {
|
||||
|
||||
String colorXmlPath = resDirPath + path_color;
|
||||
File file = new File(colorXmlPath);
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
XmlPullParser xmlPullParser = Xml.newPullParser();
|
||||
|
||||
String s = Mytool.fileToString(file);
|
||||
xmlPullParser.setInput(new StringReader(s));
|
||||
int eventT = xmlPullParser.getEventType();
|
||||
while (eventT != XmlPullParser.END_DOCUMENT) {
|
||||
if (eventT == XmlPullParser.START_TAG && (Objects.equals(xmlPullParser.getName(), "color") || Objects.equals(xmlPullParser.getName(), "item"))) {
|
||||
String value = xmlPullParser.getAttributeValue(null, "name");
|
||||
if (value.equals(color_normal_key)) {
|
||||
keyNoramlcolor = Color.parseColor(xmlPullParser.nextText());
|
||||
|
||||
}
|
||||
if (value.equals(color_action_key)) {
|
||||
keyActioncolor = Color.parseColor(xmlPullParser.nextText());
|
||||
|
||||
}
|
||||
}
|
||||
eventT = xmlPullParser.next();
|
||||
}
|
||||
} catch (XmlPullParserException exception) {
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void updateConfig(Context con) {
|
||||
String resDirPath = StaticValue.PATH;
|
||||
if (!resDirPath.isEmpty()) {
|
||||
updateKeyColor(resDirPath);
|
||||
BG = getBackGround(con, resDirPath);
|
||||
BgNormalDraw = getKeyBackGround(con, resDirPath, Bg_normal);
|
||||
BgActionDraw = getKeyBackGround(con, resDirPath, Bg_action_normal);
|
||||
BgSpaceDraw = getKeyBackGround(con, resDirPath, Bg_space_normal);
|
||||
iconDel = getKeyBackGround(con, resDirPath, icon_del);
|
||||
iconShift = getKeyBackGround(con, resDirPath, icon_shift);
|
||||
iconShiftLock = getKeyBackGround(con, resDirPath, icon_shift_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.key.vibekeyboard.Keyboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.inputmethodservice.KeyboardView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.key.vibekeyboard.R;
|
||||
|
||||
|
||||
public class KeyboardService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
|
||||
private int[] ViewXmls = new int[4]; // 保存不同键盘视图的XML资源ID
|
||||
private MyKeyboard myKeyboard; // 自定义键盘视图的实例
|
||||
|
||||
private int curImeAction; // 当前输入法的动作类型
|
||||
|
||||
public KeyboardService() {
|
||||
// 默认构造函数
|
||||
}
|
||||
|
||||
// 创建输入视图的方法,返回键盘视图
|
||||
@Override
|
||||
public View onCreateInputView() {
|
||||
// 初始化不同键盘视图的XML布局文件
|
||||
ViewXmls[0] = R.xml.view_1;
|
||||
ViewXmls[1] = R.xml.view_2;
|
||||
ViewXmls[2] = R.xml.view_3;
|
||||
ViewXmls[3] = R.xml.view_4;
|
||||
|
||||
// 加载主键盘视图布局文件
|
||||
View inputView = LayoutInflater.from(this).inflate(R.layout.keyboard_view, null, false);
|
||||
myKeyboard = inputView.findViewById(R.id.keyboardView); // 绑定键盘视图
|
||||
myKeyboard.setKeyboard(new MyKeyboard.KeyBoard(this, ViewXmls[0])); // 设置默认键盘布局
|
||||
myKeyboard.setOnKeyboardActionListener(this); // 设置键盘操作监听器
|
||||
// myKeyboard.setPreviewEnabled(false); // 可选项,禁用按键预览
|
||||
return inputView;
|
||||
}
|
||||
|
||||
// 当输入法窗口显示时调用
|
||||
@Override
|
||||
public void onWindowShown() {
|
||||
super.onWindowShown();
|
||||
curImeAction = getImeAction(getCurrentInputEditorInfo().imeOptions); // 获取当前的输入法动作类型
|
||||
myKeyboard.updateConfigView(this, curImeAction); // 更新键盘配置视图
|
||||
myKeyboard.invalidate(); // 刷新键盘视图
|
||||
}
|
||||
|
||||
// 获取当前输入法的动作类型
|
||||
public int getImeAction(int imeOptions) {
|
||||
int i = imeOptions & EditorInfo.IME_MASK_ACTION;
|
||||
return i;
|
||||
}
|
||||
|
||||
// 键被按下时调用
|
||||
@Override
|
||||
public void onPress(int primaryCode) {
|
||||
|
||||
}
|
||||
|
||||
// 键被释放时调用
|
||||
@Override
|
||||
public void onRelease(int primaryCode) {
|
||||
|
||||
}
|
||||
|
||||
// 键盘按键被按下时调用
|
||||
@Override
|
||||
public void onKey(int primaryCode, int[] keyCodes) {
|
||||
switch (primaryCode) {
|
||||
case MyKeyboard.KeyBoard.KEYCODE_SHIFT:
|
||||
// 切换到大写字母布局或恢复到小写字母布局
|
||||
if (myKeyboard.getShiftType() == 0) {
|
||||
changeView(3);
|
||||
myKeyboard.setShiftType(1);
|
||||
} else {
|
||||
changeView(0);
|
||||
myKeyboard.setShiftType(0);
|
||||
}
|
||||
break;
|
||||
case MyKeyboard.KeyBoard.KEYCODE_MODE_CHANGE:
|
||||
// 切换到符号键盘或字母键盘
|
||||
if (myKeyboard.getViewType() == 0) {
|
||||
changeView(1);
|
||||
} else {
|
||||
changeView(0);
|
||||
}
|
||||
break;
|
||||
case MyKeyboard.KeyBoard.KEYCODE_SHIFT_123:
|
||||
// 切换到符号键盘
|
||||
changeView(1);
|
||||
break;
|
||||
case MyKeyboard.KeyBoard.KEYCODE_SHIFT_MORE:
|
||||
// 切换到更多符号键盘
|
||||
changeView(2);
|
||||
break;
|
||||
case MyKeyboard.KeyBoard.KEYCODE_DELETE:
|
||||
// 删除前一个字符
|
||||
getCurrentInputConnection().deleteSurroundingText(1, 0);
|
||||
break;
|
||||
case MyKeyboard.KeyBoard.KEYCODE_DONE:
|
||||
// 完成输入并隐藏键盘
|
||||
getCurrentInputConnection().performEditorAction(curImeAction);
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(myKeyboard.getWindowToken(), 0);
|
||||
break;
|
||||
default:
|
||||
// 处理普通字符输入
|
||||
char value;
|
||||
if (myKeyboard.getShiftType() == 1) {
|
||||
value = Character.toUpperCase((char) primaryCode); // 大写字母
|
||||
} else {
|
||||
value = (char) primaryCode; // 小写字母
|
||||
}
|
||||
getCurrentInputConnection().commitText(String.valueOf(value), 1); // 提交字符到输入连接
|
||||
}
|
||||
}
|
||||
|
||||
// 更换键盘视图的方法
|
||||
private void changeView(int i) {
|
||||
myKeyboard.setViewType(i); // 设置键盘视图类型
|
||||
myKeyboard.setShiftType(i); // 设置键盘大小写类型
|
||||
myKeyboard.setKeyboard(new MyKeyboard.KeyBoard(this, ViewXmls[i])); // 设置新的键盘布局
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onText(CharSequence text) {
|
||||
// 文本输入时调用(未实现)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeLeft() {
|
||||
// 左滑时调用(未实现)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeRight() {
|
||||
// 右滑时调用(未实现)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeDown() {
|
||||
// 下滑时调用(未实现)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeUp() {
|
||||
// 上滑时调用(未实现)
|
||||
}
|
||||
}
|
||||
219
app/src/main/java/com/key/vibekeyboard/Keyboard/MyKeyboard.java
Normal file
@ -0,0 +1,219 @@
|
||||
package com.key.vibekeyboard.Keyboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.inputmethodservice.Keyboard;
|
||||
import android.inputmethodservice.KeyboardView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
|
||||
|
||||
import com.key.vibekeyboard.Utils.Mytool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MyKeyboard extends KeyboardView {
|
||||
// 自定义键盘视图类,继承自 KeyboardView,用于自定义键盘布局及其行为。
|
||||
|
||||
private Paint mPaint;
|
||||
// 用于绘制键盘的 Paint 对象。
|
||||
|
||||
private int viewType = 0;
|
||||
// 键盘视图的类型,用于区分不同的键盘视图模式。
|
||||
|
||||
private int shiftType = 0;
|
||||
// 当前 Shift 键的状态,0 表示未按下,其他值可能表示按下或锁定状态。
|
||||
|
||||
private CustomViewConfig config;
|
||||
// 键盘的自定义配置对象,包含键盘背景、键的颜色和图标等。
|
||||
|
||||
private int curImeAction;
|
||||
// 当前输入法的动作类型(如搜索、完成等)。
|
||||
|
||||
public MyKeyboard(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
// 初始化视图,配置画笔和其他参数。
|
||||
}
|
||||
|
||||
public static class KeyBoard extends Keyboard {
|
||||
// 自定义键盘类,继承自 Keyboard,用于定义键盘的布局和键值。
|
||||
|
||||
public static final int KEYCODE_SHIFT_MORE = -360;
|
||||
public static final int KEYCODE_SHIFT_123 = -361;
|
||||
// 自定义的键值常量,分别用于切换到更多符号和切换到 123 键盘。
|
||||
|
||||
public KeyBoard(Context context, int layoutTemplateResId) {
|
||||
super(context, layoutTemplateResId);
|
||||
// 使用布局模板资源 ID 初始化键盘对象。
|
||||
}
|
||||
}
|
||||
|
||||
public int getShiftType() {
|
||||
return shiftType;
|
||||
// 返回当前 Shift 键的状态。
|
||||
}
|
||||
|
||||
public void setShiftType(int shiftType) {
|
||||
this.shiftType = shiftType;
|
||||
// 设置 Shift 键的状态。
|
||||
}
|
||||
|
||||
public void setViewType(int viewType) {
|
||||
this.viewType = viewType;
|
||||
// 设置键盘视图的类型。
|
||||
}
|
||||
|
||||
public int getViewType() {
|
||||
return viewType;
|
||||
// 返回当前键盘视图的类型。
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
// 重写 onDraw 方法,自定义绘制键盘的方式。
|
||||
|
||||
KeyBoard keyboard = (KeyBoard) getKeyboard();
|
||||
// 获取当前键盘对象。
|
||||
|
||||
List<Keyboard.Key> keys = keyboard.getKeys();
|
||||
// 获取键盘中的所有键。
|
||||
|
||||
for (int r = 0; r < keys.size(); r++) {
|
||||
Keyboard.Key key = keys.get(r);
|
||||
// 遍历每个键对象。
|
||||
|
||||
int code = key.codes[0];
|
||||
// 获取键的第一个键值代码。
|
||||
|
||||
mPaint.setColor(config.getKeyActioncolor());
|
||||
// 设置画笔的颜色为操作键的颜色。
|
||||
|
||||
if (code == KeyBoard.KEYCODE_MODE_CHANGE) {
|
||||
// 如果键是模式切换键,绘制其背景和标签(无文字)。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
onDrawLabel(key, canvas, "");
|
||||
|
||||
} else if (code == KeyBoard.KEYCODE_SHIFT) {
|
||||
// 如果键是 Shift 键,绘制其背景和图标。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
Mytool.onDrawKeyIcon(key, getShiftDraw(), canvas, this);
|
||||
|
||||
} else if (code == KeyBoard.KEYCODE_SHIFT_123) {
|
||||
// 如果键是切换到 123 键盘的键,绘制其背景和标签(无文字)。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
onDrawLabel(key, canvas, "");
|
||||
|
||||
} else if (code == KeyBoard.KEYCODE_SHIFT_MORE) {
|
||||
// 如果键是切换到更多符号的键,绘制其背景和标签(无文字)。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
onDrawLabel(key, canvas, "");
|
||||
|
||||
} else if (code == KeyBoard.KEYCODE_DONE) {
|
||||
// 如果键是完成键,根据当前输入法的动作类型绘制其背景和标签。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
if (curImeAction == EditorInfo.IME_ACTION_SEARCH) {
|
||||
onDrawLabel(key, canvas, "Search");
|
||||
} else {
|
||||
onDrawLabel(key, canvas, "");
|
||||
}
|
||||
|
||||
} else if (code == KeyBoard.KEYCODE_DELETE) {
|
||||
// 如果键是删除键,绘制其背景、图标和标签(无文字)。
|
||||
|
||||
onDrawKeyBackground(key, config.getBgActionDraw(), canvas);
|
||||
Mytool.onDrawKeyIcon(key, config.getIconDel(), canvas, this);
|
||||
onDrawLabel(key, canvas, "");
|
||||
|
||||
} else {
|
||||
// 其他普通键,设置画笔颜色为普通键颜色,绘制其背景和标签。
|
||||
|
||||
mPaint.setColor(config.getKeyNoramlcolor());
|
||||
onDrawKeyBackground(key, config.getBgNormalDraw(), canvas);
|
||||
onDrawLabel(key, canvas, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getShiftDraw() {
|
||||
// 根据 Shift 键的状态返回相应的图标。
|
||||
|
||||
if (shiftType == 0) {
|
||||
return config.getIconShift();
|
||||
} else {
|
||||
return config.getIconShiftLock();
|
||||
}
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
// 初始化视图,配置画笔和自定义视图配置对象。
|
||||
|
||||
config = new CustomViewConfig();
|
||||
mPaint = new Paint();
|
||||
config.init();
|
||||
float texsize = Mytool.spToPpx(20f, this.getContext());
|
||||
mPaint.setTextSize(texsize);
|
||||
setPreviewEnabled(false);
|
||||
// 禁用键预览。
|
||||
}
|
||||
|
||||
public void updateConfigView(Context con, int ime) {
|
||||
// 更新键盘配置视图,根据上下文和输入法动作类型更新配置。
|
||||
|
||||
curImeAction = ime;
|
||||
config.updateConfig(con);
|
||||
setBackground(config.getBG());
|
||||
invalidateAllKeys();
|
||||
// 更新键盘背景并刷新所有按键。
|
||||
}
|
||||
|
||||
private void onDrawKeyBackground(Keyboard.Key myKey, Drawable keyBG, Canvas canvas) {
|
||||
// 绘制按键的背景。
|
||||
|
||||
if (keyBG != null) {
|
||||
int left = myKey.x + getPaddingLeft();
|
||||
int top = myKey.y + getPaddingTop();
|
||||
int right = left + myKey.width;
|
||||
int bottom = top + myKey.height;
|
||||
|
||||
keyBG.setBounds(left, top, right, bottom);
|
||||
keyBG.setState(myKey.getCurrentDrawableState());
|
||||
keyBG.draw(canvas);
|
||||
// 设置背景的边界并绘制背景。
|
||||
}
|
||||
}
|
||||
|
||||
private void onDrawLabel(Keyboard.Key myKey, Canvas canvas, String custLabel) {
|
||||
// 绘制按键的标签文字。
|
||||
|
||||
boolean b = myKey.label == null || myKey.label == "";
|
||||
if (!b) {
|
||||
float y1 = myKey.y + myKey.height / 2f - (mPaint.descent() + mPaint.ascent()) / 2f;
|
||||
float x1 = myKey.x + getPaddingLeft() + (myKey.width / 2f);
|
||||
x1 -= mPaint.measureText(myKey.label.toString()) / 2f;
|
||||
// 计算标签的绘制位置,居中显示。
|
||||
|
||||
if (!custLabel.isEmpty()) {
|
||||
// 如果提供了自定义标签,使用自定义标签绘制文字。
|
||||
|
||||
float texsize = Mytool.spToPpx(14f, this.getContext());
|
||||
mPaint.setTextSize(texsize);
|
||||
canvas.drawText(custLabel, x1, y1, mPaint);
|
||||
} else {
|
||||
// 否则使用按键的默认标签绘制文字。
|
||||
|
||||
float texsize = Mytool.spToPpx(18f, this.getContext());
|
||||
mPaint.setTextSize(texsize);
|
||||
canvas.drawText(myKey.label.toString(), x1, y1, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
app/src/main/java/com/key/vibekeyboard/Room/Category.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.key.vibekeyboard.Room;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Category {
|
||||
|
||||
private String className;
|
||||
private List<WallpaperInfo> list = new ArrayList<>();
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public List<WallpaperInfo> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<WallpaperInfo> list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
27
app/src/main/java/com/key/vibekeyboard/Room/MyDatabase.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.key.vibekeyboard.Room;
|
||||
|
||||
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
|
||||
@Database(entities = {WallpaperInfo.class}, version = 1, exportSchema = false)
|
||||
public abstract class MyDatabase extends RoomDatabase {
|
||||
|
||||
public abstract WallpaperInfoDao wallpaperInfoDao();
|
||||
|
||||
private static MyDatabase INSTANCE;
|
||||
|
||||
public static MyDatabase getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (MyDatabase.class) {
|
||||
INSTANCE = Room.databaseBuilder(AppApplication.getContext(), MyDatabase.class, "Database").build();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
157
app/src/main/java/com/key/vibekeyboard/Room/WallpaperInfo.java
Normal file
@ -0,0 +1,157 @@
|
||||
package com.key.vibekeyboard.Room;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity(tableName = "wallpaper_info")
|
||||
public class WallpaperInfo implements Parcelable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int id;
|
||||
public String preview;
|
||||
public String thumb;
|
||||
public String className;
|
||||
public String title;
|
||||
public String zipUrl;
|
||||
public Boolean islike;
|
||||
public Boolean isDownloaded;
|
||||
public String path;
|
||||
|
||||
// Default constructor
|
||||
public WallpaperInfo() {
|
||||
}
|
||||
|
||||
// Constructor for Parcelable
|
||||
protected WallpaperInfo(Parcel in) {
|
||||
id = in.readInt();
|
||||
preview = in.readString();
|
||||
thumb = in.readString();
|
||||
className = in.readString();
|
||||
title = in.readString();
|
||||
zipUrl = in.readString();
|
||||
islike = in.readByte() != 0;
|
||||
isDownloaded = in.readByte() != 0;
|
||||
path = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(id);
|
||||
dest.writeString(preview);
|
||||
dest.writeString(thumb);
|
||||
dest.writeString(className);
|
||||
dest.writeString(title);
|
||||
dest.writeString(zipUrl);
|
||||
dest.writeByte((byte) (islike ? 1 : 0));
|
||||
dest.writeByte((byte) (isDownloaded ? 1 : 0));
|
||||
dest.writeString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<WallpaperInfo> CREATOR = new Creator<WallpaperInfo>() {
|
||||
@Override
|
||||
public WallpaperInfo createFromParcel(Parcel in) {
|
||||
return new WallpaperInfo(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WallpaperInfo[] newArray(int size) {
|
||||
return new WallpaperInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
// Getters and setters
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getPreview() {
|
||||
return preview;
|
||||
}
|
||||
|
||||
public void setPreview(String preview) {
|
||||
this.preview = preview;
|
||||
}
|
||||
|
||||
public String getThumb() {
|
||||
return thumb;
|
||||
}
|
||||
|
||||
public void setThumb(String thumb) {
|
||||
this.thumb = thumb;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getZipUrl() {
|
||||
return zipUrl;
|
||||
}
|
||||
|
||||
public void setZipUrl(String zipUrl) {
|
||||
this.zipUrl = zipUrl;
|
||||
}
|
||||
|
||||
public Boolean getIslike() {
|
||||
return islike;
|
||||
}
|
||||
|
||||
public void setIslike(Boolean islike) {
|
||||
this.islike = islike;
|
||||
}
|
||||
|
||||
public Boolean getDownloaded() {
|
||||
return isDownloaded;
|
||||
}
|
||||
|
||||
public void setDownloaded(Boolean downloaded) {
|
||||
isDownloaded = downloaded;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
WallpaperInfo that = (WallpaperInfo) o;
|
||||
return id == that.id &&
|
||||
Objects.equals(title, that.title) &&
|
||||
Objects.equals(preview, that.preview) &&
|
||||
islike == that.islike;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, title, preview, islike);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.key.vibekeyboard.Room;
|
||||
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface WallpaperInfoDao {
|
||||
|
||||
@Query("select * from wallpaper_info order by RANDOM() LIMIT 1")
|
||||
WallpaperInfo queryRandomItem();
|
||||
|
||||
@Insert
|
||||
void insertAll(List<WallpaperInfo> likeDataList);
|
||||
|
||||
@Query("select * from wallpaper_info where preview =:pre ")
|
||||
List<WallpaperInfo> checklikelist(String pre);
|
||||
|
||||
@Update
|
||||
void update(WallpaperInfo wallpaperInfo);
|
||||
|
||||
@Query("SELECT * FROM wallpaper_info WHERE islike = :islike")
|
||||
List<WallpaperInfo> getlikelist(boolean islike);
|
||||
@Query("SELECT * FROM wallpaper_info WHERE islike = :islike")
|
||||
LiveData<List<WallpaperInfo>> getLiveLikeList(boolean islike);
|
||||
|
||||
@Query("SELECT * FROM wallpaper_info WHERE isDownloaded = :isdownload")
|
||||
List<WallpaperInfo> getdownloadlist(boolean isdownload);
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
package com.key.vibekeyboard.Utils;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
|
||||
|
||||
// ItemDecoration 是一个自定义的 RecyclerView.ItemDecoration 类,用于在 RecyclerView 中为每个子项设置间距。
|
||||
public class ItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
// 垂直间距 (vertical spacing)、水平间距 (horizontal spacing) 和额外间距 (extra spacing):这里设置的是第一个的左边距,其它item根据剩余的距离均匀显示。
|
||||
private int v, h, ex;
|
||||
|
||||
// 构造函数,传入 dp 值的垂直、水平和额外间距,并将它们转换为像素值。
|
||||
public ItemDecoration(int v, int h, int ex) {
|
||||
// 将 dp 值转换为像素值并四舍五入
|
||||
this.v = Math.round(dpToPx(v));
|
||||
this.h = Math.round(dpToPx(h));
|
||||
this.ex = Math.round(dpToPx(ex));
|
||||
}
|
||||
|
||||
// 重写 getItemOffsets 方法,用于为每个子项设置偏移量(间距)。
|
||||
@Override
|
||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
|
||||
// 定义网格的列数(spanCount)、子项所占的列数(spanSize)以及子项在网格中的索引(spanIndex)
|
||||
int spanCount = 1; // 列数默认为 1
|
||||
int spanSize = 1; // 子项所占列数默认为 1
|
||||
int spanIndex = 0; // 子项在网格中的索引默认为 0
|
||||
|
||||
// 获取子项在 Adapter 中的位置
|
||||
int childAdapterPosition = parent.getChildAdapterPosition(view);
|
||||
// 获取 RecyclerView 的布局管理器
|
||||
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
|
||||
|
||||
// 如果布局管理器是 StaggeredGridLayoutManager(交错网格布局管理器)
|
||||
if (layoutManager instanceof StaggeredGridLayoutManager) {
|
||||
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
|
||||
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
|
||||
spanCount = staggeredGridLayoutManager.getSpanCount(); // 获取列数
|
||||
// 如果子项占据整行(isFullSpan),将 spanSize 设置为列数
|
||||
if (layoutParams.isFullSpan()) {
|
||||
spanSize = spanCount;
|
||||
}
|
||||
spanIndex = layoutParams.getSpanIndex(); // 获取子项的索引
|
||||
|
||||
// 如果布局管理器是 GridLayoutManager(网格布局管理器)
|
||||
} else if (layoutManager instanceof GridLayoutManager) {
|
||||
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
|
||||
GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
|
||||
spanCount = gridLayoutManager.getSpanCount(); // 获取列数
|
||||
spanSize = gridLayoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition); // 获取子项占据的列数
|
||||
spanIndex = layoutParams.getSpanIndex(); // 获取子项的索引
|
||||
|
||||
// 如果布局管理器是 LinearLayoutManager(线性布局管理器)
|
||||
} else if (layoutManager instanceof LinearLayoutManager) {
|
||||
// 设置子项的左、右和底部的间距
|
||||
outRect.left = v;
|
||||
outRect.right = v;
|
||||
outRect.bottom = h;
|
||||
}
|
||||
|
||||
// 如果子项占据整行(spanSize == spanCount),设置左、右和底部的间距
|
||||
if (spanSize == spanCount) {
|
||||
outRect.left = v + ex;
|
||||
outRect.right = v + ex;
|
||||
outRect.bottom = h;
|
||||
|
||||
// 如果子项不占据整行,根据网格布局计算左右间距
|
||||
} else {
|
||||
// 计算每个子项的总间距(包括额外间距)
|
||||
int itemAllSpacing = (v * (spanCount + 1) + ex * 2) / spanCount;
|
||||
// 计算子项的左边距
|
||||
int left = v * (spanIndex + 1) - itemAllSpacing * spanIndex + ex;
|
||||
// 计算子项的右边距
|
||||
int right = itemAllSpacing - left;
|
||||
outRect.left = left;
|
||||
outRect.right = right;
|
||||
outRect.bottom = h;
|
||||
}
|
||||
}
|
||||
|
||||
// 将 dp 值转换为像素值的方法
|
||||
public static float dpToPx(float dpValue) {
|
||||
// 获取当前设备的屏幕密度(dpi)
|
||||
float density = AppApplication.getContext().getResources().getDisplayMetrics().density;
|
||||
// 通过公式 density * dp + 0.5f 将 dp 转换为像素,并返回结果
|
||||
return density * dpValue + 0.5f;
|
||||
}
|
||||
}
|
||||
273
app/src/main/java/com/key/vibekeyboard/Utils/Mytool.java
Normal file
@ -0,0 +1,273 @@
|
||||
package com.key.vibekeyboard.Utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.inputmethodservice.Keyboard;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.util.TypedValue;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.key.vibekeyboard.AppApplication;
|
||||
import com.key.vibekeyboard.Keyboard.MyKeyboard;
|
||||
import com.key.vibekeyboard.R;
|
||||
import com.key.vibekeyboard.Room.Category;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
import com.key.vibekeyboard.callback.DownloadCallback;
|
||||
import com.key.vibekeyboard.callback.UnzipCallback;
|
||||
|
||||
import net.sf.sevenzipjbinding.ArchiveFormat;
|
||||
import net.sf.sevenzipjbinding.IInArchive;
|
||||
import net.sf.sevenzipjbinding.SevenZip;
|
||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileOutStream;
|
||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Mytool {
|
||||
|
||||
// 获取输入法管理服务的实例
|
||||
private static final InputMethodManager methodManager = (InputMethodManager) AppApplication.instance.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
// 用于执行异步任务的线程池
|
||||
private static ExecutorService executorService;
|
||||
|
||||
public static void onDrawKeyIcon(Keyboard.Key currentKey,
|
||||
Drawable drawKeyIcon,
|
||||
Canvas myCanvas,
|
||||
MyKeyboard myKeyboardView) {
|
||||
currentKey.icon = drawKeyIcon;
|
||||
currentKey.icon.setBounds(calculateIconBounds(currentKey, drawKeyIcon, myKeyboardView));
|
||||
currentKey.icon.draw(myCanvas);
|
||||
}
|
||||
|
||||
private static Rect calculateIconBounds(Keyboard.Key currentKey,
|
||||
Drawable drawKeyIcon,
|
||||
MyKeyboard myKeyboardView) {
|
||||
float icon_w = drawKeyIcon.getIntrinsicWidth();
|
||||
float icon_h = drawKeyIcon.getIntrinsicHeight();
|
||||
float icon_wr = icon_w / currentKey.width;
|
||||
float icon_hr = icon_h / currentKey.height;
|
||||
|
||||
float tep1, tep2;
|
||||
if (icon_wr > icon_hr) {
|
||||
tep2 = icon_wr;
|
||||
tep1 = Math.max(icon_wr, 0.5f);
|
||||
} else {
|
||||
tep2 = icon_hr;
|
||||
tep1 = Math.max(icon_hr, 0.5f);
|
||||
}
|
||||
|
||||
icon_h = (icon_h / tep2) * tep1;
|
||||
icon_w = (icon_w / tep2) * tep1;
|
||||
|
||||
int top = (int) (currentKey.y + myKeyboardView.getPaddingTop() + (currentKey.height - icon_h) / 2);
|
||||
int left = (int) (currentKey.x + myKeyboardView.getPaddingLeft() + (currentKey.width - icon_w) / 2);
|
||||
int bottom = top + (int) icon_h;
|
||||
int right = left + (int) icon_w;
|
||||
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
// 从资源文件加载JSON数据
|
||||
public static JSONArray loadJSONFromAsset(String filename) {
|
||||
String json;
|
||||
try {
|
||||
AssetManager assetManager = AppApplication.getContext().getAssets();
|
||||
InputStream inputStream = assetManager.open(filename);
|
||||
int size = inputStream.available();
|
||||
byte[] buffer = new byte[size];
|
||||
inputStream.read(buffer);
|
||||
inputStream.close();
|
||||
json = new String(buffer, StandardCharsets.UTF_8);
|
||||
return new JSONArray(json); // 转换为JSONArray
|
||||
} catch (IOException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 解析JSON数据为列表
|
||||
public static List<Category> parseJsonToList(String filename) {
|
||||
List<Category> dataList = new ArrayList<>();
|
||||
try {
|
||||
JSONArray jsonObject = loadJSONFromAsset(filename);
|
||||
for (int a = 0; a < Objects.requireNonNull(jsonObject).length(); a++) {
|
||||
JSONObject list = jsonObject.getJSONObject(a);
|
||||
Category myData = new Category();
|
||||
List<WallpaperInfo> otherdataList = new ArrayList<>();
|
||||
myData.setClassName(list.getString("className"));
|
||||
JSONArray classArray = list.getJSONArray("list");
|
||||
for (int i = 0; i < classArray.length(); i++) {
|
||||
JSONObject item = classArray.getJSONObject(i);
|
||||
WallpaperInfo otherdata = new WallpaperInfo();
|
||||
otherdata.setDownloaded(false);
|
||||
otherdata.setIslike(false);
|
||||
otherdata.setClassName(myData.getClassName());
|
||||
otherdata.setPreview(item.getString("preview"));
|
||||
otherdata.setThumb(item.getString("thumb"));
|
||||
otherdata.setTitle(item.getString("title"));
|
||||
otherdata.setZipUrl(item.getString("zipUrl"));
|
||||
otherdataList.add(otherdata);
|
||||
}
|
||||
myData.setList(otherdataList);
|
||||
dataList.add(myData);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return dataList;
|
||||
}
|
||||
|
||||
// 检查输入法步骤2(确认输入法是否为当前应用)
|
||||
public static boolean isStep2() {
|
||||
String string = Settings.Secure.getString(AppApplication.instance.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
return string.startsWith(AppApplication.instance.getPackageName());
|
||||
}
|
||||
|
||||
// 检查输入法步骤1(确认当前输入法是否被启用)
|
||||
public static boolean isStep1() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return methodManager.getEnabledInputMethodList().stream()
|
||||
.anyMatch(inputMethodInfo -> inputMethodInfo.getId().startsWith(AppApplication.instance.getPackageName()));
|
||||
} else {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) AppApplication.instance.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
List<InputMethodInfo> inputMethodList = inputMethodManager.getEnabledInputMethodList();
|
||||
for (InputMethodInfo inputMethodInfo : inputMethodList) {
|
||||
if (inputMethodInfo.getId().startsWith(AppApplication.instance.getPackageName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 解压文件的操作
|
||||
public static void unZip(Context context, String urlpath, File resource, UnzipCallback callback) throws IOException {
|
||||
if (!resource.exists()) { // 如果资源文件不存在,显示下载失败的提示
|
||||
Toast.makeText(context, context.getString(R.string.app_name), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
String itemFilePath = "";
|
||||
RandomAccessFile accessFile = new RandomAccessFile(resource, "r");
|
||||
RandomAccessFileInStream inStream = new RandomAccessFileInStream(accessFile);
|
||||
IInArchive iInArchive = SevenZip.openInArchive(ArchiveFormat.SEVEN_ZIP, inStream);
|
||||
ISimpleInArchiveItem[] archiveItems = iInArchive.getSimpleInterface().getArchiveItems();
|
||||
// 解压每一个文件
|
||||
for (int d = 0; d < archiveItems.length; d++) {
|
||||
ISimpleInArchiveItem simple = archiveItems[d];
|
||||
File file = new File(urlpath, simple.getPath());
|
||||
if (!simple.isFolder()) { // 如果不是文件夹,解压文件
|
||||
RandomAccessFileOutStream outStream = new RandomAccessFileOutStream(new RandomAccessFile(file, "rw"));
|
||||
simple.extractSlow(outStream);
|
||||
itemFilePath = file.getPath(); // 记录解压后的文件路径
|
||||
} else {
|
||||
boolean mkdirs = file.mkdirs(); // 创建文件夹
|
||||
}
|
||||
}
|
||||
inStream.close();
|
||||
iInArchive.close();
|
||||
int res = itemFilePath.indexOf("res");
|
||||
String substring = itemFilePath.substring(0, res + 3); // 截取资源路径
|
||||
callback.onUnzipCall(true, substring); // 调用回调函数
|
||||
}
|
||||
}
|
||||
|
||||
// 下载压缩文件操作
|
||||
public static void donwnZip(Context context, String url, DownloadCallback callback) {
|
||||
// 使用Glide库来下载文件
|
||||
Glide.with(context)
|
||||
.asFile() // 指定下载的资源类型为File
|
||||
.load(url) // 设置下载的URL
|
||||
.listener(new RequestListener<File>() {
|
||||
// 添加监听器来处理下载结果
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<File> target, boolean isFirstResource) {
|
||||
// 下载失败时的回调
|
||||
try {
|
||||
callback.onDownloadCall(false, null); // 调用回调方法,传递失败状态
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new RuntimeException(ex); // 如果捕获到FileNotFoundException异常,抛出运行时异常
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex); // 如果捕获到IOException异常,抛出运行时异常
|
||||
}
|
||||
return false; // 表示处理了这个事件
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(@NonNull File resource, @NonNull Object model, Target<File> target, @NonNull DataSource dataSource, boolean isFirstResource) {
|
||||
// 下载成功时的回调
|
||||
try {
|
||||
callback.onDownloadCall(true, resource); // 调用回调方法,传递成功状态和下载的文件
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e); // 如果捕获到FileNotFoundException异常,抛出运行时异常
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e); // 如果捕获到IOException异常,抛出运行时异常
|
||||
}
|
||||
return false; // 表示处理了这个事件
|
||||
}
|
||||
}).preload(); // 预加载文件
|
||||
}
|
||||
|
||||
// 将文件内容转换为字符串
|
||||
public static String fileToString(File file) throws IOException {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String lin = "";
|
||||
// 逐行读取文件内容
|
||||
while ((lin = bufferedReader.readLine()) != null) {
|
||||
stringBuilder.append(lin);
|
||||
}
|
||||
bufferedReader.close();
|
||||
String con = stringBuilder.toString(); // 转换为字符串
|
||||
return con;
|
||||
}
|
||||
|
||||
// 将SP单位转换为像素单位
|
||||
public static float spToPpx(Float values, Context context) {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, values, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
// 运行IO操作的任务
|
||||
public static void runIO(Runnable task) {
|
||||
getExecutorService().execute(task);
|
||||
}
|
||||
|
||||
// 获取线程池的实例,如果不存在则创建一个单线程池
|
||||
private static ExecutorService getExecutorService() {
|
||||
if (executorService == null) {
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
return executorService;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.key.vibekeyboard.Utils;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class SettingUtil {
|
||||
public static final String PRIVACY_POLICY_URL = "https://himelody.mystrikingly.com/privacy";
|
||||
public static final String TERMS_OF_SERVICE_URL = "https://himelody.mystrikingly.com/terms";
|
||||
|
||||
// 获取当前应用的版本号
|
||||
public static String getCurrentVersion(Context context) {
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
|
||||
return packageInfo.versionName; // 返回版本名称
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return null; // 返回null表示获取版本号失败
|
||||
}
|
||||
}
|
||||
|
||||
// 发送反馈
|
||||
public static void sendFeedback(Context context, String email, String subject) {
|
||||
Intent emailIntent = new Intent(Intent.ACTION_SEND);
|
||||
emailIntent.setType("message/rfc822");
|
||||
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
try {
|
||||
context.startActivity(Intent.createChooser(emailIntent, "Send Feedback"));
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
Toast.makeText(context, "There is no app that supports sending emails", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
// 分享应用
|
||||
public static void shareApp(Context context) {
|
||||
String appPackageName = context.getPackageName();
|
||||
String appName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
|
||||
String appPlayStoreLink = "https://play.google.com/store/apps/details?id=" + appPackageName;
|
||||
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Check out this app: " + appName);
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, "Download " + appName + " from Google Play: " + appPlayStoreLink);
|
||||
context.startActivity(Intent.createChooser(shareIntent, "Share " + appName + " via"));
|
||||
}
|
||||
|
||||
// 打开隐私政策
|
||||
public static void openPrivacyPolicy(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(PRIVACY_POLICY_URL));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
// 打开服务条款
|
||||
public static void openTermsOfService(Context context) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TERMS_OF_SERVICE_URL));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
// 打开Google Play
|
||||
public static void openGooglePlay(Context context, String packageName) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + packageName));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.key.vibekeyboard.Utils;
|
||||
|
||||
public class StaticValue {
|
||||
public static String KEY_NAME = "key_name";
|
||||
public static String KEY_URL = "key_url";
|
||||
public static String KEY_PRE = "key_pre";
|
||||
public static String PATH = "";
|
||||
public static String KEY_TEXT = "";
|
||||
public static String KEY_ISMAINSH = "";
|
||||
public static String KEY_ISshow = "";
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.key.vibekeyboard.ViewModel;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import com.key.vibekeyboard.Room.MyDatabase;
|
||||
import com.key.vibekeyboard.Room.WallpaperInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FavoriteViewModel extends ViewModel {
|
||||
private final LiveData<List<WallpaperInfo>> favoriteList;
|
||||
private final MyDatabase database;
|
||||
|
||||
public FavoriteViewModel() {
|
||||
// 获取数据库实例
|
||||
database = MyDatabase.getInstance();
|
||||
// 通过 LiveData 监听数据库中的喜欢列表变化
|
||||
favoriteList = database.wallpaperInfoDao().getLiveLikeList(true);
|
||||
}
|
||||
|
||||
// 提供一个获取喜欢列表 LiveData 的方法
|
||||
public LiveData<List<WallpaperInfo>> getFavoriteList() {
|
||||
return favoriteList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.key.vibekeyboard.callback;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DownloadCallback {
|
||||
|
||||
void onDownloadCall(boolean successful, File resource) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package com.key.vibekeyboard.callback;
|
||||
|
||||
public interface RecommendDialogCallback {
|
||||
|
||||
void onTryNow();
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package com.key.vibekeyboard.callback;
|
||||
|
||||
public interface StepDialogCallback {
|
||||
|
||||
void onDisMiss();
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package com.key.vibekeyboard.callback;
|
||||
|
||||
public interface UnzipCallback {
|
||||
|
||||
void onUnzipCall(boolean successful, String resDirPath);
|
||||
}
|
||||
30
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
20
app/src/main/res/drawable/back.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M13,8L6,14L13,21"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M6,14H28.994C35.877,14 41.722,19.62 41.99,26.5C42.274,33.77 36.267,40 28.994,40H11.998"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
23
app/src/main/res/drawable/help.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M24,44C29.523,44 34.523,41.761 38.142,38.142C41.761,34.523 44,29.523 44,24C44,18.477 41.761,13.477 38.142,9.858C34.523,6.239 29.523,4 24,4C18.477,4 13.477,6.239 9.858,9.858C6.239,13.477 4,18.477 4,24C4,29.523 6.239,34.523 9.858,38.142C13.477,41.761 18.477,44 24,44Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
<path
|
||||
android:pathData="M24,28.625V24.625C27.314,24.625 30,21.938 30,18.625C30,15.311 27.314,12.625 24,12.625C20.686,12.625 18,15.311 18,18.625"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M24,37.625C25.381,37.625 26.5,36.506 26.5,35.125C26.5,33.744 25.381,32.625 24,32.625C22.619,32.625 21.5,33.744 21.5,35.125C21.5,36.506 22.619,37.625 24,37.625Z"
|
||||
android:fillColor="#333"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
74
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
android:height="108dp"
|
||||
android:width="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</vector>
|
||||
7
app/src/main/res/drawable/permission_select.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/un_rounded_corners" android:state_selected="false" />
|
||||
<item android:drawable="@drawable/rounded_corners" android:state_selected="true" />
|
||||
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/rounded_corners.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@android:color/darker_gray" />
|
||||
<corners android:radius="22dp"/>
|
||||
</shape>
|
||||
15
app/src/main/res/drawable/rounded_rectangle.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<!-- 设置背景颜色 -->
|
||||
<solid android:color="#FFFFFF"/> <!-- 替换为你需要的颜色 -->
|
||||
|
||||
<!-- 设置圆角 -->
|
||||
<corners android:radius="40dp"/> <!-- 圆角半径,可以根据需要调整 -->
|
||||
|
||||
<!-- 设置边框 -->
|
||||
<stroke android:width="2dp" android:color="#FFFFFF"/> <!-- 可选:为矩形设置边框 -->
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
30
app/src/main/res/drawable/seek_bar_color.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<!-- res/drawable/seekbar_progress_drawable.xml -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<corners android:radius="5dp" />
|
||||
<solid android:color="#D3D3D3" /> <!-- 背景颜色 -->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:id="@android:id/secondaryProgress">
|
||||
<clip>
|
||||
<shape>
|
||||
<corners android:radius="5dp" />
|
||||
<solid android:color="#FFD700" /> <!-- 次级进度颜色 -->
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<corners android:radius="5dp" />
|
||||
<gradient
|
||||
android:startColor="#4891FF"
|
||||
android:endColor="#6CE89E"
|
||||
android:angle="0" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
||||
27
app/src/main/res/drawable/share.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M42,38V42L6,42L6,38"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M30,6L40,16L30,26"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M40,16C20,16 6,19 6,32"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
38
app/src/main/res/drawable/share_right.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M35,16C37.761,16 40,13.761 40,11C40,8.239 37.761,6 35,6C32.239,6 30,8.239 30,11C30,13.761 32.239,16 35,16Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
<path
|
||||
android:pathData="M13,29C15.761,29 18,26.761 18,24C18,21.239 15.761,19 13,19C10.239,19 8,21.239 8,24C8,26.761 10.239,29 13,29Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
<path
|
||||
android:pathData="M30,13.575L17.339,21.245"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M17.338,26.564L30.679,34.447"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M35,32C37.761,32 40,34.239 40,37C40,39.761 37.761,42 35,42C32.239,42 30,39.761 30,37C30,34.239 32.239,32 35,32Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/un_rounded_corners.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@android:color/holo_blue_bright" />
|
||||
<corners android:radius="22dp"/>
|
||||
</shape>
|
||||
56
app/src/main/res/layout/activity_category.xml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Activity.CategoryActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/category_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center"
|
||||
android:text="Simple Keyboard"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/category_search"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:src="@android:drawable/ic_menu_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/category_tab"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="45dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/category_search"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabMode="scrollable"
|
||||
app:tabRippleColor="@android:color/transparent" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/category_viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/category_tab" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
135
app/src/main/res/layout/activity_download.xml
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Activity.DownloadActivity">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:text="love kiteen"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_favorite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:src="@android:drawable/btn_star"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_back" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/download_download"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:backgroundTint="@android:color/holo_blue_light"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_image">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@android:drawable/stat_sys_download" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Download"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_text1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="Simple Keyboard"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_download" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/download_text2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="View All"
|
||||
app:layout_constraintEnd_toStartOf="@+id/download_all"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_download" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@android:drawable/ic_menu_sort_by_size"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_download" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_text1" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="#80000000"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
28
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@mipmap/activity_background"
|
||||
tools:context=".Activity.MainActivity">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/main_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/main_tablayout"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/main_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabRippleColor="@android:color/transparent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
10
app/src/main/res/layout/activity_permission.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Activity.PermissionActivity">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
16
app/src/main/res/layout/activity_search.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/searchEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Search" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
49
app/src/main/res/layout/activity_splash.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@mipmap/activity_background"
|
||||
tools:activity=".activity.SplashActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/splash_image"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:src="@mipmap/ic_launcher_foreground"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/splash_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/splash_image" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="5dp"
|
||||
android:layout_marginStart="53dp"
|
||||
android:layout_marginEnd="53dp"
|
||||
android:layout_marginBottom="80dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:progressDrawable="@drawable/seek_bar_color"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
18
app/src/main/res/layout/category_tab_custom.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category_tab_custom_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="17sp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
79
app/src/main/res/layout/dialog_permission.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#f0f0f0">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/ic_launcher_foreground"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="示例文字"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/imageView" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/firstIconTextLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/permission_select"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/ic_launcher_foreground" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="图标文字1" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/secondIconTextLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/permission_select"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/firstIconTextLayout">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@drawable/ic_launcher_foreground" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="图标文字2" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
30
app/src/main/res/layout/dialog_recommended.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/ic_launcher_foreground" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/imageView" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
14
app/src/main/res/layout/fragment_category.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".Fragment.CategoryFragment">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/category_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
28
app/src/main/res/layout/fragment_favorite.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Fragment.FavoriteFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/favorite_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center"
|
||||
android:text="Simple Keyboard"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/favorite_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/favorite_title"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
79
app/src/main/res/layout/fragment_home.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/home_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Fragment.HomeFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center"
|
||||
android:text="Simple Keyboard"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_search"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:src="@android:drawable/ic_menu_search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/home_viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_text1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="More recommendations"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_viewPager" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_text2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="View All"
|
||||
app:layout_constraintEnd_toStartOf="@+id/home_all"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_viewPager" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@android:drawable/ic_menu_sort_by_size"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_viewPager" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/home_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/home_text1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
99
app/src/main/res/layout/fragment_setting.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
tools:context=".Fragment.SettingFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Setting"
|
||||
android:textSize="24sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/help" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Version"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/share" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Share"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/share_right" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
12
app/src/main/res/layout/home_recycler_item.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_recycler_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
12
app/src/main/res/layout/home_viewpager2_item.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_viewpager_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
12
app/src/main/res/layout/keyboard_view.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.key.vibekeyboard.Keyboard.MyKeyboard
|
||||
android:id="@+id/keyboardView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="210dp" />
|
||||
|
||||
</LinearLayout>
|
||||
14
app/src/main/res/layout/main_tab_custom.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_custom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/activity_background.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
7
app/src/main/res/values-night/themes.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.KeyboardDemo" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your dark theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
|
||||
</style>
|
||||
</resources>
|
||||
5
app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
4
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<string name="app_name">Vibe Keyboard</string>
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
9
app/src/main/res/values/themes.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.KeyboardDemo" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.KeyboardDemo" parent="Base.Theme.KeyboardDemo" />
|
||||
</resources>
|
||||
13
app/src/main/res/xml/backup_rules.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
19
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
10
app/src/main/res/xml/im.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<subtype
|
||||
android:icon="@drawable/ic_launcher_background"
|
||||
android:imeSubtypeLocale="en_US"
|
||||
android:imeSubtypeMode = "keyboard"
|
||||
android:label="@string/app_name" />
|
||||
|
||||
</input-method>
|
||||
146
app/src/main/res/xml/view_1.xml
Normal file
@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.45%"
|
||||
android:keyHeight="50dp">
|
||||
<Key
|
||||
android:codes="113"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="q" />
|
||||
<Key
|
||||
android:codes="119"
|
||||
android:keyLabel="w" />
|
||||
<Key
|
||||
android:codes="101"
|
||||
android:keyLabel="e" />
|
||||
<Key
|
||||
android:codes="114"
|
||||
android:keyLabel="r" />
|
||||
<Key
|
||||
android:codes="116"
|
||||
android:keyLabel="t" />
|
||||
<Key
|
||||
android:codes="121"
|
||||
android:keyLabel="y" />
|
||||
<Key
|
||||
android:codes="117"
|
||||
android:keyLabel="u" />
|
||||
<Key
|
||||
android:codes="105"
|
||||
android:keyLabel="i" />
|
||||
<Key
|
||||
android:codes="111"
|
||||
android:keyLabel="o" />
|
||||
<Key
|
||||
android:codes="112"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="p" />
|
||||
</Row>
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.444444%"
|
||||
android:keyHeight="50dp">
|
||||
<Key
|
||||
android:codes="97"
|
||||
android:horizontalGap="5.5%"
|
||||
android:keyLabel="a" />
|
||||
<Key
|
||||
android:codes="115"
|
||||
android:keyLabel="s" />
|
||||
<Key
|
||||
android:codes="100"
|
||||
android:keyLabel="d" />
|
||||
<Key
|
||||
android:codes="102"
|
||||
android:keyLabel="f" />
|
||||
<Key
|
||||
android:codes="103"
|
||||
android:keyLabel="g" />
|
||||
<Key
|
||||
android:codes="104"
|
||||
android:keyLabel="h" />
|
||||
<Key
|
||||
android:codes="106"
|
||||
android:keyLabel="j" />
|
||||
<Key
|
||||
android:codes="107"
|
||||
android:keyLabel="k" />
|
||||
<Key
|
||||
android:codes="108"
|
||||
android:keyLabel="l" />
|
||||
</Row>
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.5%"
|
||||
android:keyHeight="50dp">
|
||||
|
||||
<Key
|
||||
android:codes="-1"
|
||||
android:isModifier="true"
|
||||
android:isSticky="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="left" />
|
||||
<Key
|
||||
android:codes="122"
|
||||
android:keyLabel="z" />
|
||||
<Key
|
||||
android:codes="120"
|
||||
android:keyLabel="x" />
|
||||
<Key
|
||||
android:codes="99"
|
||||
android:keyLabel="c" />
|
||||
<Key
|
||||
android:codes="118"
|
||||
android:keyLabel="v" />
|
||||
<Key
|
||||
android:codes="98"
|
||||
android:keyLabel="b" />
|
||||
<Key
|
||||
android:codes="110"
|
||||
android:keyLabel="n" />
|
||||
<Key
|
||||
android:codes="109"
|
||||
android:keyLabel="m" />
|
||||
|
||||
<Key
|
||||
android:codes="-5"
|
||||
android:isModifier="true"
|
||||
android:isRepeatable="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.5%"
|
||||
android:keyHeight="50dp"
|
||||
android:rowEdgeFlags="bottom">
|
||||
|
||||
<Key
|
||||
android:codes="-2"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="\?123" />
|
||||
|
||||
<Key
|
||||
android:codes="44"
|
||||
android:keyLabel="," />
|
||||
<Key
|
||||
android:codes="32"
|
||||
android:keyWidth="49.5%"
|
||||
android:keyLabel="English" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="." />
|
||||
|
||||
|
||||
<Key
|
||||
android:codes="-4"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="Done" />
|
||||
</Row>
|
||||
|
||||
</Keyboard>
|
||||