commit b1d7efc0345d91af007938c1d634bb0b47c96fda Author: MiDupl1711 Date: Sat Mar 7 22:32:39 2026 +0300 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..68b07f6 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +MySERVER \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..5a339e5 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..29e60fc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..a4703f8 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,78 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + packaging { + jniLibs { + useLegacyPackaging = false + } + } + // Для компиляции с поддержкой 16 KB + defaultConfig { + externalNativeBuild { + cmake { + // ИСПРАВЛЕНИЕ: здесь нужно использовать аргументы и скобки/равенство + cppFlags("-Wl,-z,max-page-size=16384") + } + } + } + + + namespace = "com.example.myserver" + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "com.example.myserver" + minSdk = 29 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + cppFlags += "" + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + externalNativeBuild { + cmake { + path = file("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } +} + +dependencies { + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.activity) + implementation(libs.constraintlayout) + implementation(libs.recyclerview) + implementation(libs.cardview) + implementation(libs.viewpager2) + implementation(libs.legacy.support.v4) + implementation(libs.mediarouter) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/myserver/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/myserver/ExampleInstrumentedTest.java new file mode 100644 index 0000000..2050ba0 --- /dev/null +++ b/app/src/androidTest/java/com/example/myserver/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.myserver; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.myserver", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fcee2f8 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..e07cac3 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,38 @@ + +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html. +# For more examples on how to use CMake, see https://github.com/android/ndk-samples. + +# Sets the minimum CMake version required for this project. +cmake_minimum_required(VERSION 3.22.1) + +# Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, +# Since this is the top level CMakeLists.txt, the project name is also accessible +# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level +# build script scope). +project("myserver") + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. +# +# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define +# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} +# is preferred for the same purpose. +# +# In order to load a library into your app from Java/Kotlin, you must call +# System.loadLibrary() and pass the name of the library defined here; +# for GameActivity/NativeActivity derived applications, the same library name must be +# used in the AndroidManifest.xml file. +add_library(${CMAKE_PROJECT_NAME} SHARED + # List C/C++ source files with relative paths to this CMakeLists.txt. + myserver.cpp) + +# Specifies libraries CMake should link to your target library. You +# can link libraries from various origins, such as libraries defined in this +# build script, prebuilt third-party libraries, or Android system libraries. +target_link_libraries(${CMAKE_PROJECT_NAME} + # List libraries link to the target library + android + log) diff --git a/app/src/main/cpp/myserver.cpp b/app/src/main/cpp/myserver.cpp new file mode 100644 index 0000000..c09b4bb --- /dev/null +++ b/app/src/main/cpp/myserver.cpp @@ -0,0 +1,17 @@ +// Write C++ code here. +// +// Do not forget to dynamically load the C++ library into your application. +// +// For instance, +// +// In MainActivity.java: +// static { +// System.loadLibrary("myserver"); +// } +// +// Or, in MainActivity.kt: +// companion object { +// init { +// System.loadLibrary("myserver") +// } +// } \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..515665d Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/example/myserver/AuthManager.java b/app/src/main/java/com/example/myserver/AuthManager.java new file mode 100644 index 0000000..b55bc96 --- /dev/null +++ b/app/src/main/java/com/example/myserver/AuthManager.java @@ -0,0 +1,61 @@ +package com.example.myserver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import android.widget.Toast; + +import androidx.annotation.NonNull; + + +public class AuthManager { + private final Context context; + + public AuthManager(Context context) { + this.context = context; + } + + public void authUser(String realname, String password, String email, boolean isRegistration) { + UserRequest request = new UserRequest(realname, password, email); + MyApiService api = RetrofitClient.getApiService(); + + // Выбираем метод в зависимости от флага + Call call = isRegistration ? api.register(request) : api.login(request); + + call.enqueue(new Callback<>() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null) { + saveUserToLocal(response.body()); + + // ДОБАВЬ ЭТОТ КОД ДЛЯ ПЕРЕХОДА: + Intent intent = new Intent(context, LoadScreen.class); // Укажи свою главную активность + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + + Toast.makeText(context, "Успешный вход!", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "Ошибка сервера: " + response.code(), Toast.LENGTH_SHORT).show(); + } + } + + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + // ЕСЛИ СЕРВЕР ВООБЩЕ НЕ ДОСТУПЕН (не тот IP или выключен) + Toast.makeText(context, "Сеть недоступна: " + t.getMessage(), Toast.LENGTH_LONG).show(); + } + + }); + } + + private void saveUserToLocal(UserResponse user) { + SharedPreferences prefs = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE); + prefs.edit() + .putBoolean("isLoggedIn", true) + .putString("realname", user.getRealname()) + .apply(); + } +} diff --git a/app/src/main/java/com/example/myserver/InformationActivity.java b/app/src/main/java/com/example/myserver/InformationActivity.java new file mode 100644 index 0000000..c71e623 --- /dev/null +++ b/app/src/main/java/com/example/myserver/InformationActivity.java @@ -0,0 +1,26 @@ +package com.example.myserver; + +import android.os.Bundle; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +public class InformationActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_information); + 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; + }); + String name = getSharedPreferences("AppPrefs", MODE_PRIVATE).getString("username", "Гость"); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/LoadScreen.java b/app/src/main/java/com/example/myserver/LoadScreen.java new file mode 100644 index 0000000..cd83842 --- /dev/null +++ b/app/src/main/java/com/example/myserver/LoadScreen.java @@ -0,0 +1,75 @@ +package com.example.myserver; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +public class LoadScreen extends AppCompatActivity { + private TextView textViewWelcome; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_load_screen); + textViewWelcome = findViewById(R.id.textWelcome); + + // Получаем переданное имя + SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE); + String realName = prefs.getString("realname", null); + + if (realName != null) { + textViewWelcome.setText("Добро пожаловать, " + realName + "!"); + } else { + textViewWelcome.setText("Добро пожаловать!"); + } + + + // Запускаем анимацию для приветствия + animateWelcomeMessage(); + } + private void animateWelcomeMessage() { + if (textViewWelcome != null) { + // 1. Появление текста (1 секунда) + AlphaAnimation fadeIn = new AlphaAnimation(0.0f, 1.0f); + fadeIn.setDuration(1000); + textViewWelcome.startAnimation(fadeIn); + + // 2. Ждем, пока пользователь почитает (например, 2 секунды), и запускаем исчезновение + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + AlphaAnimation fadeOut = new AlphaAnimation(1.0f, 0.0f); + fadeOut.setDuration(1000); // время затухания + + fadeOut.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} + + @Override + public void onAnimationEnd(Animation animation) { + textViewWelcome.setVisibility(View.GONE); + + // ПЕРЕХОД ДЕЛАЕМ ТУТ (когда всё исчезло) + Intent intent = new Intent(LoadScreen.this, MainActivity2.class); + startActivity(intent); + finish(); + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + + textViewWelcome.startAnimation(fadeOut); + } + }, 2000); + } + } + +} diff --git a/app/src/main/java/com/example/myserver/MainActivity.java b/app/src/main/java/com/example/myserver/MainActivity.java new file mode 100644 index 0000000..97a13a3 --- /dev/null +++ b/app/src/main/java/com/example/myserver/MainActivity.java @@ -0,0 +1,123 @@ +package com.example.myserver; + +import android.os.Bundle; +import android.content.SharedPreferences; + +import android.text.TextUtils; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +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 android.content.Intent; +import android.view.View; +import android.widget.Button; + + +public class MainActivity extends AppCompatActivity { + private AuthManager authManager; + private EditText editTextName; + private EditText editTextPass; + private Button buttonSubmit; + private TextView textViewError; + + private Button buttonReg; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // 1. Сначала проверяем сессию. Если вошел — уходим отсюда сразу. + SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE); + if (prefs.getBoolean("isLoggedIn", false)) { + startActivity(new Intent(this, LoadScreen.class)); + finish(); + return; // Обязательно выходим из метода, чтобы не грузить Layout ниже + } + + // 2. Только если НЕ залогинен, инициализируем интерфейс + EdgeToEdge.enable(this); + setContentView(R.layout.activity_main); + + // 3. Инициализируем остальное + authManager = new AuthManager(this); + editTextName = findViewById(R.id.editTextText); + editTextPass = findViewById(R.id.editTextTextPassword2); + textViewError = findViewById(R.id.txtWarn); + buttonSubmit = findViewById(R.id.btnLogin); + buttonReg = findViewById(R.id.btnRegister); + buttonSubmit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkFieldAndProceed(); + } + }); + + buttonReg.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity.this, RegActivity.class); + startActivity(intent); + finish(); + }); + } + + private void checkFieldAndProceed() { + String name = editTextName.getText().toString().trim(); + String password = editTextPass.getText().toString().trim(); + + if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)) { + showErrorMessage("Поля не могут быть пустыми!"); + } else { + hideErrorMessage(); + + // ВМЕСТО openSecondActivity(name) делаем запрос к серверу: + // false означает, что это попытка входа (Login) + authManager.authUser(name, password, "", false); + } + } + + + private void showErrorMessage(String message) { + if (textViewError != null) { + textViewError.setText(message); + textViewError.setAlpha(1f); + textViewError.setVisibility(View.VISIBLE); + + // Скрываем через 1 секунду + new android.os.Handler().postDelayed(new Runnable() { + @Override + public void run() { + hideErrorMessage(); + } + }, 1000); // 1000 миллисекунд = 1 секунда + } + } + + private void hideErrorMessage() { + if (textViewError != null && textViewError.getVisibility() == View.VISIBLE) { + textViewError.animate() + .alpha(0f) + .setDuration(500) // Анимация скрытия 0.5 секунды + .withEndAction(new Runnable() { + @Override + public void run() { + textViewError.setVisibility(View.GONE); + textViewError.setAlpha(1f); + } + }) + .start(); + } + } + + private void openSecondActivity(String realName) { + Intent intent = new Intent(MainActivity.this, LoadScreen.class); + intent.putExtra("USER_NAME", realName); + startActivity(intent); + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/MainActivity2.java b/app/src/main/java/com/example/myserver/MainActivity2.java new file mode 100644 index 0000000..0042055 --- /dev/null +++ b/app/src/main/java/com/example/myserver/MainActivity2.java @@ -0,0 +1,117 @@ +package com.example.myserver; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import androidx.activity.EdgeToEdge; +import android.widget.PopupMenu; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import java.util.List; +import android.widget.Toast; +import android.util.Log; +import android.widget.ImageView; +import android.text.TextUtils; +import android.widget.EditText; +import android.widget.TextView; +import android.os.Handler; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.content.SharedPreferences; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.LinearLayoutManager; + + + + + + +public class MainActivity2 extends AppCompatActivity { + private RecyclerView rvPlayers; + private PlayerAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_main2); + 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; + }); + rvPlayers = findViewById(R.id.rvPlayers); + rvPlayers.setLayoutManager(new LinearLayoutManager(this)); + + loadPlayers(); + + ImageView image = findViewById(R.id.buttonMenu); + image.setOnClickListener(v -> { + PopupMenu popup = new PopupMenu(MainActivity2.this, v); + popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu()); + + popup.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.option_2) { + //Intent intent = new Intent(MainActivity2.this, MainActivity3.class); + //startActivity(intent); + return true; + } + if (item.getItemId() == R.id.option1) { + getSharedPreferences("AppPrefs", MODE_PRIVATE).edit().clear().apply(); + startActivity(new Intent(MainActivity2.this, MainActivity.class)); + finish(); + return true; + } + + return false; + }); + popup.show(); + }); + ImageView map = findViewById(R.id.imageButtonMap); + map.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity2.this, MapActivity.class); + startActivity(intent); + }); + + ImageView player = findViewById(R.id.imageButtonPlayer); + player.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity2.this, MainActivity3.class); + startActivity(intent); + }); + ImageView inf = findViewById(R.id.imageButton); + inf.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity2.this, InformationActivity.class); + startActivity(intent); + }); + } + private void loadPlayers() { + RetrofitClient.getApiService().getPlayers().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful() && response.body() != null) { + adapter = new PlayerAdapter(response.body(), player -> { + // ПЕРЕХОД В ПРОФИЛЬ + Intent intent = new Intent(MainActivity2.this, ProfileActivity.class); + intent.putExtra("PLAYER_NAME", player.getRealname()); + startActivity(intent); + }); + rvPlayers.setAdapter(adapter); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + Toast.makeText(MainActivity2.this, "Ошибка списка", Toast.LENGTH_SHORT).show(); + } + }); + } + +} diff --git a/app/src/main/java/com/example/myserver/MainActivity3.java b/app/src/main/java/com/example/myserver/MainActivity3.java new file mode 100644 index 0000000..b811da2 --- /dev/null +++ b/app/src/main/java/com/example/myserver/MainActivity3.java @@ -0,0 +1,33 @@ +package com.example.myserver; + +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ImageView; +import android.content.Intent; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +public class MainActivity3 extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_main3); + 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; + }); + ImageView back = findViewById(R.id.imageButton4); + back.setOnClickListener(v -> { + finish(); + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/MapActivity.java b/app/src/main/java/com/example/myserver/MapActivity.java new file mode 100644 index 0000000..de92cc0 --- /dev/null +++ b/app/src/main/java/com/example/myserver/MapActivity.java @@ -0,0 +1,37 @@ +package com.example.myserver; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.ImageView; + +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 android.webkit.WebView; +import android.webkit.WebViewClient; + +public class MapActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_map); + 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; + }); + WebView webView = findViewById(R.id.webView); + webView.getSettings().setJavaScriptEnabled(true); + webView.setWebViewClient(new WebViewClient()); + webView.loadUrl("http://quantumblocks.hopto.org:8123"); + ImageView back = findViewById(R.id.imageButton2); + back.setOnClickListener(v -> { + finish(); + }); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/MyApiService.java b/app/src/main/java/com/example/myserver/MyApiService.java new file mode 100644 index 0000000..b0bb478 --- /dev/null +++ b/app/src/main/java/com/example/myserver/MyApiService.java @@ -0,0 +1,17 @@ +package com.example.myserver; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.POST; +import retrofit2.http.GET; +import java.util.List; +public interface MyApiService { + @POST("api/auth/login") + Call login(@Body UserRequest request); + + @POST("api/auth/register") + Call register(@Body UserRequest request); + + @GET("api/auth/players") // Тот же путь, что на сервере + Call> getPlayers(); + +} diff --git a/app/src/main/java/com/example/myserver/PlayerAdapter.java b/app/src/main/java/com/example/myserver/PlayerAdapter.java new file mode 100644 index 0000000..a3a5dfa --- /dev/null +++ b/app/src/main/java/com/example/myserver/PlayerAdapter.java @@ -0,0 +1,53 @@ +package com.example.myserver; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import java.util.List; + + +public class PlayerAdapter extends RecyclerView.Adapter { + + private List playerList; + private OnPlayerClickListener listener; + + // Интерфейс для клика + public interface OnPlayerClickListener { + void onPlayerClick(UserResponse player); + } + + public PlayerAdapter(List playerList, OnPlayerClickListener listener) { + this.playerList = playerList; + this.listener = listener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_player, parent, false); + return new ViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + UserResponse player = playerList.get(position); + holder.tvName.setText(player.getRealname()); + + // Клик по прямоугольнику + holder.itemView.setOnClickListener(v -> listener.onPlayerClick(player)); + } + + @Override + public int getItemCount() { return playerList.size(); } + + public static class ViewHolder extends RecyclerView.ViewHolder { + TextView tvName; + public ViewHolder(View itemView) { + super(itemView); + tvName = itemView.findViewById(R.id.tvName); + } + } +} diff --git a/app/src/main/java/com/example/myserver/ProfileActivity.java b/app/src/main/java/com/example/myserver/ProfileActivity.java new file mode 100644 index 0000000..9aff5a0 --- /dev/null +++ b/app/src/main/java/com/example/myserver/ProfileActivity.java @@ -0,0 +1,30 @@ +package com.example.myserver; + +import android.os.Bundle; +import android.widget.ImageView; + +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 android.content.Intent; + +public class ProfileActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_profile); + 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; + }); + ImageView back = findViewById(R.id.imageButton2); + back.setOnClickListener(v -> { + finish(); + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/RegActivity.java b/app/src/main/java/com/example/myserver/RegActivity.java new file mode 100644 index 0000000..3b5951c --- /dev/null +++ b/app/src/main/java/com/example/myserver/RegActivity.java @@ -0,0 +1,112 @@ +package com.example.myserver; + +import android.os.Bundle; +import android.text.TextUtils; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +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 android.content.Intent; +import android.view.View; +import android.widget.Button; + +public class RegActivity extends AppCompatActivity { + private AuthManager authManager; + private EditText editTextName; + private EditText editTextPass; + private EditText editTextEmail; + private Button buttonSubmit; + private TextView textViewError; + private Button buttonReg; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_reg_activity); + 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; + }); + editTextName = findViewById(R.id.editTextText); + editTextEmail = findViewById(R.id.editTextEmail); + editTextPass = findViewById(R.id.editTextTextPassword2); + textViewError = findViewById(R.id.txtWarn); + buttonSubmit = findViewById(R.id.btnRegister); + buttonSubmit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkFieldAndProceed(); + } + }); + authManager = new AuthManager(this); // 2. Инициализируем + buttonReg = findViewById(R.id.btnLogin); + buttonReg.setOnClickListener(v -> { + Intent intent = new Intent(RegActivity.this, MainActivity.class); + startActivity(intent); + finish(); + }); + } + + private void checkFieldAndProceed() { + String name = editTextName.getText().toString().trim(); + String password = editTextPass.getText().toString().trim(); + String email = editTextEmail.getText().toString().trim(); + + if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password) || TextUtils.isEmpty(email)) { + showErrorMessage("Поля не могут быть пустыми!"); + } else { + hideErrorMessage(); + + // 3. ВМЕСТО openSecondActivity и finish() вызываем сервер: + // true означает, что это РЕГИСТРАЦИЯ + authManager.authUser(name, password, email, true); + + // ПРИМЕЧАНИЕ: finish() делать ТУТ НЕ НУЖНО. + // AuthManager сам сделает переход и закроет экран при успешном ответе. + } + } + + private void showErrorMessage(String message) { + if (textViewError != null) { + textViewError.setText(message); + textViewError.setAlpha(1f); + textViewError.setVisibility(View.VISIBLE); + + // Скрываем через 1 секунду + new android.os.Handler().postDelayed(new Runnable() { + @Override + public void run() { + hideErrorMessage(); + } + }, 1000); // 1000 миллисекунд = 1 секунда + } + } + + private void hideErrorMessage() { + if (textViewError != null && textViewError.getVisibility() == View.VISIBLE) { + textViewError.animate() + .alpha(0f) + .setDuration(500) // Анимация скрытия 0.5 секунды + .withEndAction(new Runnable() { + @Override + public void run() { + textViewError.setVisibility(View.GONE); + textViewError.setAlpha(1f); + } + }) + .start(); + } + } + + private void openSecondActivity(String realName) { + Intent intent = new Intent(RegActivity.this, LoadScreen.class); + intent.putExtra("USER_NAME", realName); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myserver/RetrofitClient.java b/app/src/main/java/com/example/myserver/RetrofitClient.java new file mode 100644 index 0000000..eaa6a5f --- /dev/null +++ b/app/src/main/java/com/example/myserver/RetrofitClient.java @@ -0,0 +1,18 @@ +package com.example.myserver; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class RetrofitClient { + private static Retrofit retrofit = null; + private static final String BASE_URL = "http://quantumblocks.hopto.org:45678/"; + + public static MyApiService getApiService() { + if (retrofit == null) { + retrofit = new Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + } + return retrofit.create(MyApiService.class); + } +} diff --git a/app/src/main/java/com/example/myserver/UserRequest.java b/app/src/main/java/com/example/myserver/UserRequest.java new file mode 100644 index 0000000..a770688 --- /dev/null +++ b/app/src/main/java/com/example/myserver/UserRequest.java @@ -0,0 +1,20 @@ +package com.example.myserver; + +public class UserRequest { + private String realname; + private String password; + private String email; + + public UserRequest(String realname, String password, String email) { + this.realname = realname; + this.password = password; + this.email = email; + } + + public String getRealname() { return realname; } + public void setRealname(String realname) { this.realname = realname; } + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } + public String getEmail() { return email; } + public void setEmail(String email) { this.email = email; } +} diff --git a/app/src/main/java/com/example/myserver/UserResponse.java b/app/src/main/java/com/example/myserver/UserResponse.java new file mode 100644 index 0000000..c2571d5 --- /dev/null +++ b/app/src/main/java/com/example/myserver/UserResponse.java @@ -0,0 +1,13 @@ +package com.example.myserver; + + +public class UserResponse { + private Long id; + private String realname; + + public UserResponse() {} + + public Long getId() { return id; } + public String getRealname() { return realname; } + public void setRealname(String realname) { this.realname = realname; } +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..ca3826a --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/img1.jpg b/app/src/main/res/drawable/img1.jpg new file mode 100644 index 0000000..8c7a946 Binary files /dev/null and b/app/src/main/res/drawable/img1.jpg differ diff --git a/app/src/main/res/drawable/img10.png b/app/src/main/res/drawable/img10.png new file mode 100644 index 0000000..410001e Binary files /dev/null and b/app/src/main/res/drawable/img10.png differ diff --git a/app/src/main/res/drawable/img11.png b/app/src/main/res/drawable/img11.png new file mode 100644 index 0000000..6d9d00b Binary files /dev/null and b/app/src/main/res/drawable/img11.png differ diff --git a/app/src/main/res/drawable/img12.png b/app/src/main/res/drawable/img12.png new file mode 100644 index 0000000..8bdd7a0 Binary files /dev/null and b/app/src/main/res/drawable/img12.png differ diff --git a/app/src/main/res/drawable/img13.png b/app/src/main/res/drawable/img13.png new file mode 100644 index 0000000..f915e2a Binary files /dev/null and b/app/src/main/res/drawable/img13.png differ diff --git a/app/src/main/res/drawable/img14.png b/app/src/main/res/drawable/img14.png new file mode 100644 index 0000000..9e517a0 Binary files /dev/null and b/app/src/main/res/drawable/img14.png differ diff --git a/app/src/main/res/drawable/img15.png b/app/src/main/res/drawable/img15.png new file mode 100644 index 0000000..20fc40c Binary files /dev/null and b/app/src/main/res/drawable/img15.png differ diff --git a/app/src/main/res/drawable/img16.png b/app/src/main/res/drawable/img16.png new file mode 100644 index 0000000..7fe0ba6 Binary files /dev/null and b/app/src/main/res/drawable/img16.png differ diff --git a/app/src/main/res/drawable/img17.png b/app/src/main/res/drawable/img17.png new file mode 100644 index 0000000..ed3fd4b Binary files /dev/null and b/app/src/main/res/drawable/img17.png differ diff --git a/app/src/main/res/drawable/img18.png b/app/src/main/res/drawable/img18.png new file mode 100644 index 0000000..b90f9ed Binary files /dev/null and b/app/src/main/res/drawable/img18.png differ diff --git a/app/src/main/res/drawable/img19.png b/app/src/main/res/drawable/img19.png new file mode 100644 index 0000000..0cd1923 Binary files /dev/null and b/app/src/main/res/drawable/img19.png differ diff --git a/app/src/main/res/drawable/img20.png b/app/src/main/res/drawable/img20.png new file mode 100644 index 0000000..6aeb022 Binary files /dev/null and b/app/src/main/res/drawable/img20.png differ diff --git a/app/src/main/res/drawable/img21.png b/app/src/main/res/drawable/img21.png new file mode 100644 index 0000000..52bb60b Binary files /dev/null and b/app/src/main/res/drawable/img21.png differ diff --git a/app/src/main/res/drawable/img22.png b/app/src/main/res/drawable/img22.png new file mode 100644 index 0000000..8adb499 Binary files /dev/null and b/app/src/main/res/drawable/img22.png differ diff --git a/app/src/main/res/drawable/img3.jpg b/app/src/main/res/drawable/img3.jpg new file mode 100644 index 0000000..ad06be6 Binary files /dev/null and b/app/src/main/res/drawable/img3.jpg differ diff --git a/app/src/main/res/drawable/img4.png b/app/src/main/res/drawable/img4.png new file mode 100644 index 0000000..d03ae29 Binary files /dev/null and b/app/src/main/res/drawable/img4.png differ diff --git a/app/src/main/res/drawable/img5.png b/app/src/main/res/drawable/img5.png new file mode 100644 index 0000000..28765e3 Binary files /dev/null and b/app/src/main/res/drawable/img5.png differ diff --git a/app/src/main/res/drawable/img6.png b/app/src/main/res/drawable/img6.png new file mode 100644 index 0000000..39b62c0 Binary files /dev/null and b/app/src/main/res/drawable/img6.png differ diff --git a/app/src/main/res/drawable/img7.png b/app/src/main/res/drawable/img7.png new file mode 100644 index 0000000..8763dbc Binary files /dev/null and b/app/src/main/res/drawable/img7.png differ diff --git a/app/src/main/res/drawable/img8.png b/app/src/main/res/drawable/img8.png new file mode 100644 index 0000000..07e9616 Binary files /dev/null and b/app/src/main/res/drawable/img8.png differ diff --git a/app/src/main/res/drawable/img9.png b/app/src/main/res/drawable/img9.png new file mode 100644 index 0000000..f53ff2f Binary files /dev/null and b/app/src/main/res/drawable/img9.png differ diff --git a/app/src/main/res/drawable/player_card_bg.xml b/app/src/main/res/drawable/player_card_bg.xml new file mode 100644 index 0000000..593ed8c --- /dev/null +++ b/app/src/main/res/drawable/player_card_bg.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_information.xml b/app/src/main/res/layout/activity_information.xml new file mode 100644 index 0000000..2892200 --- /dev/null +++ b/app/src/main/res/layout/activity_information.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_load_screen.xml b/app/src/main/res/layout/activity_load_screen.xml new file mode 100644 index 0000000..420c9ff --- /dev/null +++ b/app/src/main/res/layout/activity_load_screen.xml @@ -0,0 +1,45 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..22ae615 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + +