V1.0.0(1)完成版
BIN
app/GlowKeyboard.jks
Normal file
15
app/proguard-rules.pro
vendored
@ -19,3 +19,18 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keepclassmembers class com.keyboard.glowkeyboard.MyApplication {
|
||||
public static final java.lang.String DB_NAME;
|
||||
public static final int DB_VERSION;
|
||||
}
|
||||
|
||||
-keepclassmembers class * {
|
||||
@androidx.room.Query <methods>;
|
||||
}
|
||||
-keep class com.keyboard.glowkeyboard.room.AppDatabase { *; }
|
||||
-keep class com.keyboard.glowkeyboard.room.GlowData { *; }
|
||||
-keep class com.keyboard.glowkeyboard.room.GlowDataDao { *; }
|
||||
|
||||
-keep class com.omicronapplications.** { *; }
|
||||
-keep class net.sf.sevenzipjbinding.** { *; }
|
||||
@ -16,17 +16,20 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.GlowKeyboard"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".ui.activity.TestActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.CategoryListActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.SplashActivity"
|
||||
android:name=".ui.activity.MainActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.GlowActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.MainActivity"
|
||||
android:name=".ui.activity.SplashActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@ -34,6 +37,21 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".ui.keyboard.GlowService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
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>
|
||||
@ -13,7 +13,6 @@ import com.keyboard.glowkeyboard.room.AppDatabase;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
import com.keyboard.glowkeyboard.room.GlowDataDao;
|
||||
import com.keyboard.glowkeyboard.util.JsonParse;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -24,7 +23,7 @@ public class MyApplication extends Application {
|
||||
public static final String DB_NAME = "keyboard_database";
|
||||
public static final String PREF_NAME = "app_preferences";
|
||||
public static final String KEY_FILE_PATH = "file_path";
|
||||
private static final String KEY_INITIALIZED = "is_database_initialized";
|
||||
private static final String INIT_FLAG = "init_database";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@ -33,11 +32,10 @@ public class MyApplication extends Application {
|
||||
application = this;
|
||||
|
||||
SharedPreferences preferences = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
boolean isDatabaseInitialized = preferences.getBoolean(KEY_INITIALIZED, false);
|
||||
|
||||
if (!isDatabaseInitialized) {
|
||||
initializeDatabase();
|
||||
preferences.edit().putBoolean(KEY_INITIALIZED, true).apply();
|
||||
if (!preferences.getBoolean(INIT_FLAG, false)) {
|
||||
initDatabase();
|
||||
preferences.edit().putBoolean(INIT_FLAG, true).apply();
|
||||
}
|
||||
|
||||
lockScreenOrientation();
|
||||
@ -86,15 +84,9 @@ public class MyApplication extends Application {
|
||||
return application.getApplicationContext();
|
||||
}
|
||||
|
||||
private void initializeDatabase() {
|
||||
private void initDatabase() {
|
||||
GlowDataDao glowDataDao = AppDatabase.getInstance(getContext()).glowDataDao();
|
||||
List<GlowData> glowDataList = JsonParse.parseJson(getContext(), "keyboard_wallpaper.json");
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
glowDataDao.insertAll(glowDataList);
|
||||
new Thread(() -> glowDataDao.insertAll(glowDataList)).start();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package com.keyboard.glowkeyboard.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;
|
||||
@ -15,4 +17,15 @@ public interface GlowDataDao {
|
||||
@Update
|
||||
void update(GlowData glowData);
|
||||
|
||||
@Query("SELECT * FROM GlowData WHERE isFavorite = 1")
|
||||
LiveData<List<GlowData>> getFavorite();
|
||||
|
||||
@Query("SELECT * FROM GlowData WHERE id IN (SELECT MIN(id) FROM GlowData GROUP BY name)")
|
||||
LiveData<List<GlowData>> getFirstCategory();
|
||||
|
||||
@Query("SELECT * FROM GlowData WHERE name = :name")
|
||||
LiveData<List<GlowData>> getCategory(String name);
|
||||
|
||||
@Query("SELECT * FROM GlowData LIMIT :limit OFFSET :offset")
|
||||
LiveData<List<GlowData>> getRecommended(int limit, int offset);
|
||||
}
|
||||
|
||||
@ -1,26 +1,104 @@
|
||||
package com.keyboard.glowkeyboard.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
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 androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityCategoryListBinding;
|
||||
import com.keyboard.glowkeyboard.ui.adapter.GlowAdapter;
|
||||
import com.keyboard.glowkeyboard.util.ItemDecoration;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CategoryListActivity extends AppCompatActivity {
|
||||
private ActivityCategoryListBinding viewBinding;
|
||||
private GlowAdapter glowAdapter;
|
||||
private GlowViewModel glowViewModel;
|
||||
private String categoryTitle;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
enableEdgeToEdgeDisplay();
|
||||
initializeBinding();
|
||||
setupWindowInsets();
|
||||
|
||||
loadInitialData();
|
||||
configureEvents();
|
||||
}
|
||||
|
||||
private void enableEdgeToEdgeDisplay() {
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_category_list);
|
||||
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;
|
||||
}
|
||||
|
||||
private void initializeBinding() {
|
||||
viewBinding = ActivityCategoryListBinding.inflate(getLayoutInflater());
|
||||
setContentView(viewBinding.getRoot());
|
||||
}
|
||||
|
||||
private void setupWindowInsets() {
|
||||
View mainLayout = findViewById(R.id.main);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mainLayout, (view, windowInsets) -> {
|
||||
Insets bars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
view.setPadding(bars.left, bars.top, bars.right, bars.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
}
|
||||
|
||||
private void loadInitialData() {
|
||||
categoryTitle = retrieveCategoryName();
|
||||
if (categoryTitle == null) {
|
||||
terminateActivity();
|
||||
return;
|
||||
}
|
||||
|
||||
glowViewModel = new ViewModelProvider(this).get(GlowViewModel.class);
|
||||
configureRecyclerView();
|
||||
}
|
||||
|
||||
private String retrieveCategoryName() {
|
||||
return getIntent().getStringExtra("name");
|
||||
}
|
||||
|
||||
private void terminateActivity() {
|
||||
finish();
|
||||
}
|
||||
|
||||
private void configureRecyclerView() {
|
||||
RecyclerView recycler = viewBinding.recyclerView;
|
||||
recycler.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
glowAdapter = new GlowAdapter(glowViewModel, this, new ArrayList<>(), this,1);
|
||||
recycler.setAdapter(glowAdapter);
|
||||
recycler.addItemDecoration(new ItemDecoration(20, 15, 20));
|
||||
}
|
||||
|
||||
private void configureEvents() {
|
||||
viewBinding.back.setOnClickListener(view -> terminateActivity());
|
||||
viewBinding.title.setText(categoryTitle);
|
||||
fetchCategoryData();
|
||||
}
|
||||
|
||||
private void fetchCategoryData() {
|
||||
glowViewModel.getCategory(categoryTitle).observe(this, categoryData -> {
|
||||
if (categoryData != null) {
|
||||
glowAdapter.refreshData(categoryData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
viewBinding = null;
|
||||
}
|
||||
}
|
||||
@ -1,26 +1,190 @@
|
||||
package com.keyboard.glowkeyboard.ui.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
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 androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.MultiTransformation;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.keyboard.glowkeyboard.MyApplication;
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityGlowBinding;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
import com.keyboard.glowkeyboard.ui.adapter.GlowAdapter;
|
||||
import com.keyboard.glowkeyboard.ui.dialog.RequestDialog;
|
||||
import com.keyboard.glowkeyboard.util.DownloadAndUnzipFileUtil;
|
||||
import com.keyboard.glowkeyboard.util.ItemDecoration;
|
||||
import com.keyboard.glowkeyboard.util.KeyboardServiceValidatorUtil;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
public class GlowActivity extends AppCompatActivity {
|
||||
private ActivityGlowBinding binding;
|
||||
private GlowViewModel glowViewModel;
|
||||
private GlowData glowData;
|
||||
private GlowAdapter glowAdapter;
|
||||
private int limit = 1;
|
||||
private int offset = 20;
|
||||
private String title;
|
||||
private String zipUrl;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setupFullScreen();
|
||||
bindLayout();
|
||||
adjustInsets();
|
||||
|
||||
prepareData();
|
||||
attachEvents();
|
||||
}
|
||||
|
||||
private void setupFullScreen() {
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_glow);
|
||||
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);
|
||||
}
|
||||
|
||||
private void bindLayout() {
|
||||
binding = ActivityGlowBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
private void adjustInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
|
||||
Insets systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(systemInsets.left, systemInsets.top, systemInsets.right, systemInsets.bottom);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
private void prepareData() {
|
||||
glowData = (GlowData) getIntent().getSerializableExtra("wallpaper");
|
||||
if (glowData == null || glowData.getPreview() == null) {
|
||||
displayMessage("Invalid wallpaper data!");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
glowViewModel = new ViewModelProvider(this).get(GlowViewModel.class);
|
||||
title = glowData.getTitle();
|
||||
zipUrl = glowData.getZipUrl();
|
||||
|
||||
configureRandomRange();
|
||||
setupRecyclerView();
|
||||
displayPreview();
|
||||
}
|
||||
|
||||
private void configureRandomRange() {
|
||||
Random rand = new Random();
|
||||
limit = rand.nextInt(800) + 1;
|
||||
offset = limit + 20;
|
||||
}
|
||||
|
||||
private void setupRecyclerView() {
|
||||
glowAdapter = new GlowAdapter(glowViewModel, this, new ArrayList<>(), this, 1);
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recyclerView.setAdapter(glowAdapter);
|
||||
binding.recyclerView.addItemDecoration(new ItemDecoration(20, 15, 20));
|
||||
}
|
||||
|
||||
private void displayPreview() {
|
||||
Glide.with(this)
|
||||
.load(glowData.getPreview())
|
||||
.placeholder(R.mipmap.placeholder)
|
||||
.error(R.mipmap.placeholder)
|
||||
.apply(RequestOptions.bitmapTransform(new MultiTransformation<>(new CenterCrop(), new RoundedCorners(16))))
|
||||
.into(binding.imageView);
|
||||
}
|
||||
|
||||
private void attachEvents() {
|
||||
binding.back.setOnClickListener(v -> finish());
|
||||
binding.downloadApply.setOnClickListener(v -> processDownload());
|
||||
binding.like.setOnClickListener(v -> updateFavorite());
|
||||
binding.home.setOnClickListener(v -> navigateHome());
|
||||
binding.title.setText(title);
|
||||
|
||||
refreshLikeIcon();
|
||||
loadRecommendations();
|
||||
}
|
||||
|
||||
private void processDownload() {
|
||||
toggleLoading(true);
|
||||
if (!KeyboardServiceValidatorUtil.checkAppKeyboardEnabled() || !KeyboardServiceValidatorUtil.verifyAppKeyboardActive()) {
|
||||
new RequestDialog().show(getSupportFragmentManager(), "SelectInputMethodDialog");
|
||||
toggleLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadAndUnzipFileUtil.processFileDownloadAndExtract(this, zipUrl, (success, path) -> {
|
||||
toggleLoading(false);
|
||||
if (success) {
|
||||
savePathToPrefs(path);
|
||||
displayMessage("Wallpaper applied!");
|
||||
navigateToTest();
|
||||
} else {
|
||||
displayMessage("Download failed!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void savePathToPrefs(String path) {
|
||||
SharedPreferences prefs = getSharedPreferences(MyApplication.PREF_NAME, MODE_PRIVATE);
|
||||
prefs.edit().putString(MyApplication.KEY_FILE_PATH, path).apply();
|
||||
}
|
||||
|
||||
private void loadRecommendations() {
|
||||
glowViewModel.getRecommended(limit, offset).observe(this, items -> {
|
||||
if (items != null) {
|
||||
glowAdapter.refreshData(items);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void refreshLikeIcon() {
|
||||
int icon = glowData.getFavorite() ? R.drawable.like : R.drawable.dis_like;
|
||||
binding.like.setImageResource(icon);
|
||||
}
|
||||
|
||||
private void updateFavorite() {
|
||||
glowData.setFavorite(!glowData.getFavorite());
|
||||
glowViewModel.update(glowData);
|
||||
refreshLikeIcon();
|
||||
}
|
||||
|
||||
private void navigateHome() {
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
}
|
||||
|
||||
private void navigateToTest() {
|
||||
startActivity(new Intent(this, TestActivity.class));
|
||||
}
|
||||
|
||||
private void displayMessage(String msg) {
|
||||
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void toggleLoading(boolean isVisible) {
|
||||
binding.progressBar.setVisibility(isVisible ? View.VISIBLE : View.GONE);
|
||||
binding.view.setVisibility(isVisible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.keyboard.glowkeyboard.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@ -13,6 +14,7 @@ import androidx.core.view.WindowInsetsCompat;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityCategoryListBinding;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityMainBinding;
|
||||
import com.keyboard.glowkeyboard.databinding.MainTabCustomBinding;
|
||||
import com.keyboard.glowkeyboard.ui.adapter.ViewPager2Adapter;
|
||||
@ -23,19 +25,32 @@ public class MainActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
EdgeToEdge.enable(this);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
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;
|
||||
});
|
||||
enableEdgeToEdgeDisplay();
|
||||
initializeBinding();
|
||||
setupWindowInsets();
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void enableEdgeToEdgeDisplay() {
|
||||
EdgeToEdge.enable(this);
|
||||
}
|
||||
|
||||
private void initializeBinding() {
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
private void setupWindowInsets() {
|
||||
View mainLayout = findViewById(R.id.main);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mainLayout, (view, windowInsets) -> {
|
||||
Insets bars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
view.setPadding(bars.left, bars.top, bars.right, bars.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
ViewPager2Adapter adapter = new ViewPager2Adapter(this);
|
||||
binding.viewPager2.setAdapter(adapter);
|
||||
@ -45,29 +60,29 @@ public class MainActivity extends AppCompatActivity {
|
||||
new TabLayoutMediator(binding.tabLayout, binding.viewPager2, (tab, position) -> {
|
||||
MainTabCustomBinding mainTabCustomBinding = MainTabCustomBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(mainTabCustomBinding.getRoot());
|
||||
setTab(mainTabCustomBinding, position);
|
||||
setPosition(mainTabCustomBinding, position);
|
||||
}).attach();
|
||||
|
||||
binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
updateTab(tab, true);
|
||||
updateSelect(tab, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
updateTab(tab, false);
|
||||
updateSelect(tab, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
}
|
||||
|
||||
private void updateTab(TabLayout.Tab tab, boolean isSelected) {
|
||||
private void updateSelect(TabLayout.Tab tab, boolean isSelected) {
|
||||
if (tab.getCustomView() != null) {
|
||||
MainTabCustomBinding mainTabCustomBinding = MainTabCustomBinding.bind(tab.getCustomView());
|
||||
|
||||
int iconResId = getIconResource(tab.getPosition(), isSelected);
|
||||
int iconResId = getIcon(tab.getPosition(), isSelected);
|
||||
mainTabCustomBinding.image.setImageResource(iconResId);
|
||||
|
||||
int textColor = isSelected ? R.color.black : R.color.gray;
|
||||
@ -77,8 +92,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
});
|
||||
}
|
||||
|
||||
private void setTab(MainTabCustomBinding mainCustomBinding, int position) {
|
||||
int iconResId = getIconResource(position, false);
|
||||
private void setPosition(MainTabCustomBinding mainCustomBinding, int position) {
|
||||
int iconResId = getIcon(position, false);
|
||||
int textColorResId = R.color.gray;
|
||||
|
||||
switch (position) {
|
||||
@ -96,7 +111,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
mainCustomBinding.text.setTextColor(ContextCompat.getColor(this, textColorResId));
|
||||
}
|
||||
|
||||
private int getIconResource(int position, boolean isSelected) {
|
||||
private int getIcon(int position, boolean isSelected) {
|
||||
if (position == 1) {
|
||||
return isSelected ? R.drawable.favorite : R.drawable.dis_favorite;
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.keyboard.glowkeyboard.ui.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@ -8,19 +10,76 @@ import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivitySplashBinding;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
private ActivitySplashBinding binding;
|
||||
private static final long TOTAL_TIME = 1000;
|
||||
private CountDownTimer countDownTimer;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySplashBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
EdgeToEdge.enable(this);
|
||||
setContentView(R.layout.activity_splash);
|
||||
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;
|
||||
});
|
||||
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
loadImage();
|
||||
startProgressTimer();
|
||||
}
|
||||
|
||||
private void startProgressTimer() {
|
||||
countDownTimer = new CountDownTimer(TOTAL_TIME,100) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
int percentage = (int) (100 - (float) millisUntilFinished / TOTAL_TIME * 100);
|
||||
binding.progressBar.setProgress(percentage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
startMain();
|
||||
}
|
||||
};
|
||||
|
||||
countDownTimer.start();
|
||||
}
|
||||
|
||||
private void loadImage() {
|
||||
Glide.with(this)
|
||||
.load(R.mipmap.placeholder)
|
||||
.transform(new RoundedCorners(16))
|
||||
.into(binding.splashImage);
|
||||
}
|
||||
|
||||
private void startMain() {
|
||||
binding.progressBar.setProgress(100);
|
||||
|
||||
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel();
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package com.keyboard.glowkeyboard.ui.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
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.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityMainBinding;
|
||||
import com.keyboard.glowkeyboard.databinding.ActivityTestBinding;
|
||||
|
||||
public class TestActivity extends AppCompatActivity {
|
||||
private ActivityTestBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
enableEdgeToEdgeDisplay();
|
||||
initializeBinding();
|
||||
setupWindowInsets();
|
||||
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void enableEdgeToEdgeDisplay() {
|
||||
EdgeToEdge.enable(this);
|
||||
}
|
||||
|
||||
private void initializeBinding() {
|
||||
binding = ActivityTestBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
private void setupWindowInsets() {
|
||||
View mainLayout = findViewById(R.id.main);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mainLayout, (view, windowInsets) -> {
|
||||
Insets bars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
view.setPadding(bars.left, bars.top, bars.right, bars.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
binding.back.setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
binding.editText.requestFocus();
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (imm != null) {
|
||||
imm.showSoftInput(binding.editText, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package com.keyboard.glowkeyboard.ui.adapter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
@ -14,112 +13,120 @@ 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.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
import com.keyboard.glowkeyboard.ui.activity.CategoryListActivity;
|
||||
import com.keyboard.glowkeyboard.ui.activity.GlowActivity;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GlowAdapter extends RecyclerView.Adapter<GlowAdapter.ViewHolder> {
|
||||
private final GlowViewModel glowViewModel;
|
||||
private final Context context;
|
||||
private List<GlowData> glowDataList;
|
||||
private final Activity activity;
|
||||
private final int type;
|
||||
private final GlowViewModel viewModel;
|
||||
private final Context appContext;
|
||||
private List<GlowData> dataItems;
|
||||
private final Activity hostActivity;
|
||||
private final int displayMode;
|
||||
|
||||
public GlowAdapter(GlowViewModel glowViewModel, Context context, List<GlowData> glowDataList, Activity activity, int type) {
|
||||
this.glowViewModel = glowViewModel;
|
||||
this.context = context;
|
||||
this.glowDataList = glowDataList;
|
||||
this.activity = activity;
|
||||
this.type = type;
|
||||
public GlowAdapter(GlowViewModel viewModel, Context appContext, List<GlowData> dataItems, Activity hostActivity, int displayMode) {
|
||||
this.viewModel = viewModel;
|
||||
this.appContext = appContext;
|
||||
this.dataItems = dataItems;
|
||||
this.hostActivity = hostActivity;
|
||||
this.displayMode = displayMode;
|
||||
}
|
||||
|
||||
public void updateData(List<GlowData> newWallpaperEntries) {
|
||||
this.glowDataList = newWallpaperEntries;
|
||||
public void refreshData(List<GlowData> updatedItems) {
|
||||
dataItems = updatedItems;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.item_glow, parent, false);
|
||||
return new ViewHolder(view);
|
||||
LayoutInflater inflater = LayoutInflater.from(appContext);
|
||||
View itemView = inflater.inflate(R.layout.item_glow, parent, false);
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
GlowData wallpaperEntity = glowDataList.get(position);
|
||||
holder.bind(wallpaperEntity);
|
||||
GlowData itemData = dataItems.get(position);
|
||||
holder.renderItem(itemData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return glowDataList.size();
|
||||
return dataItems.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ImageView imageView;
|
||||
private final ImageView favorite;
|
||||
private final TextView title;
|
||||
private final ImageView previewImage;
|
||||
private final ImageView likeButton;
|
||||
private final TextView captionText;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.item_image_view);
|
||||
favorite = itemView.findViewById(R.id.item_like);
|
||||
title = itemView.findViewById(R.id.item_title);
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
previewImage = view.findViewById(R.id.item_image_view);
|
||||
likeButton = view.findViewById(R.id.item_favorite);
|
||||
captionText = view.findViewById(R.id.item_title);
|
||||
}
|
||||
|
||||
public void bind(GlowData glowData) {
|
||||
String imagePath = glowData.getPreview();
|
||||
loadImage(imagePath);
|
||||
|
||||
if (type == 0) {
|
||||
title.setText(glowData.getName());
|
||||
favorite.setVisibility(View.GONE);
|
||||
} else {
|
||||
title.setText(glowData.getTitle());
|
||||
setFavoriteButton(glowData);
|
||||
public void renderItem(GlowData itemData) {
|
||||
displayPreview(itemData.getPreview());
|
||||
configureDisplayMode(itemData);
|
||||
setupInteractions(itemData);
|
||||
}
|
||||
|
||||
setClickListeners(glowData);
|
||||
}
|
||||
|
||||
private void loadImage(String imagePath) {
|
||||
Glide.with(context)
|
||||
.load(imagePath)
|
||||
.transform(new RoundedCorners(16))
|
||||
private void displayPreview(String previewUrl) {
|
||||
Glide.with(appContext)
|
||||
.load(previewUrl)
|
||||
.apply(new RequestOptions()
|
||||
.transform(new CenterCrop(), new RoundedCorners(32))
|
||||
.error(R.mipmap.placeholder)
|
||||
.placeholder(R.mipmap.placeholder)
|
||||
.into(imageView);
|
||||
.placeholder(R.mipmap.placeholder))
|
||||
.into(previewImage);
|
||||
}
|
||||
|
||||
private void setFavoriteButton(GlowData wallpaperEntity) {
|
||||
favorite.setImageResource(wallpaperEntity.getFavorite() ? R.drawable.like : R.drawable.dis_like);
|
||||
}
|
||||
|
||||
private void setClickListeners(GlowData wallpaperEntity) {
|
||||
imageView.setOnClickListener(view -> {
|
||||
Intent intent;
|
||||
if (type == 0) {
|
||||
intent = new Intent(activity, ListActivity.class);
|
||||
intent.putExtra("name", wallpaperEntity.getName());
|
||||
private void configureDisplayMode(GlowData itemData) {
|
||||
if (displayMode == 0) {
|
||||
captionText.setText(itemData.getName());
|
||||
likeButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
intent = new Intent(activity, GlowActivity.class);
|
||||
intent.putExtra("wallpaper", wallpaperEntity);
|
||||
captionText.setText(itemData.getTitle());
|
||||
updateLikeIcon(itemData.getFavorite());
|
||||
}
|
||||
activity.startActivity(intent);
|
||||
});
|
||||
|
||||
favorite.setOnClickListener(view -> toggleLike(wallpaperEntity));
|
||||
}
|
||||
|
||||
private void toggleLike(GlowData wallpaperEntity) {
|
||||
boolean newStatus = !wallpaperEntity.getFavorite();
|
||||
wallpaperEntity.setFavorite(newStatus);
|
||||
glowViewModel.update(wallpaperEntity);
|
||||
private void updateLikeIcon(boolean isFavorite) {
|
||||
int iconRes = isFavorite ? R.drawable.like : R.drawable.dis_like;
|
||||
likeButton.setImageResource(iconRes);
|
||||
}
|
||||
|
||||
private void setupInteractions(GlowData itemData) {
|
||||
previewImage.setOnClickListener(v -> launchNextScreen(itemData));
|
||||
likeButton.setOnClickListener(v -> handleLikeAction(itemData));
|
||||
}
|
||||
|
||||
private void launchNextScreen(GlowData itemData) {
|
||||
Intent navigationIntent;
|
||||
if (displayMode == 0) {
|
||||
navigationIntent = new Intent(hostActivity, CategoryListActivity.class);
|
||||
navigationIntent.putExtra("name", itemData.getName());
|
||||
} else {
|
||||
navigationIntent = new Intent(hostActivity, GlowActivity.class);
|
||||
navigationIntent.putExtra("wallpaper", itemData);
|
||||
}
|
||||
hostActivity.startActivity(navigationIntent);
|
||||
}
|
||||
|
||||
private void handleLikeAction(GlowData itemData) {
|
||||
boolean currentState = itemData.getFavorite();
|
||||
itemData.setFavorite(!currentState);
|
||||
viewModel.update(itemData);
|
||||
notifyItemChanged(getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,153 @@
|
||||
package com.keyboard.glowkeyboard.ui.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
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.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.keyboard.glowkeyboard.MyApplication;
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.RequestDialogBinding;
|
||||
import com.keyboard.glowkeyboard.util.KeyboardServiceValidatorUtil;
|
||||
|
||||
public class RequestDialog extends DialogFragment {
|
||||
private RequestDialogBinding binding;
|
||||
private InputMethodManager inputMethodManager;
|
||||
private ContentObserver contentObserver;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setCancelable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
binding = RequestDialogBinding.inflate(inflater, container, false);
|
||||
setupListeners();
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
registerInputMethodObserver();
|
||||
adjustWindowSize();
|
||||
if (getDialog() != null && getDialog().getWindow() != null) {
|
||||
getDialog().getWindow().setBackgroundDrawableResource(R.drawable.rounded_rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setupListeners() {
|
||||
inputMethodManager = (InputMethodManager) MyApplication.application.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
displayPlaceholder();
|
||||
|
||||
binding.firstSelect.setOnClickListener(v -> openSettings());
|
||||
binding.secondSelect.setOnClickListener(v -> showInputPicker());
|
||||
binding.imageView.setOnClickListener(v -> closeDialog());
|
||||
|
||||
contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
super.onChange(selfChange);
|
||||
checkAndDismiss();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void displayPlaceholder() {
|
||||
Glide.with(requireContext())
|
||||
.load(R.mipmap.placeholder)
|
||||
.apply(RequestOptions.bitmapTransform(new RoundedCorners(16)))
|
||||
.into(binding.imageView);
|
||||
}
|
||||
|
||||
private void openSettings() {
|
||||
startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
|
||||
}
|
||||
|
||||
private void showInputPicker() {
|
||||
inputMethodManager.showInputMethodPicker();
|
||||
}
|
||||
|
||||
private void closeDialog() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void registerInputMethodObserver() {
|
||||
Uri uri = Settings.Secure.getUriFor(Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
requireContext().getContentResolver().registerContentObserver(uri, false, contentObserver);
|
||||
}
|
||||
|
||||
private void adjustWindowSize() {
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog != null && dialog.getWindow() != null) {
|
||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
dialog.getWindow().setLayout((int) (metrics.widthPixels * 0.9), WindowManager.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshUI() {
|
||||
boolean isEnabled = KeyboardServiceValidatorUtil.checkAppKeyboardEnabled();
|
||||
boolean isActive = KeyboardServiceValidatorUtil.verifyAppKeyboardActive();
|
||||
|
||||
binding.firstSelect.setEnabled(!isEnabled);
|
||||
binding.firstSelect.setSelected(isEnabled);
|
||||
binding.secondSelect.setSelected(isActive);
|
||||
|
||||
if (isEnabled && isActive) {
|
||||
closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndDismiss() {
|
||||
if (KeyboardServiceValidatorUtil.checkAppKeyboardEnabled() && KeyboardServiceValidatorUtil.verifyAppKeyboardActive()) {
|
||||
closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
unregisterObserver();
|
||||
}
|
||||
|
||||
private void unregisterObserver() {
|
||||
if (contentObserver != null) {
|
||||
requireContext().getContentResolver().unregisterContentObserver(contentObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
adjustWindowSize();
|
||||
refreshUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -2,19 +2,69 @@ package com.keyboard.glowkeyboard.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.FragmentFavoriteBinding;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
import com.keyboard.glowkeyboard.ui.adapter.GlowAdapter;
|
||||
import com.keyboard.glowkeyboard.util.ItemDecoration;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoriteFragment extends Fragment {
|
||||
private FragmentFavoriteBinding binding;
|
||||
private GlowAdapter adapter;
|
||||
private GlowViewModel glowViewModel;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_favorite, container, false);
|
||||
binding = FragmentFavoriteBinding.inflate(inflater, container, false);
|
||||
initData();
|
||||
initEvent();
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
glowViewModel = new ViewModelProvider(this).get(GlowViewModel.class);
|
||||
|
||||
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
|
||||
adapter = new GlowAdapter(glowViewModel, requireContext(), new ArrayList<>(), requireActivity(), 1);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
ItemDecoration itemDecoration = new ItemDecoration(20, 15, 20);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
loadLikeList();
|
||||
}
|
||||
|
||||
private void loadLikeList() {
|
||||
glowViewModel
|
||||
.getFavorite()
|
||||
.observe(getViewLifecycleOwner(), new Observer<List<GlowData>>() {
|
||||
@Override
|
||||
public void onChanged(List<GlowData> glowDataList) {
|
||||
adapter.refreshData(glowDataList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -2,20 +2,69 @@ package com.keyboard.glowkeyboard.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.databinding.FragmentHomeBinding;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
import com.keyboard.glowkeyboard.ui.adapter.GlowAdapter;
|
||||
import com.keyboard.glowkeyboard.util.ItemDecoration;
|
||||
import com.keyboard.glowkeyboard.viewmodel.GlowViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
|
||||
private FragmentHomeBinding binding;
|
||||
private GlowAdapter adapter;
|
||||
private GlowViewModel glowViewModel;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_home, container, false);
|
||||
binding = FragmentHomeBinding.inflate(inflater, container, false);
|
||||
initData();
|
||||
initEvent();
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
glowViewModel = new ViewModelProvider(this).get(GlowViewModel.class);
|
||||
|
||||
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
|
||||
adapter = new GlowAdapter(glowViewModel, requireContext(), new ArrayList<>(), requireActivity(), 0);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
ItemDecoration itemDecoration = new ItemDecoration(20, 15, 20);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
loadFirstWallpaper();
|
||||
}
|
||||
|
||||
private void loadFirstWallpaper() {
|
||||
glowViewModel
|
||||
.getFirstCategory()
|
||||
.observe(getViewLifecycleOwner(), new Observer<List<GlowData>>() {
|
||||
@Override
|
||||
public void onChanged(List<GlowData> glowDataList) {
|
||||
adapter.refreshData(glowDataList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
package com.keyboard.glowkeyboard.ui.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 com.keyboard.glowkeyboard.util.KeyIconRendererUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GlowKeyboardView extends KeyboardView {
|
||||
private final Paint mPaint;
|
||||
private final GlowThem glowThem;
|
||||
private ShiftState shiftState = ShiftState.NORMAL;
|
||||
|
||||
private static final float TEXT_SIZE_NORMAL = 18f;
|
||||
private static final float TEXT_SIZE_LARGE = 20f;
|
||||
|
||||
public GlowKeyboardView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
glowThem = new GlowThem(context);
|
||||
mPaint = new Paint();
|
||||
mPaint.setTextSize(KeyIconRendererUtil.convertSpToPixels(TEXT_SIZE_LARGE, context));
|
||||
setPreviewEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
List<Keyboard.Key> keyList = getKeyboard().getKeys();
|
||||
for (Keyboard.Key key : keyList) {
|
||||
int code = key.codes[0];
|
||||
configurePaint(code);
|
||||
|
||||
Drawable background = fetchBackground(code);
|
||||
if (background != null) {
|
||||
renderBackground(key, background, canvas);
|
||||
}
|
||||
|
||||
renderKeyContent(key, code, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void configurePaint(int code) {
|
||||
mPaint.setColor(isSpecialKey(code) ? glowThem.getActionKeyColor() : glowThem.getNormalKeyColor());
|
||||
}
|
||||
|
||||
private boolean isSpecialKey(int code) {
|
||||
return code == Keyboard.KEYCODE_SHIFT || code == Keyboard.KEYCODE_DELETE ||
|
||||
code == Keyboard.KEYCODE_MODE_CHANGE || code == Keyboard.KEYCODE_DONE ||
|
||||
code == -1000 || code == 32;
|
||||
}
|
||||
|
||||
private Drawable fetchBackground(int code) {
|
||||
if (isSpecialKey(code)) {
|
||||
return code == 32 ? glowThem.getSpaceBackgroundDrawable() : glowThem.getActionBackgroundDrawable();
|
||||
}
|
||||
return glowThem.getNormalBackgroundDrawable();
|
||||
}
|
||||
|
||||
private Drawable selectShiftIcon() {
|
||||
switch (shiftState) {
|
||||
case NORMAL:
|
||||
return glowThem.getShiftIconDrawable();
|
||||
case CAPS:
|
||||
return glowThem.getShiftLockIconDrawable();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderBackground(Keyboard.Key key, Drawable bg, Canvas canvas) {
|
||||
if (bg != null) {
|
||||
int paddingLeft = getPaddingLeft();
|
||||
int paddingTop = getPaddingTop();
|
||||
bg.setBounds(
|
||||
key.x + paddingLeft,
|
||||
key.y + paddingTop,
|
||||
key.x + paddingLeft + key.width,
|
||||
key.y + paddingTop + key.height
|
||||
);
|
||||
bg.setState(key.getCurrentDrawableState());
|
||||
bg.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderKeyContent(Keyboard.Key key, int code, Canvas canvas) {
|
||||
switch (code) {
|
||||
case Keyboard.KEYCODE_SHIFT:
|
||||
KeyIconRendererUtil.renderKeyIcon(key, selectShiftIcon(), canvas, this);
|
||||
break;
|
||||
|
||||
case Keyboard.KEYCODE_DELETE:
|
||||
KeyIconRendererUtil.renderKeyIcon(key, glowThem.getDeleteIconDrawable(), canvas, this);
|
||||
drawLabel(key, canvas);
|
||||
break;
|
||||
|
||||
case Keyboard.KEYCODE_DONE:
|
||||
KeyIconRendererUtil.renderKeyIcon(key, glowThem.getReturnIconDrawable(), canvas, this);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
KeyIconRendererUtil.renderKeyIcon(key, glowThem.getSpaceIconDrawable(), canvas, this);
|
||||
break;
|
||||
|
||||
default:
|
||||
drawLabel(key, canvas);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLabel(Keyboard.Key key, Canvas canvas) {
|
||||
if (key.label != null && !key.label.toString().isEmpty()) {
|
||||
String labelText = key.label.toString();
|
||||
mPaint.setTextSize(KeyIconRendererUtil.convertSpToPixels(TEXT_SIZE_NORMAL, getContext()));
|
||||
float textWidth = mPaint.measureText(labelText);
|
||||
float x = key.x + getPaddingLeft() + (key.width - textWidth) / 2f;
|
||||
float y = key.y + key.height / 2f - (mPaint.descent() + mPaint.ascent()) / 2f;
|
||||
canvas.drawText(labelText, x, y, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateKeyboardView(Context context) {
|
||||
glowThem.updateBackground(context);
|
||||
setBackground(glowThem.getBackgroundDrawable());
|
||||
invalidateAllKeys();
|
||||
}
|
||||
|
||||
public enum ShiftState {
|
||||
NORMAL, CAPS
|
||||
}
|
||||
|
||||
public void setShiftState(ShiftState state) {
|
||||
this.shiftState = state;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
package com.keyboard.glowkeyboard.ui.keyboard;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.inputmethodservice.Keyboard;
|
||||
import android.inputmethodservice.KeyboardView;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
|
||||
public class GlowService extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
|
||||
private Keyboard keyboardLowercase;
|
||||
private Keyboard keyboardUppercase;
|
||||
private Keyboard keyboardSymbols;
|
||||
private Keyboard keyboardMoreSymbols;
|
||||
private Keyboard currentKeyboard;
|
||||
|
||||
private GlowKeyboardView glowKeyboardView;
|
||||
|
||||
private static final int KEYCODE_MORE_SYMBOLS = -1000;
|
||||
|
||||
@Override
|
||||
public View onCreateInputView() {
|
||||
glowKeyboardView = inflateKeyboardView();
|
||||
setupKeyboards();
|
||||
configureKeyboardView();
|
||||
return glowKeyboardView;
|
||||
}
|
||||
|
||||
private GlowKeyboardView inflateKeyboardView() {
|
||||
return (GlowKeyboardView) getLayoutInflater().inflate(R.layout.wallpaper_keyboard_view, null, false);
|
||||
}
|
||||
|
||||
private void setupKeyboards() {
|
||||
keyboardLowercase = loadKeyboard(R.xml.keyboard_lowercase);
|
||||
keyboardUppercase = loadKeyboard(R.xml.keyboard_uppercase);
|
||||
keyboardSymbols = loadKeyboard(R.xml.keyboard_symbols);
|
||||
keyboardMoreSymbols = loadKeyboard(R.xml.keyboard_more_symbols);
|
||||
currentKeyboard = keyboardLowercase;
|
||||
}
|
||||
|
||||
private Keyboard loadKeyboard(int resId) {
|
||||
return new Keyboard(this, resId);
|
||||
}
|
||||
|
||||
private void configureKeyboardView() {
|
||||
glowKeyboardView.setKeyboard(currentKeyboard);
|
||||
glowKeyboardView.setOnKeyboardActionListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowShown() {
|
||||
super.onWindowShown();
|
||||
refreshKeyboardAppearance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKey(int primaryCode, int[] keyCodes) {
|
||||
InputConnection ic = getCurrentInputConnection();
|
||||
if (ic == null) return;
|
||||
|
||||
processKeyEvent(primaryCode, ic);
|
||||
}
|
||||
|
||||
private void processKeyEvent(int code, InputConnection ic) {
|
||||
switch (code) {
|
||||
case Keyboard.KEYCODE_DELETE:
|
||||
deleteText(ic);
|
||||
break;
|
||||
|
||||
case Keyboard.KEYCODE_SHIFT:
|
||||
switchCase();
|
||||
break;
|
||||
|
||||
case Keyboard.KEYCODE_MODE_CHANGE:
|
||||
cycleKeyboardMode();
|
||||
break;
|
||||
|
||||
case Keyboard.KEYCODE_DONE:
|
||||
executeEditorAction(ic);
|
||||
break;
|
||||
|
||||
case KEYCODE_MORE_SYMBOLS:
|
||||
flipSymbolsMode();
|
||||
break;
|
||||
|
||||
default:
|
||||
insertCharacter(code, ic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteText(InputConnection ic) {
|
||||
ic.deleteSurroundingText(1, 0);
|
||||
}
|
||||
|
||||
private void switchCase() {
|
||||
if (currentKeyboard == keyboardLowercase) {
|
||||
applyKeyboard(keyboardUppercase, GlowKeyboardView.ShiftState.CAPS);
|
||||
} else if (currentKeyboard == keyboardUppercase) {
|
||||
applyKeyboard(keyboardLowercase, GlowKeyboardView.ShiftState.NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void cycleKeyboardMode() {
|
||||
if (currentKeyboard == keyboardLowercase || currentKeyboard == keyboardUppercase) {
|
||||
applyKeyboard(keyboardSymbols, null);
|
||||
} else if (currentKeyboard == keyboardSymbols || currentKeyboard == keyboardMoreSymbols) {
|
||||
applyKeyboard(keyboardLowercase, GlowKeyboardView.ShiftState.NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyKeyboard(Keyboard newKeyboard, GlowKeyboardView.ShiftState state) {
|
||||
if (currentKeyboard != newKeyboard) {
|
||||
currentKeyboard = newKeyboard;
|
||||
glowKeyboardView.setKeyboard(newKeyboard);
|
||||
if (state != null) {
|
||||
glowKeyboardView.setShiftState(state);
|
||||
}
|
||||
refreshKeyboardAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
private void executeEditorAction(InputConnection ic) {
|
||||
EditorInfo info = getCurrentInputEditorInfo();
|
||||
int action = info.imeOptions & EditorInfo.IME_MASK_ACTION;
|
||||
if (action == EditorInfo.IME_ACTION_SEARCH) {
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_SEARCH);
|
||||
} else if (action == EditorInfo.IME_ACTION_DONE) {
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_DONE);
|
||||
} else {
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
private void flipSymbolsMode() {
|
||||
applyKeyboard(currentKeyboard == keyboardSymbols ? keyboardMoreSymbols : keyboardSymbols, null);
|
||||
}
|
||||
|
||||
private void insertCharacter(int code, InputConnection ic) {
|
||||
ic.commitText(Character.toString((char) code), 1);
|
||||
}
|
||||
|
||||
private void refreshKeyboardAppearance() {
|
||||
glowKeyboardView.updateKeyboardView(this);
|
||||
glowKeyboardView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPress(int primaryCode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int primaryCode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onText(CharSequence text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeLeft() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeRight() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeDown() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swipeUp() {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,192 @@
|
||||
package com.keyboard.glowkeyboard.ui.keyboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
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.keyboard.glowkeyboard.MyApplication;
|
||||
import com.keyboard.glowkeyboard.R;
|
||||
import com.keyboard.glowkeyboard.util.DocumentFileUtils;
|
||||
import com.keyboard.glowkeyboard.util.StaticKeyboardPath;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringReader;
|
||||
|
||||
public class GlowThem {
|
||||
private Drawable actionBackgroundDrawable;
|
||||
private Drawable normalBackgroundDrawable;
|
||||
private Drawable spaceBackgroundDrawable;
|
||||
private Drawable shiftIconDrawable;
|
||||
private Drawable shiftLockIconDrawable;
|
||||
private Drawable deleteIconDrawable;
|
||||
private Drawable returnIconDrawable;
|
||||
private Drawable spaceIconDrawable;
|
||||
private Drawable backgroundDrawable;
|
||||
|
||||
private int normalKeyColor;
|
||||
private int actionKeyColor;
|
||||
|
||||
private static final String COLOR_NORMAL_KEY_TEXT = "key_text_color_normal";
|
||||
private static final String COLOR_ACTION_KEY_TEXT = "key_text_color_functional";
|
||||
|
||||
private static final int DEFAULT_SHIFT_ICON = R.drawable.shift;
|
||||
private static final int DEFAULT_SHIFT_LOCK_ICON = R.drawable.shift_lock;
|
||||
private static final int DEFAULT_DELETE_ICON = R.drawable.delete;
|
||||
private static final int DEFAULT_RETURN_ICON = R.drawable.return_back;
|
||||
private static final int DEFAULT_SPACE_ICON = R.drawable.space;
|
||||
private static final int DEFAULT_BACKGROUND_COLOR = R.color.soft_black;
|
||||
|
||||
public GlowThem(Context context) {
|
||||
initializeDrawables(context);
|
||||
initializeColors(context);
|
||||
}
|
||||
|
||||
private void initializeDrawables(Context context) {
|
||||
shiftIconDrawable = fetchDrawable(context, DEFAULT_SHIFT_ICON);
|
||||
shiftLockIconDrawable = fetchDrawable(context, DEFAULT_SHIFT_LOCK_ICON);
|
||||
deleteIconDrawable = fetchDrawable(context, DEFAULT_DELETE_ICON);
|
||||
returnIconDrawable = fetchDrawable(context, DEFAULT_RETURN_ICON);
|
||||
spaceIconDrawable = fetchDrawable(context, DEFAULT_SPACE_ICON);
|
||||
backgroundDrawable = fetchDrawable(context, DEFAULT_BACKGROUND_COLOR);
|
||||
}
|
||||
|
||||
private void initializeColors(Context context) {
|
||||
normalKeyColor = ContextCompat.getColor(context, R.color.white);
|
||||
actionKeyColor = normalKeyColor;
|
||||
}
|
||||
|
||||
private Drawable fetchDrawable(Context context, int resId) {
|
||||
return ContextCompat.getDrawable(context, resId);
|
||||
}
|
||||
|
||||
public Drawable getBackgroundDrawable() {
|
||||
return backgroundDrawable;
|
||||
}
|
||||
|
||||
public Drawable getActionBackgroundDrawable() {
|
||||
return actionBackgroundDrawable;
|
||||
}
|
||||
|
||||
public Drawable getNormalBackgroundDrawable() {
|
||||
return normalBackgroundDrawable;
|
||||
}
|
||||
|
||||
public Drawable getSpaceBackgroundDrawable() {
|
||||
return spaceBackgroundDrawable;
|
||||
}
|
||||
|
||||
public Drawable getDeleteIconDrawable() {
|
||||
return deleteIconDrawable;
|
||||
}
|
||||
|
||||
public Drawable getShiftIconDrawable() {
|
||||
return shiftIconDrawable;
|
||||
}
|
||||
|
||||
public Drawable getReturnIconDrawable() {
|
||||
return returnIconDrawable;
|
||||
}
|
||||
|
||||
public Drawable getSpaceIconDrawable() {
|
||||
return spaceIconDrawable;
|
||||
}
|
||||
|
||||
public Drawable getShiftLockIconDrawable() {
|
||||
return shiftLockIconDrawable;
|
||||
}
|
||||
|
||||
public int getNormalKeyColor() {
|
||||
return normalKeyColor;
|
||||
}
|
||||
|
||||
public int getActionKeyColor() {
|
||||
return actionKeyColor;
|
||||
}
|
||||
|
||||
public void updateBackground(Context context) {
|
||||
String wallpaperDir = retrieveWallpaperDir(context);
|
||||
if (!wallpaperDir.isEmpty()) {
|
||||
refreshKeyColors(wallpaperDir);
|
||||
updateDrawables(context, wallpaperDir);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDrawables(Context context, String dirPath) {
|
||||
backgroundDrawable = loadBackgroundImage(context, dirPath);
|
||||
normalBackgroundDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.NORMAL_KEY_BACKGROUND);
|
||||
actionBackgroundDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.ACTION_KEY_BACKGROUND);
|
||||
spaceBackgroundDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.SPACE_KEY_BACKGROUND);
|
||||
returnIconDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.RETURN_ICON);
|
||||
spaceIconDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.SPACE_ICON);
|
||||
deleteIconDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.DELETE_ICON);
|
||||
shiftIconDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.SHIFT_ICON);
|
||||
shiftLockIconDrawable = loadKeyDrawable(context, dirPath, StaticKeyboardPath.SHIFT_LOCK_ICON);
|
||||
}
|
||||
|
||||
private Drawable loadBackgroundImage(Context context, String basePath) {
|
||||
String path = basePath + "/drawable-xxhdpi-v4/keyboard_background.jpg";
|
||||
return createDrawableFromPath(context, path);
|
||||
}
|
||||
|
||||
private Drawable loadKeyDrawable(Context context, String basePath, String name) {
|
||||
String path = basePath + "/drawable-xhdpi-v4/" + name;
|
||||
return createDrawableFromPath(context, path);
|
||||
}
|
||||
|
||||
private Drawable createDrawableFromPath(Context context, String filePath) {
|
||||
File imageFile = new File(filePath);
|
||||
if (imageFile.exists()) {
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
|
||||
return new BitmapDrawable(context.getResources(), bitmap);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void refreshKeyColors(String directory) {
|
||||
File colorsFile = new File(directory + "/colors.xml");
|
||||
if (!colorsFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String xmlContent = DocumentFileUtils.readFileToString(colorsFile);
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new StringReader(xmlContent));
|
||||
|
||||
int event = parser.getEventType();
|
||||
while (event != XmlPullParser.END_DOCUMENT) {
|
||||
if (event == XmlPullParser.START_TAG && ("color".equals(parser.getName()) || "item".equals(parser.getName()))) {
|
||||
String name = parser.getAttributeValue(null, "name");
|
||||
String value = parser.nextText();
|
||||
if (value != null && !value.trim().isEmpty()) {
|
||||
parseColor(name, value);
|
||||
}
|
||||
}
|
||||
event = parser.next();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseColor(String name, String colorValue) {
|
||||
if (COLOR_NORMAL_KEY_TEXT.equals(name)) {
|
||||
normalKeyColor = Color.parseColor(colorValue);
|
||||
} else if (COLOR_ACTION_KEY_TEXT.equals(name)) {
|
||||
actionKeyColor = Color.parseColor(colorValue);
|
||||
}
|
||||
}
|
||||
|
||||
private String retrieveWallpaperDir(Context context) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(MyApplication.PREF_NAME, Context.MODE_PRIVATE);
|
||||
return prefs.getString(MyApplication.KEY_FILE_PATH, "");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.keyboard.glowkeyboard.ui.keyboard.callback;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DownloadDone {
|
||||
void onDownloadCall(boolean success, File file) throws IOException;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.keyboard.glowkeyboard.ui.keyboard.callback;
|
||||
|
||||
public interface OnDownloadUnzipDone {
|
||||
void onResult(boolean success, String resultPath);
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.keyboard.glowkeyboard.ui.keyboard.callback;
|
||||
|
||||
public interface UnzipDone {
|
||||
void onUnzipCall(boolean success, String path);
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.keyboard.glowkeyboard.util;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class DocumentFileUtils {
|
||||
public static void copyFile(File fromFile, File toFile) throws IOException {
|
||||
if (!fromFile.exists()) {
|
||||
throw new IOException("Source file does not exist: " + fromFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
File parentDir = toFile.getParentFile();
|
||||
if (parentDir != null && !parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
|
||||
boolean useModernApi = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O;
|
||||
|
||||
if (useModernApi) {
|
||||
transferFileModern(fromFile, toFile);
|
||||
} else {
|
||||
transferFileLegacy(fromFile, toFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void transferFileModern(File source, File dest) throws IOException {
|
||||
Path sourcePath = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
sourcePath = source.toPath();
|
||||
}
|
||||
Path destPath = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
destPath = dest.toPath();
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
try (InputStream input = Files.newInputStream(sourcePath);
|
||||
OutputStream output = Files.newOutputStream(destPath)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void transferFileLegacy(File source, File dest) throws IOException {
|
||||
try (FileInputStream input = new FileInputStream(source);
|
||||
FileOutputStream output = new FileOutputStream(dest)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
while ((length = input.read(buffer)) > 0) {
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String readFileToString(File file) throws IOException {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream))) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
package com.keyboard.glowkeyboard.util;
|
||||
|
||||
import android.content.Context;
|
||||
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.keyboard.glowkeyboard.ui.keyboard.callback.OnDownloadUnzipDone;
|
||||
import com.keyboard.glowkeyboard.ui.keyboard.callback.DownloadDone;
|
||||
import com.keyboard.glowkeyboard.ui.keyboard.callback.UnzipDone;
|
||||
|
||||
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 java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class DownloadAndUnzipFileUtil {
|
||||
private static final Logger LOGGER = Logger.getLogger(DownloadAndUnzipFileUtil.class.getName());
|
||||
|
||||
|
||||
public static void processFileDownloadAndExtract(Context context, String urlString, OnDownloadUnzipDone resultHandler) {
|
||||
initiateFileDownload(context, urlString, (isSuccess, downloadedFile) -> {
|
||||
if (isSuccess) {
|
||||
try {
|
||||
extractArchive(context, downloadedFile, (extractSuccess, extractLocation) ->
|
||||
resultHandler.onResult(extractSuccess, extractLocation));
|
||||
} catch (IOException exception) {
|
||||
LOGGER.log(Level.SEVERE, "Extraction failure", exception);
|
||||
resultHandler.onResult(false, null);
|
||||
}
|
||||
} else {
|
||||
resultHandler.onResult(false, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initiateFileDownload(Context context, String url, DownloadDone downloadHandler) {
|
||||
Glide.with(context)
|
||||
.asFile()
|
||||
.load(url)
|
||||
.listener(new RequestListener<File>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model,
|
||||
@NonNull Target<File> target, boolean isFirst) {
|
||||
try {
|
||||
downloadHandler.onDownloadCall(false, null);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Download callback error", ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(@NonNull File fileResource, @NonNull Object model,
|
||||
Target<File> target, @NonNull DataSource source, boolean isFirst) {
|
||||
try {
|
||||
File storageDir = getStorageDirectory(context);
|
||||
File targetDir = new File(storageDir, "DownloadedFiles");
|
||||
targetDir.mkdirs();
|
||||
|
||||
File outputFile = new File(targetDir, fileResource.getName());
|
||||
DocumentFileUtils.copyFile(fileResource, outputFile);
|
||||
|
||||
downloadHandler.onDownloadCall(true, outputFile);
|
||||
LOGGER.log(Level.INFO, "File saved: " + outputFile.getPath());
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Download processing error", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}).preload();
|
||||
}
|
||||
|
||||
private static void extractArchive(Context context, File archiveFile, UnzipDone extractHandler) throws IOException {
|
||||
if (!archiveFile.exists()) {
|
||||
Toast.makeText(context, "Archive not found", Toast.LENGTH_SHORT).show();
|
||||
extractHandler.onUnzipCall(false, null);
|
||||
return;
|
||||
}
|
||||
|
||||
File baseDir = getStorageDirectory(context);
|
||||
File extractDir = new File(baseDir, "ExtractedFiles");
|
||||
extractDir.mkdirs();
|
||||
String finalPath = "";
|
||||
|
||||
try (RandomAccessFile archiveAccess = new RandomAccessFile(archiveFile, "r");
|
||||
RandomAccessFileInStream inputArchive = new RandomAccessFileInStream(archiveAccess);
|
||||
IInArchive archive = SevenZip.openInArchive(ArchiveFormat.SEVEN_ZIP, inputArchive)) {
|
||||
|
||||
ISimpleInArchiveItem[] items = archive.getSimpleInterface().getArchiveItems();
|
||||
for (ISimpleInArchiveItem item : items) {
|
||||
File targetFile = new File(extractDir, item.getPath());
|
||||
if (item.isFolder()) {
|
||||
targetFile.mkdirs();
|
||||
} else {
|
||||
try (RandomAccessFileOutStream output = new RandomAccessFileOutStream(
|
||||
new RandomAccessFile(targetFile, "rw"))) {
|
||||
item.extractSlow(output);
|
||||
finalPath = targetFile.getPath();
|
||||
LOGGER.log(Level.INFO, "Extracted: " + finalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int resourceIndex = finalPath.indexOf("res");
|
||||
if (resourceIndex >= 0) {
|
||||
String resultPath = finalPath.substring(0, resourceIndex + 3);
|
||||
LOGGER.log(Level.INFO, "Result path: " + resultPath);
|
||||
extractHandler.onUnzipCall(true, resultPath);
|
||||
} else {
|
||||
extractHandler.onUnzipCall(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static File getStorageDirectory(Context context) {
|
||||
File dir = context.getExternalFilesDir(null);
|
||||
return dir != null ? dir : context.getFilesDir();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.keyboard.glowkeyboard.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.inputmethodservice.Keyboard;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.keyboard.glowkeyboard.ui.keyboard.GlowKeyboardView;
|
||||
|
||||
public class KeyIconRendererUtil {
|
||||
public static void renderKeyIcon(Keyboard.Key key,
|
||||
Drawable iconDrawable,
|
||||
Canvas drawingCanvas,
|
||||
GlowKeyboardView view) {
|
||||
if (key == null || iconDrawable == null || drawingCanvas == null || view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
key.icon = iconDrawable;
|
||||
Rect bounds = calculateIconBounds(key, iconDrawable, view);
|
||||
key.icon.setBounds(bounds);
|
||||
key.icon.draw(drawingCanvas);
|
||||
}
|
||||
|
||||
public static float convertSpToPixels(float sp, Context ctx) {
|
||||
if (ctx == null) {
|
||||
return 0;
|
||||
}
|
||||
DisplayMetrics metrics = ctx.getResources().getDisplayMetrics();
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics);
|
||||
}
|
||||
|
||||
private static Rect calculateIconBounds(Keyboard.Key key,
|
||||
Drawable icon,
|
||||
GlowKeyboardView view) {
|
||||
if (key == null || icon == null || view == null) {
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
float baseWidth = icon.getIntrinsicWidth();
|
||||
float baseHeight = icon.getIntrinsicHeight();
|
||||
float widthScale = baseWidth / key.width;
|
||||
float heightScale = baseHeight / key.height;
|
||||
|
||||
float scaling = Math.max(0.5f, Math.max(widthScale, heightScale));
|
||||
float finalWidth = baseWidth / scaling;
|
||||
float finalHeight = baseHeight / scaling;
|
||||
|
||||
int xOffset = (int) (key.x + view.getPaddingLeft() + (key.width - finalWidth) / 2);
|
||||
int yOffset = (int) (key.y + view.getPaddingTop() + (key.height - finalHeight) / 2);
|
||||
|
||||
return new Rect(
|
||||
xOffset,
|
||||
yOffset,
|
||||
xOffset + (int) finalWidth,
|
||||
yOffset + (int) finalHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.keyboard.glowkeyboard.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.keyboard.glowkeyboard.MyApplication;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KeyboardServiceValidatorUtil {
|
||||
private static final InputMethodManager keyboardManager =
|
||||
(InputMethodManager) MyApplication.application.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
public static boolean checkAppKeyboardEnabled() {
|
||||
if (keyboardManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<InputMethodInfo> activeMethods = keyboardManager.getEnabledInputMethodList();
|
||||
String appPackage = MyApplication.application.getPackageName();
|
||||
|
||||
for (InputMethodInfo method : activeMethods) {
|
||||
if (method.getId().contains(appPackage)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean verifyAppKeyboardActive() {
|
||||
ContentResolver resolver = MyApplication.application.getContentResolver();
|
||||
String activeMethodId = Settings.Secure.getString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
return activeMethodId != null && activeMethodId.contains(MyApplication.application.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package com.keyboard.glowkeyboard.util;
|
||||
|
||||
public class StaticKeyboardPath {
|
||||
public static String NORMAL_KEY_BACKGROUND = "btn_keyboard_key_normal_normal.9.png";
|
||||
public static String ACTION_KEY_BACKGROUND = "btn_keyboard_key_functional_normal.9.png";
|
||||
public static String SPACE_KEY_BACKGROUND = "btn_keyboard_spacekey_normal_normal.9.png";
|
||||
|
||||
public static String DELETE_ICON = "sym_keyboard_delete_normal.png";
|
||||
public static String SHIFT_ICON = "sym_keyboard_shift.png";
|
||||
public static String SHIFT_LOCK_ICON = "sym_keyboard_shift_locked.png";
|
||||
public static String RETURN_ICON = "sym_keyboard_return_normal.png";
|
||||
public static String SPACE_ICON = "sym_keyboard_space_led.9.png";
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.keyboard.glowkeyboard.room.AppDatabase;
|
||||
import com.keyboard.glowkeyboard.room.GlowData;
|
||||
@ -14,8 +15,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class GlowViewModel extends AndroidViewModel {
|
||||
private GlowDataDao glowDataDao;
|
||||
private ExecutorService executorService;
|
||||
private final GlowDataDao glowDataDao;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
public GlowViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
@ -27,4 +28,19 @@ public class GlowViewModel extends AndroidViewModel {
|
||||
executorService.execute(()-> glowDataDao.update(glowData));
|
||||
}
|
||||
|
||||
public LiveData<List<GlowData>> getFavorite() {
|
||||
return glowDataDao.getFavorite();
|
||||
}
|
||||
|
||||
public LiveData<List<GlowData>> getFirstCategory() {
|
||||
return glowDataDao.getFirstCategory();
|
||||
}
|
||||
|
||||
public LiveData<List<GlowData>> getCategory(String name) {
|
||||
return glowDataDao.getCategory(name);
|
||||
}
|
||||
|
||||
public LiveData<List<GlowData>> getRecommended(int limit, int offset) {
|
||||
return glowDataDao.getRecommended(limit, offset);
|
||||
}
|
||||
}
|
||||
|
||||
9
app/src/main/res/drawable/back.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M232.7,0h558.5a232.7,232.7 0,0 1,232.7 232.7v558.5a232.7,232.7 0,0 1,-232.7 232.7L232.7,1024a232.7,232.7 0,0 1,-232.7 -232.7L0,232.7a232.7,232.7 0,0 1,232.7 -232.7zM670.9,711.8L471.1,512l199.8,-199.8L605.1,246.4 339.5,512 605.1,777.6l65.8,-65.8z"
|
||||
android:fillColor="#606979"/>
|
||||
</vector>
|
||||
15
app/src/main/res/drawable/delete.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1025"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="@color/gray"
|
||||
android:pathData="M897.1,896H342.4c-12.8,0 -25.6,-4.3 -34.1,-12.8l-298.7,-341.3c-12.8,-17.1 -12.8,-38.4 0,-55.5l298.7,-341.3c8.5,-12.8 21.3,-17.1 34.1,-17.1h554.7c72.5,0 128,55.5 128,128v512c0,72.5 -55.5,128 -128,128zM363.7,810.7H897.1c25.6,0 42.7,-17.1 42.7,-42.7V256c0,-25.6 -17.1,-42.7 -42.7,-42.7H363.7l-260.3,298.7 260.3,298.7z"/>
|
||||
<path
|
||||
android:fillColor="@color/gray"
|
||||
android:pathData="M513.1,682.7c-12.8,0 -21.3,-4.3 -29.9,-12.8 -17.1,-17.1 -17.1,-42.7 0,-59.7l256,-256c17.1,-17.1 42.7,-17.1 59.7,0s17.1,42.7 0,59.7l-256,256c-8.5,8.5 -17.1,12.8 -29.9,12.8z"/>
|
||||
<path
|
||||
android:fillColor="@color/gray"
|
||||
android:pathData="M769.1,682.7c-12.8,0 -21.3,-4.3 -29.9,-12.8l-256,-256c-17.1,-17.1 -17.1,-42.7 0,-59.7s42.7,-17.1 59.7,0l256,256c17.1,17.1 17.1,42.7 0,59.7 -8.5,8.5 -17.1,12.8 -29.9,12.8z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/dialog_select_background.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/rounded_rectangle_select" android:state_selected="true" />
|
||||
<item android:drawable="@drawable/rounded_rectangle_un_select" android:state_selected="false" />
|
||||
</selector>
|
||||
@ -1,4 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M832,840.4L832,128c0,-17.6 -14.3,-32 -32,-32L256,96c-17.7,0 -32,14.4 -32,32v712.4a31.9,31.9 0,0 0,25.7 31.4c8.4,1.8 16.9,0 24,-4.7l201,-134a95.7,95.7 0,0 1,106.5 0l201,134A32,32 0,0 0,832 840.4zM800,32c52.9,0 96,43.1 96,96v712.4c0,52.9 -43.1,96 -96,96a95.5,95.5 0,0 1,-53.3 -16.2l-200.9,-134a32,32 0,0 0,-35.6 0l-201,134a95,95 0,0 1,-72.1 14.2,95.3 95.3,0 0,1 -61,-40.9A95.6,95.6 0,0 1,160 840.4L160,128c0,-52.9 43.1,-96 96,-96h544zM576.6,400.2l24.6,-24 -34,-4.9a32,32 0,0 1,-24.1 -17.5l-15.2,-30.7 -15.2,30.7a32,32 0,0 1,-24.1 17.5l-34,4.9 24.6,24a32,32 0,0 1,9.2 28.3l-5.8,33.8 30.4,-16a31.8,31.8 0,0 1,29.8 0l30.4,16 -5.8,-33.9a32,32 0,0 1,9.2 -28.3zM674.6,322.2a32.1,32.1 0,0 1,17.7 54.6l-59,57.5 14,81.2a32,32 0,0 1,-46.4 33.7L528,510.8l-72.9,38.3a32,32 0,1 1,-46.4 -33.7l14,-81.2 -59,-57.5a32,32 0,0 1,17.7 -54.6l81.5,-11.8 36.4,-73.8c10.7,-21.9 46.6,-21.9 57.3,0l36.5,73.8 81.5,11.8z"
|
||||
android:fillColor="@color/gray"/>
|
||||
</vector>
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M96,480c-9.6,0 -19.2,-3.2 -25.6,-12.8 -12.8,-12.8 -9.6,-35.2 3.2,-44.8l377.6,-310.4c35.2,-25.6 86.4,-25.6 118.4,0l377.6,307.2c12.8,9.6 16,32 3.2,44.8 -12.8,12.8 -32,16 -44.8,3.2L531.2,166.4c-9.6,-6.4 -28.8,-6.4 -38.4,0L115.2,473.6c-6.4,6.4 -12.8,6.4 -19.2,6.4zM816,928H608c-19.2,0 -32,-12.8 -32,-32v-150.4c0,-22.4 -38.4,-44.8 -67.2,-44.8 -28.8,0 -64,19.2 -64,44.8V896c0,19.2 -12.8,32 -32,32H211.2C163.2,928 128,892.8 128,848V544c0,-19.2 12.8,-32 32,-32s32,12.8 32,32v304c0,9.6 6.4,16 19.2,16H384v-118.4c0,-64 67.2,-108.8 128,-108.8s131.2,44.8 131.2,108.8V864h176c9.6,0 16,0 16,-19.2V544c0,-19.2 12.8,-32 32,-32s32,12.8 32,32v304C896,896 864,928 816,928z"
|
||||
android:fillColor="@color/gray"/>
|
||||
</vector>
|
||||
|
||||
12
app/src/main/res/drawable/download.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M863.2,315.8c-0.2,-1.4 -0.4,-2.6 -0.8,-4 -1.5,-5.5 -3.9,-10.6 -7.8,-14.5l-128,-128c-6,-6 -14.1,-9.4 -22.6,-9.4L320,159.9c-8.5,0 -16.6,3.4 -22.6,9.4l-128,128c-3.9,3.9 -6.3,9 -7.8,14.5 -0.4,1.4 -0.6,2.6 -0.8,4 -0.2,1.4 -0.8,2.7 -0.8,4.2l0,451.8c0,50.8 41.4,92.2 92.2,92.2l519.5,0c50.9,0 92.2,-41.4 92.2,-92.2L863.9,320C864,318.5 863.4,317.3 863.2,315.8zM333.2,224l357.5,0 64,64L269.2,288 333.2,224zM800,771.8c0,15.6 -12.7,28.2 -28.2,28.2L252.2,800c-15.6,0 -28.2,-12.7 -28.2,-28.2L224,352l576,0L800,771.8z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M489.4,726.6c6.2,6.2 14.4,9.4 22.6,9.4s16.4,-3.1 22.6,-9.4l76.8,-76.8c12.5,-12.5 12.5,-32.8 0,-45.2s-32.8,-12.5 -45.2,0L544,626.8 544,448c0,-17.7 -14.3,-32 -32,-32 -17.7,0 -32,14.3 -32,32l0,178.8 -22.2,-22.2c-12.5,-12.5 -32.8,-12.5 -45.2,0s-12.5,32.8 0,45.2L489.4,726.6z"/>
|
||||
</vector>
|
||||
@ -5,5 +5,5 @@
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M832,840.4L832,128c0,-17.6 -14.3,-32 -32,-32L256,96c-17.7,0 -32,14.4 -32,32v712.4a31.9,31.9 0,0 0,25.7 31.4c8.4,1.8 16.9,0 24,-4.7l201,-134a95.7,95.7 0,0 1,106.5 0l201,134A32,32 0,0 0,832 840.4zM800,32c52.9,0 96,43.1 96,96v712.4c0,52.9 -43.1,96 -96,96a95.5,95.5 0,0 1,-53.3 -16.2l-200.9,-134a32,32 0,0 0,-35.6 0l-201,134a95,95 0,0 1,-72.1 14.2,95.3 95.3,0 0,1 -61,-40.9A95.6,95.6 0,0 1,160 840.4L160,128c0,-52.9 43.1,-96 96,-96h544zM576.6,400.2l24.6,-24 -34,-4.9a32,32 0,0 1,-24.1 -17.5l-15.2,-30.7 -15.2,30.7a32,32 0,0 1,-24.1 17.5l-34,4.9 24.6,24a32,32 0,0 1,9.2 28.3l-5.8,33.8 30.4,-16a31.8,31.8 0,0 1,29.8 0l30.4,16 -5.8,-33.9a32,32 0,0 1,9.2 -28.3zM674.6,322.2a32.1,32.1 0,0 1,17.7 54.6l-59,57.5 14,81.2a32,32 0,0 1,-46.4 33.7L528,510.8l-72.9,38.3a32,32 0,1 1,-46.4 -33.7l14,-81.2 -59,-57.5a32,32 0,0 1,17.7 -54.6l81.5,-11.8 36.4,-73.8c10.7,-21.9 46.6,-21.9 57.3,0l36.5,73.8 81.5,11.8z"
|
||||
android:fillColor="#404853"/>
|
||||
android:fillColor="@color/black"/>
|
||||
</vector>
|
||||
|
||||
@ -5,5 +5,5 @@
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M96,480c-9.6,0 -19.2,-3.2 -25.6,-12.8 -12.8,-12.8 -9.6,-35.2 3.2,-44.8l377.6,-310.4c35.2,-25.6 86.4,-25.6 118.4,0l377.6,307.2c12.8,9.6 16,32 3.2,44.8 -12.8,12.8 -32,16 -44.8,3.2L531.2,166.4c-9.6,-6.4 -28.8,-6.4 -38.4,0L115.2,473.6c-6.4,6.4 -12.8,6.4 -19.2,6.4zM816,928H608c-19.2,0 -32,-12.8 -32,-32v-150.4c0,-22.4 -38.4,-44.8 -67.2,-44.8 -28.8,0 -64,19.2 -64,44.8V896c0,19.2 -12.8,32 -32,32H211.2C163.2,928 128,892.8 128,848V544c0,-19.2 12.8,-32 32,-32s32,12.8 32,32v304c0,9.6 6.4,16 19.2,16H384v-118.4c0,-64 67.2,-108.8 128,-108.8s131.2,44.8 131.2,108.8V864h176c9.6,0 16,0 16,-19.2V544c0,-19.2 12.8,-32 32,-32s32,12.8 32,32v304C896,896 864,928 816,928z"
|
||||
android:fillColor="#666666"/>
|
||||
android:fillColor="@color/black"/>
|
||||
</vector>
|
||||
|
||||
8
app/src/main/res/drawable/input_border.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- res/drawable/edit_text_border.xml -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gray" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/gray" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
30
app/src/main/res/drawable/progress_background_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>
|
||||
12
app/src/main/res/drawable/return_back.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="@color/gray"
|
||||
android:pathData="M224,736c-8.2,0 -16.4,-3.2 -22.6,-9.4l-128,-128c-12.4,-12.4 -12.4,-32.8 0,-45.2l128,-128c12.4,-12.4 32.8,-12.4 45.2,0 12.4,12.4 12.4,32.8 0,45.2L141.2,576l105.4,105.4c12.4,12.4 12.4,32.8 0,45.2 -6.2,6.2 -14.4,9.4 -22.6,9.4z"/>
|
||||
<path
|
||||
android:fillColor="@color/gray"
|
||||
android:pathData="M716,608H128c-17.6,0 -32,-14.4 -32,-32s14.4,-32 32,-32h588c47.8,0 93,-19.2 127.2,-54.4 34,-35 52.8,-81 52.8,-129.6v-40c0,-17.6 14.4,-32 32,-32s32,14.4 32,32v40c0,65.4 -25.2,127.4 -71,174.4 -46.2,47.4 -107.8,73.6 -173,73.6z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/rounded_rectangle_select.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?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="#9C979D" />
|
||||
<corners android:radius="16sp" />
|
||||
<stroke android:width="2dp" android:color="#9C979D" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@ -0,0 +1,9 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:angle="45"
|
||||
android:endColor="#60E8FB"
|
||||
android:startColor="#62C5D1"
|
||||
android:type="linear"
|
||||
android:useLevel="false" />
|
||||
<corners android:radius="16sp" />
|
||||
</shape>
|
||||
9
app/src/main/res/drawable/shift.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M693.3,874.7a32,32 0,0 1,4.4 63.7L693.3,938.7h-362.7a32,32 0,0 1,-4.4 -63.7l4.4,-0.3h362.7zM469.6,101.2a74.7,74.7 0,0 1,95.1 8.7l4.6,5 335.6,402.7a74.7,74.7 0,0 1,-51.2 122.2l-6.1,0.3h-122.3v96a74.7,74.7 0,0 1,-62.2 73.6l-6.3,0.8 -6.1,0.3h-277.3a74.7,74.7 0,0 1,-74.4 -68.6L298.7,736 298.6,640L176.4,640a74.7,74.7 0,0 1,-35.5 -9l-6.4,-3.8 -6,-4.5a74.7,74.7 0,0 1,-13.7 -99.7l4.1,-5.4 335.6,-402.7 4.6,-5 5,-4.6 5.4,-4.1zM520.2,155.8a10.7,10.7 0,0 0,-12.6 -2.9l-2.4,1.5 -1.4,1.4 -335.6,402.7a10.7,10.7 0,0 0,5.7 17.2l2.5,0.3L330.7,576a32,32 0,0 1,31.7 27.6l0.3,4.4v128a10.7,10.7 0,0 0,8.2 10.4l2.5,0.3h277.3a10.7,10.7 0,0 0,10.4 -8.2l0.3,-2.4v-128a32,32 0,0 1,27.6 -31.7l4.4,-0.3h154.2a10.7,10.7 0,0 0,9.5 -15.4l-1.3,-2 -335.6,-402.7z"
|
||||
android:fillColor="@color/gray"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/shift_lock.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M682.7,853.3a42.7,42.7 0,0 1,4.9 85L682.7,938.7H341.3a42.7,42.7 0,0 1,-5 -85L341.3,853.3h341.3zM469.6,101.2a74.7,74.7 0,0 1,95.1 8.7l4.6,5 335.6,402.7a74.7,74.7 0,0 1,-51.2 122.2l-6.1,0.3h-122.3v96a74.7,74.7 0,0 1,-62.2 73.6l-6.3,0.8 -6.1,0.3h-277.3a74.7,74.7 0,0 1,-74.4 -68.6L298.7,736 298.6,640H176.4a74.7,74.7 0,0 1,-35.5 -9l-6.4,-3.8 -6,-4.5a74.7,74.7 0,0 1,-13.7 -99.7l4.1,-5.4 335.6,-402.7 4.6,-5 5,-4.6 5.4,-4.1z"
|
||||
android:fillColor="@color/gray"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/space.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M955.7,358.4v238.9H68.3V358.4H-0v307.2h1024v-307.2z"/>
|
||||
</vector>
|
||||
@ -1,10 +1,41 @@
|
||||
<?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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.activity.CategoryListActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -7,4 +7,143 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.activity.GlowActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/like"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:src="@drawable/dis_like"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/download_apply"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:backgroundTint="#00BCD4"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/image_view">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/download" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Download&Apply"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recommended"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:gravity="center"
|
||||
android:text="Recommended"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/download_apply" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="Home"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recommended"
|
||||
app:layout_constraintEnd_toStartOf="@+id/home"
|
||||
app:layout_constraintTop_toTopOf="@+id/recommended" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/home"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recommended"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/recommended" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/recommended" />
|
||||
|
||||
<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:background="#80000000"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -24,7 +24,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="75dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabRippleColor="@android:color/transparent" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/view_pager2"
|
||||
|
||||
@ -7,4 +7,43 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.activity.SplashActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/splash_image"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:src="@mipmap/placeholder"
|
||||
app:layout_constraintVertical_bias="0.4"
|
||||
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="32dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
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="10dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginBottom="120dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:progressDrawable="@drawable/progress_background_color"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
44
app/src/main/res/layout/activity_test.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?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=".ui.activity.TestActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/black"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/input_border"
|
||||
android:padding="16dp"
|
||||
android:hint="Please enter text"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,49 +1,53 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView 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="wrap_content"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:padding="10dp">
|
||||
android:layout_margin="10dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_title"
|
||||
android:layout_width="wrap_content"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:padding="10dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="150dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/item_title" />
|
||||
app:layout_constraintEnd_toStartOf="@id/item_title"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_title"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:padding="8dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/item_favorite"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_like"
|
||||
android:id="@+id/item_favorite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/dis_like"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/item_title"
|
||||
app:layout_constraintEnd_toEndOf="@id/item_image_view"
|
||||
app:layout_constraintTop_toTopOf="@id/item_title" />
|
||||
|
||||
app:layout_constraintStart_toStartOf="@id/item_title"
|
||||
app:layout_constraintEnd_toEndOf="@id/item_title"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/item_title"
|
||||
android:visibility="visible" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
103
app/src/main/res/layout/request_dialog.xml
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView 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="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:src="@mipmap/placeholder"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Please select an input method"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/image_view" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/first_select"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@drawable/dialog_select_background"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/placeholder" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enable the input method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="italic" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/second_select"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="@drawable/dialog_select_background"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/first_select">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/placeholder" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select an input method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="italic" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintTop_toBottomOf="@id/second_select" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
5
app/src/main/res/layout/wallpaper_keyboard_view.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.keyboard.glowkeyboard.ui.keyboard.GlowKeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/keyboard_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
@ -1,6 +0,0 @@
|
||||
<?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="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 982 B |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 285 KiB |
@ -3,4 +3,5 @@
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="gray">#9C979D</color>
|
||||
<color name="soft_black">#0D1B2A</color>
|
||||
</resources>
|
||||
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="@mipmap/placeholder"
|
||||
android:imeSubtypeLocale="en_US"
|
||||
android:imeSubtypeMode = "keyboard"
|
||||
android:label="@string/app_name" />
|
||||
|
||||
</input-method>
|
||||
172
app/src/main/res/xml/keyboard_lowercase.xml
Normal file
@ -0,0 +1,172 @@
|
||||
<?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"
|
||||
android:keyLabel="Shift" />
|
||||
|
||||
<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"
|
||||
android:keyLabel="" />
|
||||
</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="Space" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="." />
|
||||
|
||||
<Key
|
||||
android:codes="-4"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="Done" />
|
||||
</Row>
|
||||
|
||||
</Keyboard>
|
||||
185
app/src/main/res/xml/keyboard_more_symbols.xml
Normal file
@ -0,0 +1,185 @@
|
||||
<?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"
|
||||
android:rowEdgeFlags="top">
|
||||
<Key
|
||||
android:codes="126"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="~" />
|
||||
|
||||
<Key
|
||||
android:codes="96"
|
||||
android:keyLabel="`" />
|
||||
|
||||
<Key
|
||||
android:codes="124"
|
||||
android:keyLabel="|" />
|
||||
|
||||
<Key
|
||||
android:codes="149"
|
||||
android:keyLabel="•" />
|
||||
|
||||
<Key
|
||||
android:codes="10004"
|
||||
android:keyLabel="✔" />
|
||||
|
||||
<Key
|
||||
android:codes="960"
|
||||
android:keyLabel="π" />
|
||||
|
||||
<Key
|
||||
android:codes="247"
|
||||
android:keyLabel="÷" />
|
||||
|
||||
<Key
|
||||
android:codes="215"
|
||||
android:keyLabel="×" />
|
||||
|
||||
<Key
|
||||
android:codes="182"
|
||||
android:keyLabel="¶" />
|
||||
|
||||
<Key
|
||||
android:codes="8710"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="∆" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.444444%"
|
||||
android:keyHeight="50dp">
|
||||
<Key
|
||||
android:codes="163"
|
||||
android:horizontalGap="5.5%"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="£" />
|
||||
|
||||
<Key
|
||||
android:codes="65504"
|
||||
android:keyLabel="¢" />
|
||||
|
||||
<Key
|
||||
android:codes="8364"
|
||||
android:keyLabel="€" />
|
||||
|
||||
<Key
|
||||
android:codes="165"
|
||||
android:keyLabel="¥" />
|
||||
|
||||
<Key
|
||||
android:codes="94"
|
||||
android:keyLabel="^" />
|
||||
|
||||
<Key
|
||||
android:codes="176"
|
||||
android:keyLabel="°" />
|
||||
|
||||
<Key
|
||||
android:codes="61"
|
||||
android:keyLabel="=" />
|
||||
|
||||
<Key
|
||||
android:codes="123"
|
||||
android:keyLabel="{" />
|
||||
|
||||
<Key
|
||||
android:codes="125"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="}" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.5%"
|
||||
android:keyHeight="50dp">
|
||||
|
||||
<Key
|
||||
android:codes="-1000"
|
||||
android:isModifier="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="\?123" />
|
||||
|
||||
<Key
|
||||
android:codes="92"
|
||||
android:keyLabel="\\" />
|
||||
|
||||
<Key
|
||||
android:codes="9400"
|
||||
android:keyLabel="Ⓒ" />
|
||||
|
||||
<Key
|
||||
android:codes="174"
|
||||
android:keyLabel="®" />
|
||||
|
||||
<Key
|
||||
android:codes="8482"
|
||||
android:keyLabel="™" />
|
||||
|
||||
<Key
|
||||
android:codes="8453"
|
||||
android:keyLabel="℅" />
|
||||
|
||||
<Key
|
||||
android:codes="91"
|
||||
android:keyLabel="[" />
|
||||
|
||||
<Key
|
||||
android:codes="93"
|
||||
android:keyLabel="]" />
|
||||
|
||||
<Key
|
||||
android:codes="-5"
|
||||
android:isModifier="true"
|
||||
android:isRepeatable="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyLabel=""
|
||||
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="ABC" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="," />
|
||||
|
||||
<Key
|
||||
android:codes="60"
|
||||
android:keyLabel="<" />
|
||||
|
||||
<Key
|
||||
android:codes="32"
|
||||
android:keyWidth="29.5%"
|
||||
android:keyLabel="Space" />
|
||||
|
||||
<Key
|
||||
android:codes="62"
|
||||
android:keyLabel=">" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="." />
|
||||
|
||||
<Key
|
||||
android:codes="-4"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="Done" />
|
||||
</Row>
|
||||
|
||||
</Keyboard>
|
||||
185
app/src/main/res/xml/keyboard_symbols.xml
Normal file
@ -0,0 +1,185 @@
|
||||
<?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"
|
||||
android:rowEdgeFlags="top">
|
||||
<Key
|
||||
android:codes="49"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="1" />
|
||||
|
||||
<Key
|
||||
android:codes="50"
|
||||
android:keyLabel="2" />
|
||||
|
||||
<Key
|
||||
android:codes="51"
|
||||
android:keyLabel="3" />
|
||||
|
||||
<Key
|
||||
android:codes="52"
|
||||
android:keyLabel="4" />
|
||||
|
||||
<Key
|
||||
android:codes="53"
|
||||
android:keyLabel="5" />
|
||||
|
||||
<Key
|
||||
android:codes="54"
|
||||
android:keyLabel="6" />
|
||||
|
||||
<Key
|
||||
android:codes="55"
|
||||
android:keyLabel="7" />
|
||||
|
||||
<Key
|
||||
android:codes="56"
|
||||
android:keyLabel="8" />
|
||||
|
||||
<Key
|
||||
android:codes="57"
|
||||
android:keyLabel="9" />
|
||||
|
||||
<Key
|
||||
android:codes="48"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="0" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.444444%"
|
||||
android:keyHeight="50dp">
|
||||
<Key
|
||||
android:codes="64"
|
||||
android:horizontalGap="5.5%"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="\@" />
|
||||
|
||||
<Key
|
||||
android:codes="35"
|
||||
android:keyLabel="#" />
|
||||
|
||||
<Key
|
||||
android:codes="36"
|
||||
android:keyLabel="\$" />
|
||||
|
||||
<Key
|
||||
android:codes="37"
|
||||
android:keyLabel="%" />
|
||||
|
||||
<Key
|
||||
android:codes="38"
|
||||
android:keyLabel="&" />
|
||||
|
||||
<Key
|
||||
android:codes="45"
|
||||
android:keyLabel="-" />
|
||||
|
||||
<Key
|
||||
android:codes="43"
|
||||
android:keyLabel="+" />
|
||||
|
||||
<Key
|
||||
android:codes="40"
|
||||
android:keyLabel="(" />
|
||||
|
||||
<Key
|
||||
android:codes="41"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel=")" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.5%"
|
||||
android:keyHeight="50dp">
|
||||
|
||||
<Key
|
||||
android:codes="-1000"
|
||||
android:isModifier="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="more" />
|
||||
|
||||
<Key
|
||||
android:codes="42"
|
||||
android:keyLabel="*" />
|
||||
|
||||
|
||||
<Key
|
||||
android:codes="34"
|
||||
android:keyLabel=""" />
|
||||
|
||||
<Key
|
||||
android:codes="39"
|
||||
android:keyLabel="'" />
|
||||
|
||||
<Key
|
||||
android:codes="58"
|
||||
android:keyLabel=":" />
|
||||
|
||||
<Key
|
||||
android:codes="59"
|
||||
android:keyLabel=";" />
|
||||
|
||||
<Key
|
||||
android:codes="33"
|
||||
android:keyLabel="!" />
|
||||
|
||||
<Key
|
||||
android:codes="63"
|
||||
android:keyLabel="\?" />
|
||||
|
||||
<Key
|
||||
android:codes="-5"
|
||||
android:isModifier="true"
|
||||
android:isRepeatable="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="" />
|
||||
</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="ABC" />
|
||||
|
||||
<Key
|
||||
android:codes="44"
|
||||
android:keyLabel="," />
|
||||
|
||||
<Key
|
||||
android:codes="95"
|
||||
android:keyLabel="_" />
|
||||
<Key
|
||||
android:codes="32"
|
||||
android:keyWidth="29.5%"
|
||||
android:keyLabel="Space" />
|
||||
|
||||
<Key
|
||||
android:codes="47"
|
||||
android:keyLabel="/" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="." />
|
||||
|
||||
<Key
|
||||
android:codes="-4"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="Done" />
|
||||
</Row>
|
||||
|
||||
</Keyboard>
|
||||
177
app/src/main/res/xml/keyboard_uppercase.xml
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:keyHeight="50dp">
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.45%"
|
||||
android:keyHeight="50dp"
|
||||
android:rowEdgeFlags="top">
|
||||
<Key
|
||||
android:codes="81"
|
||||
android:keyEdgeFlags="left"
|
||||
android:keyLabel="Q" />
|
||||
|
||||
<Key
|
||||
android:codes="87"
|
||||
android:keyLabel="W" />
|
||||
|
||||
<Key
|
||||
android:codes="69"
|
||||
android:keyLabel="E" />
|
||||
|
||||
<Key
|
||||
android:codes="82"
|
||||
android:keyLabel="R" />
|
||||
|
||||
<Key
|
||||
android:codes="84"
|
||||
android:keyLabel="T" />
|
||||
|
||||
<Key
|
||||
android:codes="89"
|
||||
android:keyLabel="Y" />
|
||||
|
||||
<Key
|
||||
android:codes="85"
|
||||
android:keyLabel="U" />
|
||||
|
||||
<Key
|
||||
android:codes="73"
|
||||
android:keyLabel="I" />
|
||||
|
||||
<Key
|
||||
android:codes="79"
|
||||
android:keyLabel="O" />
|
||||
|
||||
<Key
|
||||
android:codes="80"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="P" />
|
||||
</Row>
|
||||
|
||||
<Row
|
||||
android:horizontalGap="0.5%"
|
||||
android:keyWidth="9.444444%"
|
||||
android:keyHeight="50dp">
|
||||
<Key
|
||||
android:codes="65"
|
||||
android:horizontalGap="5.5%"
|
||||
android:keyLabel="A" />
|
||||
|
||||
<Key
|
||||
android:codes="83"
|
||||
android:keyLabel="S" />
|
||||
|
||||
<Key
|
||||
android:codes="68"
|
||||
android:keyLabel="D" />
|
||||
|
||||
<Key
|
||||
android:codes="70"
|
||||
android:keyLabel="F" />
|
||||
|
||||
<Key
|
||||
android:codes="71"
|
||||
android:keyLabel="G" />
|
||||
|
||||
<Key
|
||||
android:codes="72"
|
||||
android:keyLabel="H" />
|
||||
|
||||
<Key
|
||||
android:codes="74"
|
||||
android:keyLabel="J" />
|
||||
|
||||
<Key
|
||||
android:codes="75"
|
||||
android:keyLabel="K" />
|
||||
|
||||
<Key
|
||||
android:codes="76"
|
||||
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"
|
||||
android:keyLabel="Shift" />
|
||||
|
||||
<Key
|
||||
android:codes="90"
|
||||
android:keyLabel="Z" />
|
||||
|
||||
<Key
|
||||
android:codes="88"
|
||||
android:keyLabel="X" />
|
||||
|
||||
<Key
|
||||
android:codes="67"
|
||||
android:keyLabel="C" />
|
||||
|
||||
<Key
|
||||
android:codes="86"
|
||||
android:keyLabel="V" />
|
||||
|
||||
<Key
|
||||
android:codes="66"
|
||||
android:keyLabel="B" />
|
||||
|
||||
<Key
|
||||
android:codes="78"
|
||||
android:keyLabel="N" />
|
||||
|
||||
<Key
|
||||
android:codes="77"
|
||||
android:keyLabel="M" />
|
||||
|
||||
<Key
|
||||
android:codes="-5"
|
||||
android:isModifier="true"
|
||||
android:isRepeatable="true"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="" />
|
||||
</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="Space" />
|
||||
|
||||
<Key
|
||||
android:codes="46"
|
||||
android:keyLabel="." />
|
||||
|
||||
<Key
|
||||
android:codes="-4"
|
||||
android:keyWidth="14.25%"
|
||||
android:keyEdgeFlags="right"
|
||||
android:keyLabel="Done" />
|
||||
</Row>
|
||||
|
||||
|
||||
</Keyboard>
|
||||
@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.9.0"
|
||||
agp = "8.9.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
|
||||
6
keystore.properties
Normal file
@ -0,0 +1,6 @@
|
||||
app_name=Glow Keyboard
|
||||
package_name=com.keyboard.glowkeyboard
|
||||
keystoreFile=app/GlowKeyboard.jks
|
||||
key_alias=GlowKeyboardkey0
|
||||
key_store_password=GlowKeyboard
|
||||
key_password=GlowKeyboard
|
||||