Upgrade project to new Android Studio template and migrate Java code to Kotlin (#3937)
### Summary - Updated the project structure using the latest Android Studio template. - Migrated portions of the codebase from Java to Kotlin for improved readability and maintainability. ### Details - Refactored and reorganized files according to the new Android Studio project template to ensure compatibility with the latest project standards. - Migrated key Java classes to Kotlin, adopting Kotlin idioms and improving type safety. - Verified that core functionalities remain intact after migration and update. - Removed redundant Java files and updated imports where necessary. ### Notes - Further Kotlin migration may be needed as additional Java files are reviewed. - Test thoroughly to confirm that all functionalities work as expected after these changes.
This commit is contained in:
1 parent
bbf0b05b49
commit
18c0143186
104 files changed
+490
-542
No files matched your search
@@ -1,11 +1,11 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.v2ray.ang"
|
||||
compileSdk = 34
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.v2ray.ang"
|
||||
@@ -14,6 +14,7 @@ android {
|
||||
versionCode = 612
|
||||
versionName = "1.9.16"
|
||||
multiDexEnabled = true
|
||||
|
||||
splits {
|
||||
abi {
|
||||
isEnable = true
|
||||
@@ -27,20 +28,16 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
|
||||
}
|
||||
debug {
|
||||
isMinifyEnabled = false
|
||||
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +47,13 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
@@ -69,7 +71,8 @@ android {
|
||||
|
||||
output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk"
|
||||
if (versionCodes.containsKey(abi)) {
|
||||
output.versionCodeOverride = (1000000 * versionCodes[abi]!!).plus(variant.versionCode)
|
||||
output.versionCodeOverride =
|
||||
(1000000 * versionCodes[abi]!!).plus(variant.versionCode)
|
||||
} else {
|
||||
return@forEach
|
||||
}
|
||||
@@ -86,49 +89,60 @@ android {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Core Libraries
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar", "*.jar"))))
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.org.mockito.mockito.inline)
|
||||
testImplementation(libs.mockito.kotlin)
|
||||
|
||||
implementation(libs.flexbox)
|
||||
// Androidx
|
||||
implementation(libs.constraintlayout)
|
||||
implementation(libs.legacy.support.v4)
|
||||
implementation(libs.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation(libs.cardview)
|
||||
// AndroidX Core Libraries
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.activity)
|
||||
implementation(libs.androidx.constraintlayout)
|
||||
implementation(libs.preference.ktx)
|
||||
implementation(libs.recyclerview)
|
||||
implementation(libs.fragment.ktx)
|
||||
implementation(libs.multidex)
|
||||
implementation(libs.viewpager2)
|
||||
|
||||
// Androidx ktx
|
||||
implementation(libs.activity.ktx)
|
||||
// UI Libraries
|
||||
implementation(libs.material)
|
||||
implementation(libs.toastcompat)
|
||||
implementation(libs.editorkit)
|
||||
implementation(libs.flexbox)
|
||||
|
||||
// Data and Storage Libraries
|
||||
implementation(libs.mmkv.static)
|
||||
implementation(libs.gson)
|
||||
|
||||
// Reactive and Utility Libraries
|
||||
implementation(libs.rxjava)
|
||||
implementation(libs.rxandroid)
|
||||
implementation(libs.rxpermissions)
|
||||
|
||||
// Language and Processing Libraries
|
||||
implementation(libs.language.base)
|
||||
implementation(libs.language.json)
|
||||
|
||||
// Intent and Utility Libraries
|
||||
implementation(libs.quickie.bundled)
|
||||
implementation(libs.core)
|
||||
|
||||
// AndroidX Lifecycle and Architecture Components
|
||||
implementation(libs.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.lifecycle.livedata.ktx)
|
||||
implementation(libs.lifecycle.runtime.ktx)
|
||||
|
||||
//kotlin
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
|
||||
implementation(libs.mmkv.static)
|
||||
implementation(libs.gson)
|
||||
implementation(libs.rxjava)
|
||||
implementation(libs.rxandroid)
|
||||
implementation(libs.rxpermissions)
|
||||
implementation(libs.toastcompat)
|
||||
implementation(libs.editorkit)
|
||||
implementation(libs.language.base)
|
||||
implementation(libs.language.json)
|
||||
implementation(libs.quickie.bundled)
|
||||
implementation(libs.core)
|
||||
// Background Task Libraries
|
||||
implementation(libs.work.runtime.ktx)
|
||||
implementation(libs.work.multiprocess)
|
||||
|
||||
// Multidex Support
|
||||
implementation(libs.multidex)
|
||||
|
||||
// Testing Libraries
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
testImplementation(libs.org.mockito.mockito.inline)
|
||||
testImplementation(libs.mockito.kotlin)
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+16
-21
@@ -13,46 +13,41 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.v2ray.ang.helper;
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
package com.v2ray.ang.helper
|
||||
|
||||
/**
|
||||
* Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
|
||||
* Interface to listen for a move or dismissal event from a [ItemTouchHelper.Callback].
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public interface ItemTouchHelperAdapter {
|
||||
|
||||
interface ItemTouchHelperAdapter {
|
||||
/**
|
||||
* Called when an item has been dragged far enough to trigger a move. This is called every time
|
||||
* an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
|
||||
* an item is shifted, and **not** at the end of a "drop" event.<br></br>
|
||||
* <br></br>
|
||||
* Implementations should call [RecyclerView.Adapter.notifyItemMoved] after
|
||||
* adjusting the underlying data to reflect this move.
|
||||
*
|
||||
* @param fromPosition The start position of the moved item.
|
||||
* @param toPosition Then resolved position of the moved item.
|
||||
* @return True if the item was moved to the new adapter position.
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
* @see RecyclerView.getAdapterPositionFor
|
||||
* @see RecyclerView.ViewHolder.getAdapterPosition
|
||||
*/
|
||||
boolean onItemMove(int fromPosition, int toPosition);
|
||||
fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
|
||||
|
||||
|
||||
void onItemMoveCompleted();
|
||||
fun onItemMoveCompleted()
|
||||
|
||||
/**
|
||||
* Called when an item has been dismissed by a swipe.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
|
||||
* Called when an item has been dismissed by a swipe.<br></br>
|
||||
* <br></br>
|
||||
* Implementations should call [RecyclerView.Adapter.notifyItemRemoved] after
|
||||
* adjusting the underlying data to reflect this removal.
|
||||
*
|
||||
* @param position The position of the item dismissed.
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
* @see RecyclerView.getAdapterPositionFor
|
||||
* @see RecyclerView.ViewHolder.getAdapterPosition
|
||||
*/
|
||||
void onItemDismiss(int position);
|
||||
fun onItemDismiss(position: Int)
|
||||
}
|
||||
+8
-11
@@ -13,29 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.v2ray.ang.helper
|
||||
|
||||
package com.v2ray.ang.helper;
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
|
||||
/**
|
||||
* Interface to notify an item ViewHolder of relevant callbacks from {@link
|
||||
* ItemTouchHelper.Callback}.
|
||||
* Interface to notify an item ViewHolder of relevant callbacks from [ ].
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public interface ItemTouchHelperViewHolder {
|
||||
|
||||
interface ItemTouchHelperViewHolder {
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
|
||||
* Called when the [ItemTouchHelper] first registers an item as being moved or swiped.
|
||||
* Implementations should update the item view to indicate it's active state.
|
||||
*/
|
||||
void onItemSelected();
|
||||
fun onItemSelected()
|
||||
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
|
||||
* Called when the [ItemTouchHelper] has completed the move or swipe, and the active item
|
||||
* state should be cleared.
|
||||
*/
|
||||
void onItemClear();
|
||||
fun onItemClear()
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Paul Burke
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.v2ray.ang.helper;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
|
||||
* swipe-to-dismiss. Drag events are automatically started by an item long-press.<br/>
|
||||
* </br/>
|
||||
* Expects the <code>RecyclerView.Adapter</code> to listen for {@link
|
||||
* ItemTouchHelperAdapter} callbacks and the <code>RecyclerView.ViewHolder</code> to implement
|
||||
* {@link ItemTouchHelperViewHolder}.
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
private static final float ALPHA_FULL = 1.0f;
|
||||
private static final float SWIPE_THRESHOLD = 0.25f;
|
||||
private static final long ANIMATION_DURATION = 200;
|
||||
|
||||
private final ItemTouchHelperAdapter mAdapter;
|
||||
private ValueAnimator mReturnAnimator;
|
||||
|
||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
|
||||
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||
return makeMovementFlags(dragFlags, swipeFlags);
|
||||
} else {
|
||||
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||
return makeMovementFlags(dragFlags, swipeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull RecyclerView.ViewHolder target) {
|
||||
if (source.getItemViewType() != target.getItemViewType()) {
|
||||
return false;
|
||||
}
|
||||
mAdapter.onItemMove(source.getBindingAdapterPosition(), target.getBindingAdapterPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
// 不执行删除操作,仅返回项目到原位
|
||||
returnViewToOriginalPosition(viewHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
float maxSwipeDistance = viewHolder.itemView.getWidth() * SWIPE_THRESHOLD;
|
||||
float swipeAmount = Math.abs(dX);
|
||||
float direction = Math.signum(dX);
|
||||
|
||||
// 限制最大滑动距离
|
||||
float translationX = Math.min(swipeAmount, maxSwipeDistance) * direction;
|
||||
float alpha = ALPHA_FULL - Math.min(swipeAmount, maxSwipeDistance) / maxSwipeDistance;
|
||||
|
||||
viewHolder.itemView.setTranslationX(translationX);
|
||||
viewHolder.itemView.setAlpha(alpha);
|
||||
|
||||
if (swipeAmount >= maxSwipeDistance && isCurrentlyActive) {
|
||||
returnViewToOriginalPosition(viewHolder);
|
||||
}
|
||||
} else {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
}
|
||||
}
|
||||
|
||||
private void returnViewToOriginalPosition(RecyclerView.ViewHolder viewHolder) {
|
||||
if (mReturnAnimator != null && mReturnAnimator.isRunning()) {
|
||||
mReturnAnimator.cancel();
|
||||
}
|
||||
|
||||
mReturnAnimator = ValueAnimator.ofFloat(viewHolder.itemView.getTranslationX(), 0f);
|
||||
mReturnAnimator.addUpdateListener(animation -> {
|
||||
float value = (float) animation.getAnimatedValue();
|
||||
viewHolder.itemView.setTranslationX(value);
|
||||
viewHolder.itemView.setAlpha(1f - Math.abs(value) / (viewHolder.itemView.getWidth() * SWIPE_THRESHOLD));
|
||||
});
|
||||
mReturnAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
mReturnAnimator.setDuration(ANIMATION_DURATION);
|
||||
mReturnAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
||||
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemSelected();
|
||||
}
|
||||
}
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
viewHolder.itemView.setAlpha(ALPHA_FULL);
|
||||
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
||||
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemClear();
|
||||
}
|
||||
mAdapter.onItemMoveCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
return 1.1f; // 设置一个大于1的值,确保不会触发默认的滑动删除操作
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSwipeEscapeVelocity(float defaultValue) {
|
||||
return defaultValue * 10; // 增加滑动逃逸速度,使得更难触发滑动
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Paul Burke
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.v2ray.ang.helper
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener
|
||||
import android.graphics.Canvas
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
|
||||
/**
|
||||
* An implementation of [ItemTouchHelper.Callback] that enables basic drag & drop and
|
||||
* swipe-to-dismiss. Drag events are automatically started by an item long-press.<br></br>
|
||||
*
|
||||
* Expects the `RecyclerView.Adapter` to listen for [ ] callbacks and the `RecyclerView.ViewHolder` to implement
|
||||
* [ItemTouchHelperViewHolder].
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
class SimpleItemTouchHelperCallback(private val mAdapter: ItemTouchHelperAdapter) : ItemTouchHelper.Callback() {
|
||||
private var mReturnAnimator: ValueAnimator? = null
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean = true
|
||||
|
||||
override fun isItemViewSwipeEnabled(): Boolean = true
|
||||
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
val dragFlags: Int
|
||||
val swipeFlags: Int
|
||||
if (recyclerView.layoutManager is GridLayoutManager) {
|
||||
dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
||||
swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
|
||||
} else {
|
||||
dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||
swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
|
||||
}
|
||||
return makeMovementFlags(dragFlags, swipeFlags)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
source: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
return if (source.itemViewType != target.itemViewType) {
|
||||
false
|
||||
} else {
|
||||
mAdapter.onItemMove(source.bindingAdapterPosition, target.bindingAdapterPosition)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// Do not delete; simply return item to original position
|
||||
returnViewToOriginalPosition(viewHolder)
|
||||
}
|
||||
|
||||
override fun onChildDraw(
|
||||
c: Canvas, recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean
|
||||
) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
val maxSwipeDistance = viewHolder.itemView.width * SWIPE_THRESHOLD
|
||||
val swipeAmount = abs(dX)
|
||||
val direction = sign(dX)
|
||||
|
||||
// Limit maximum swipe distance
|
||||
val translationX = min(swipeAmount, maxSwipeDistance) * direction
|
||||
val alpha = ALPHA_FULL - min(swipeAmount, maxSwipeDistance) / maxSwipeDistance
|
||||
|
||||
viewHolder.itemView.translationX = translationX
|
||||
viewHolder.itemView.alpha = alpha
|
||||
|
||||
if (swipeAmount >= maxSwipeDistance && isCurrentlyActive) {
|
||||
returnViewToOriginalPosition(viewHolder)
|
||||
}
|
||||
} else {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnViewToOriginalPosition(viewHolder: RecyclerView.ViewHolder) {
|
||||
mReturnAnimator?.takeIf { it.isRunning }?.cancel()
|
||||
|
||||
mReturnAnimator = ValueAnimator.ofFloat(viewHolder.itemView.translationX, 0f).apply {
|
||||
addUpdateListener { animation ->
|
||||
val value = animation.animatedValue as Float
|
||||
viewHolder.itemView.translationX = value
|
||||
viewHolder.itemView.alpha = (1f - abs(value) / (viewHolder.itemView.width * SWIPE_THRESHOLD))
|
||||
}
|
||||
interpolator = DecelerateInterpolator()
|
||||
duration = ANIMATION_DURATION
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder is ItemTouchHelperViewHolder) {
|
||||
viewHolder.onItemSelected()
|
||||
}
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
viewHolder.itemView.alpha = ALPHA_FULL
|
||||
if (viewHolder is ItemTouchHelperViewHolder) {
|
||||
viewHolder.onItemClear()
|
||||
}
|
||||
mAdapter.onItemMoveCompleted()
|
||||
}
|
||||
|
||||
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
|
||||
return 1.1f // Set a value greater than 1 to prevent default swipe delete
|
||||
}
|
||||
|
||||
override fun getSwipeEscapeVelocity(defaultValue: Float): Float {
|
||||
return defaultValue * 10 // Increase swipe escape velocity to make swipe harder to trigger
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ALPHA_FULL = 1.0f
|
||||
private const val SWIPE_THRESHOLD = 0.25f
|
||||
private const val ANIMATION_DURATION: Long = 200
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-5
@@ -13,13 +13,11 @@ object AppManagerUtil {
|
||||
val apps = ArrayList<AppInfo>()
|
||||
|
||||
for (pkg in packages) {
|
||||
//if (!pkg.hasInternetPermission && pkg.packageName != "android") continue
|
||||
|
||||
val applicationInfo = pkg.applicationInfo
|
||||
val applicationInfo = pkg.applicationInfo ?: continue
|
||||
|
||||
val appName = applicationInfo.loadLabel(packageManager).toString()
|
||||
val appIcon = applicationInfo.loadIcon(packageManager)
|
||||
val isSystemApp = applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM > 0
|
||||
val appIcon = applicationInfo.loadIcon(packageManager) ?: continue
|
||||
val isSystemApp = (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) > 0
|
||||
|
||||
val appInfo = AppInfo(appName, pkg.packageName, appIcon, isSystemApp, 0)
|
||||
apps.add(appInfo)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,47 @@
|
||||
package com.v2ray.ang
|
||||
|
||||
import com.v2ray.ang.util.Utils
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class AngUnitTest {
|
||||
|
||||
@Test
|
||||
fun test_parseInt() {
|
||||
assertEquals(Utils.parseInt("1234"), 1234)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_isIpAddress() {
|
||||
assertFalse(Utils.isIpAddress("114.113.112.266"))
|
||||
assertFalse(Utils.isIpAddress("666.666.666.666"))
|
||||
assertFalse(Utils.isIpAddress("256.0.0.0"))
|
||||
assertFalse(Utils.isIpAddress("::ffff:127.0.0.0.1"))
|
||||
assertFalse(Utils.isIpAddress("baidu.com"))
|
||||
assertFalse(Utils.isIpAddress(""))
|
||||
|
||||
assertTrue(Utils.isIpAddress("127.0.0.1"))
|
||||
assertTrue(Utils.isIpAddress("127.0.0.1:80"))
|
||||
assertTrue(Utils.isIpAddress("0.0.0.0/0"))
|
||||
assertTrue(Utils.isIpAddress("::1"))
|
||||
assertTrue(Utils.isIpAddress("[::1]:80"))
|
||||
assertTrue(Utils.isIpAddress("2605:2700:0:3::4713:93e3"))
|
||||
assertTrue(Utils.isIpAddress("[2605:2700:0:3::4713:93e3]:80"))
|
||||
assertTrue(Utils.isIpAddress("::ffff:192.168.173.22"))
|
||||
assertTrue(Utils.isIpAddress("[::ffff:192.168.173.22]:80"))
|
||||
assertTrue(Utils.isIpAddress("1::"))
|
||||
assertTrue(Utils.isIpAddress("::"))
|
||||
assertTrue(Utils.isIpAddress("::/0"))
|
||||
assertTrue(Utils.isIpAddress("10.24.56.0/24"))
|
||||
assertTrue(Utils.isIpAddress("2001:4321::1"))
|
||||
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::6666"))
|
||||
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::/64"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.v2ray.ang;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* To work on unit tests, switch the Test Artifact in the Build Variants view.
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
import com.v2ray.ang.util.Utils
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class UtilTest {
|
||||
|
||||
@Test
|
||||
fun test_parseInt() {
|
||||
assertEquals(Utils.parseInt("1234"), 1234)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_isIpAddress() {
|
||||
assertFalse(Utils.isIpAddress("114.113.112.266"))
|
||||
assertFalse(Utils.isIpAddress("666.666.666.666"))
|
||||
assertFalse(Utils.isIpAddress("256.0.0.0"))
|
||||
assertFalse(Utils.isIpAddress("::ffff:127.0.0.0.1"))
|
||||
assertFalse(Utils.isIpAddress("baidu.com"))
|
||||
assertFalse(Utils.isIpAddress(""))
|
||||
|
||||
assertTrue(Utils.isIpAddress("127.0.0.1"))
|
||||
assertTrue(Utils.isIpAddress("127.0.0.1:80"))
|
||||
assertTrue(Utils.isIpAddress("0.0.0.0/0"))
|
||||
assertTrue(Utils.isIpAddress("::1"))
|
||||
assertTrue(Utils.isIpAddress("[::1]:80"))
|
||||
assertTrue(Utils.isIpAddress("2605:2700:0:3::4713:93e3"))
|
||||
assertTrue(Utils.isIpAddress("[2605:2700:0:3::4713:93e3]:80"))
|
||||
assertTrue(Utils.isIpAddress("::ffff:192.168.173.22"))
|
||||
assertTrue(Utils.isIpAddress("[::ffff:192.168.173.22]:80"))
|
||||
assertTrue(Utils.isIpAddress("1::"))
|
||||
assertTrue(Utils.isIpAddress("::"))
|
||||
assertTrue(Utils.isIpAddress("::/0"))
|
||||
assertTrue(Utils.isIpAddress("10.24.56.0/24"))
|
||||
assertTrue(Utils.isIpAddress("2001:4321::1"))
|
||||
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::6666"))
|
||||
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::/64"))
|
||||
}
|
||||
|
||||
// @Test
|
||||
// fun test_fmtHysteria2Parse() {
|
||||
// val url2 = "hysteria2://password2@127.0.0.1:443?obfs=salamander&obfs-password=obfs2&insecure=0#Hy22"
|
||||
// var result2 = Hysteria2Fmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// assertTrue(result2?.obfsPassword == "obfs2")
|
||||
// assertTrue(result2?.security == "tls")
|
||||
//
|
||||
// var url22 = Hysteria2Fmt.toUri(result2!!)
|
||||
// assertTrue(url22.contains("obfs2"))
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtSsParse() {
|
||||
// val url2 = "ss://aa:bb@127.0.0.1:10000#sss"
|
||||
// var result2 = ShadowsocksFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
//
|
||||
// var result = ShadowsocksFmt.parse("ss://YWVzLTI1Ni1nY206cGFzc3dvcmQy@127.0.0.1:10000#sss")
|
||||
// assertTrue(result != null)
|
||||
// assertTrue(result?.server == "127.0.0.1")
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtSocksParse() {
|
||||
// val url2 = "socks://Og%3D%3D@127.0.0.1:1000#socks2"
|
||||
// var result2 = SocksFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// var url22 = SocksFmt.toUri(result2!!)
|
||||
// assertTrue(url2.contains(url22))
|
||||
//
|
||||
// var result = SocksFmt.parse("socks://dXNlcjpwYXNz@127.0.0.1:1000#socks2")
|
||||
// assertTrue(result != null)
|
||||
// assertTrue(result?.server == "127.0.0.1")
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtTrojanParse() {
|
||||
// val url2 = "trojan://password2@127.0.0.1:443?flow=xtls-rprx-vision&security=tls&type=tcp&headerType=none#Trojan"
|
||||
// var result2 = TrojanFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// assertTrue(result2?.flow == "xtls-rprx-vision")
|
||||
//
|
||||
// val url = "trojan://password2@127.0.0.1:443#Trojan"
|
||||
// var result = TrojanFmt.parse(url)
|
||||
// assertTrue(result != null)
|
||||
// assertTrue(result?.server == "127.0.0.1")
|
||||
// assertTrue(result?.security == "tls")
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtVlessParse() {
|
||||
// val url2 =
|
||||
// "vless://cae1dc39-0547-4b1d-9e7a-01132c7ae3a7@127.0.0.1:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=sni2&fp=chrome&pbk=publickkey&sid=123456&spx=%2F&type=ws&host=host2&path=path2#VLESS"
|
||||
// var result2 = VlessFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// assertTrue(result2?.flow == "xtls-rprx-vision")
|
||||
//
|
||||
//
|
||||
// var url22 = VlessFmt.toUri(result2!!)
|
||||
// assertTrue(url22.contains("xtls-rprx-vision"))
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtVmessParse() {
|
||||
// val url2 =
|
||||
// "vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIlZtZXNzIiwNCiAgImFkZCI6ICIxMjcuMC4wLjEiLA0KICAicG9ydCI6ICIxMDAwMCIsDQogICJpZCI6ICJlYmI5MWM5OS1lZjA3LTRmZjUtOThhYS01OTAyYWI0ZDAyODYiLA0KICAiYWlkIjogIjEyMyIsDQogICJzY3kiOiAiYWVzLTEyOC1nY20iLA0KICAibmV0IjogInRjcCIsDQogICJ0eXBlIjogIm5vbmUiLA0KICAiaG9zdCI6ICJob3N0MiIsDQogICJwYXRoIjogInBhdGgyIiwNCiAgInRscyI6ICIiLA0KICAic25pIjogIiIsDQogICJhbHBuIjogIiINCn0="
|
||||
// var result2 = VmessFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// assertTrue(result2?.method == "aes-128-gcm")
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Test
|
||||
// fun test_fmtWireguardParse() {
|
||||
// val url2 = "wireguard://privatekey2@127.0.0.1:2000?publickey=publickey2&reserved=2%2C2%2C3&address=127.0.0.127&mtu=1250#WGG"
|
||||
// var result2 = WireguardFmt.parse(url2)
|
||||
// assertTrue(result2 != null)
|
||||
// assertTrue(result2?.server == "127.0.0.1")
|
||||
// assertTrue(result2?.publicKey == "publickey2")
|
||||
// assertTrue(result2?.localAddress == "127.0.0.127")
|
||||
//
|
||||
//
|
||||
// var url22 = WireguardFmt.toUri(result2!!)
|
||||
// assertTrue(url22.contains("publickey2"))
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.android.library) apply false
|
||||
alias(libs.plugins.android.kotlin) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
}
|
||||
@@ -1,6 +1,24 @@
|
||||
kotlin.incremental=true
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. For more details, visit
|
||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
kotlin.incremental=true
|
||||
@@ -1,71 +1,63 @@
|
||||
[versions]
|
||||
activityKtx = "1.9.3"
|
||||
appcompat = "1.7.0"
|
||||
cardview = "1.0.0"
|
||||
constraintlayout = "2.2.0"
|
||||
core = "3.5.3"
|
||||
editorkit = "2.9.0"
|
||||
flexbox = "3.0.0"
|
||||
fragmentKtx = "1.8.5"
|
||||
gson = "2.11.0"
|
||||
agp = "8.7.2"
|
||||
kotlin = "2.0.21"
|
||||
coreKtx = "1.15.0"
|
||||
junit = "4.13.2"
|
||||
kotlinReflect = "2.0.21"
|
||||
kotlinxCoroutinesCore = "1.9.0"
|
||||
legacySupportV4 = "1.0.0"
|
||||
lifecycleViewmodelKtx = "2.8.7"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
activity = "1.9.3"
|
||||
constraintlayout = "2.2.0"
|
||||
mmkvStatic = "1.3.9"
|
||||
multidex = "2.0.1"
|
||||
preferenceKtx = "1.2.1"
|
||||
quickieBundled = "1.10.0"
|
||||
recyclerview = "1.3.2"
|
||||
rxandroid = "3.0.2"
|
||||
gson = "2.11.0"
|
||||
rxjava = "3.1.9"
|
||||
rxandroid = "3.0.2"
|
||||
rxpermissions = "0.12"
|
||||
toastcompat = "1.1.0"
|
||||
viewpager2 = "1.1.0"
|
||||
workRuntimeKtx = "2.9.1"
|
||||
androidGradlePlugin = "8.7.2"
|
||||
androidKotlinPlugin = "2.0.21"
|
||||
editorkit = "2.9.0"
|
||||
quickieBundled = "1.10.0"
|
||||
core = "3.5.3"
|
||||
workRuntimeKtx = "2.10.0"
|
||||
lifecycleViewmodelKtx = "2.8.7"
|
||||
multidex = "2.0.1"
|
||||
mockitoMockitoInline = "4.0.0"
|
||||
|
||||
flexbox = "3.0.0"
|
||||
preferenceKtx = "1.2.1"
|
||||
recyclerview = "1.3.2"
|
||||
[libraries]
|
||||
activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" }
|
||||
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
|
||||
cardview = { module = "androidx.cardview:cardview", version.ref = "cardview" }
|
||||
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
|
||||
core = { module = "com.google.zxing:core", version.ref = "core" }
|
||||
editorkit = { module = "com.blacksquircle.ui:editorkit", version.ref = "editorkit" }
|
||||
flexbox = { module = "com.google.android.flexbox:flexbox", version.ref = "flexbox" }
|
||||
fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
junit = { module = "junit:junit", version.ref = "junit" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlinReflect" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesCore" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
|
||||
language-base = { module = "com.blacksquircle.ui:language-base", version.ref = "editorkit" }
|
||||
language-json = { module = "com.blacksquircle.ui:language-json", version.ref = "editorkit" }
|
||||
legacy-support-v4 = { module = "androidx.legacy:legacy-support-v4", version.ref = "legacySupportV4" }
|
||||
lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
material = { module = "com.google.android.material:material", version.ref = "material" }
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||
mmkv-static = { module = "com.tencent:mmkv-static", version.ref = "mmkvStatic" }
|
||||
multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" }
|
||||
quickie-bundled = { module = "io.github.g00fy2.quickie:quickie-bundled", version.ref = "quickieBundled" }
|
||||
recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
|
||||
preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preferenceKtx" }
|
||||
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
|
||||
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
|
||||
rxpermissions = { module = "com.github.tbruyelle:rxpermissions", version.ref = "rxpermissions" }
|
||||
toastcompat = { module = "me.drakeet.support:toastcompat", version.ref = "toastcompat" }
|
||||
viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" }
|
||||
work-multiprocess = { module = "androidx.work:work-multiprocess", version.ref = "workRuntimeKtx" }
|
||||
editorkit = { module = "com.blacksquircle.ui:editorkit", version.ref = "editorkit" }
|
||||
language-base = { module = "com.blacksquircle.ui:language-base", version.ref = "editorkit" }
|
||||
language-json = { module = "com.blacksquircle.ui:language-json", version.ref = "editorkit" }
|
||||
quickie-bundled = { module = "io.github.g00fy2.quickie:quickie-bundled", version.ref = "quickieBundled" }
|
||||
core = { module = "com.google.zxing:core", version.ref = "core" }
|
||||
work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" }
|
||||
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoMockitoInline" }
|
||||
work-multiprocess = { module = "androidx.work:work-multiprocess", version.ref = "workRuntimeKtx" }
|
||||
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" }
|
||||
org-mockito-mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockitoMockitoInline" }
|
||||
|
||||
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoMockitoInline" }
|
||||
flexbox = { module = "com.google.android.flexbox:flexbox", version.ref = "flexbox" }
|
||||
recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
|
||||
preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preferenceKtx" }
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
|
||||
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
|
||||
android-kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "androidKotlinPlugin" }
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||
|
||||
BIN
Binary file not shown.
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user